diff options
Diffstat (limited to 'src/boost/libs/program_options/example')
14 files changed, 1717 insertions, 0 deletions
diff --git a/src/boost/libs/program_options/example/Jamfile.v2 b/src/boost/libs/program_options/example/Jamfile.v2 new file mode 100644 index 000000000..9f0b1d8fa --- /dev/null +++ b/src/boost/libs/program_options/example/Jamfile.v2 @@ -0,0 +1,21 @@ + +project + : requirements <library>../build//boost_program_options + <hardcode-dll-paths>true + <link>static + ; + +exe first : first.cpp ; +exe options_description : options_description.cpp ; +exe multiple_sources : multiple_sources.cpp ; +exe custom_syntax : custom_syntax.cpp ; + +exe real : real.cpp ; +exe regex : regex.cpp /boost/regex//boost_regex ; + +# The following examples use C++ features beyond C++03. +# It would be possible to make compilation of each conditional on specific config check, +# for now just disable the compilation. +#exe config_file_types : config_file_types.cpp ; +#exe env_options : env_options.cpp ; +#exe options_heirarchy : options_heirarchy.cpp ; diff --git a/src/boost/libs/program_options/example/config_file_types.cpp b/src/boost/libs/program_options/example/config_file_types.cpp new file mode 100644 index 000000000..e466e94a1 --- /dev/null +++ b/src/boost/libs/program_options/example/config_file_types.cpp @@ -0,0 +1,242 @@ +// Copyright Thomas Kent 2016 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// This example shows a config file (in ini format) being parsed by the +// program_options library. It includes a numebr of different value types. + +#include <boost/program_options.hpp> +namespace po = boost::program_options; + +#include <assert.h> +#include <iostream> +#include <sstream> +using namespace std; + +const double FLOAT_SEPERATION = 0.00000000001; +bool check_float(double test, double expected) +{ + double seperation = expected * (1 + FLOAT_SEPERATION) / expected; + if ((test < expected + seperation) && (test > expected - seperation)) + { + return true; + } + return false; +} + +stringstream make_file() +{ + stringstream ss; + ss << "# This file checks parsing of various types of config values\n"; + //FAILS: ss << "; a windows style comment\n"; + + ss << "global_string = global value\n"; + ss << "unregistered_entry = unregistered value\n"; + + ss << "\n[strings]\n"; + ss << "word = word\n"; + ss << "phrase = this is a phrase\n"; + ss << "quoted = \"quotes are in result\"\n"; + + ss << "\n[ints]\n"; + ss << "positive = 41\n"; + ss << "negative = -42\n"; + //FAILS: Lexical cast doesn't support hex, oct, or bin + //ss << "hex = 0x43\n"; + //ss << "oct = 044\n"; + //ss << "bin = 0b101010\n"; + + ss << "\n[floats]\n"; + ss << "positive = 51.1\n"; + ss << "negative = -52.1\n"; + ss << "double = 53.1234567890\n"; + ss << "int = 54\n"; + ss << "int_dot = 55.\n"; + ss << "dot = .56\n"; + ss << "exp_lower = 57.1e5\n"; + ss << "exp_upper = 58.1E5\n"; + ss << "exp_decimal = .591e5\n"; + ss << "exp_negative = 60.1e-5\n"; + ss << "exp_negative_val = -61.1e5\n"; + ss << "exp_negative_negative_val = -62.1e-5\n"; + + ss << "\n[booleans]\n"; + ss << "number_true = 1\n"; + ss << "number_false = 0\n"; + ss << "yn_true = yes\n"; + ss << "yn_false = no\n"; + ss << "tf_true = true\n"; + ss << "tf_false = false\n"; + ss << "onoff_true = on\n"; + ss << "onoff_false = off\n"; + ss << "present_equal_true = \n"; + //FAILS: Must be an = + //ss << "present_no_equal_true\n"; + + ss.seekp(ios_base::beg); + return ss; +} + +po::options_description set_options() +{ + po::options_description opts; + opts.add_options() + ("global_string", po::value<string>()) + + ("strings.word", po::value<string>()) + ("strings.phrase", po::value<string>()) + ("strings.quoted", po::value<string>()) + + ("ints.positive", po::value<int>()) + ("ints.negative", po::value<int>()) + ("ints.hex", po::value<int>()) + ("ints.oct", po::value<int>()) + ("ints.bin", po::value<int>()) + + ("floats.positive", po::value<float>()) + ("floats.negative", po::value<float>()) + ("floats.double", po::value<double>()) + ("floats.int", po::value<float>()) + ("floats.int_dot", po::value<float>()) + ("floats.dot", po::value<float>()) + ("floats.exp_lower", po::value<float>()) + ("floats.exp_upper", po::value<float>()) + ("floats.exp_decimal", po::value<float>()) + ("floats.exp_negative", po::value<float>()) + ("floats.exp_negative_val", po::value<float>()) + ("floats.exp_negative_negative_val", po::value<float>()) + + // Load booleans as value<bool>, so they will require a --option=value on the command line + //("booleans.number_true", po::value<bool>()) + //("booleans.number_false", po::value<bool>()) + //("booleans.yn_true", po::value<bool>()) + //("booleans.yn_false", po::value<bool>()) + //("booleans.tf_true", po::value<bool>()) + //("booleans.tf_false", po::value<bool>()) + //("booleans.onoff_true", po::value<bool>()) + //("booleans.onoff_false", po::value<bool>()) + //("booleans.present_equal_true", po::value<bool>()) + //("booleans.present_no_equal_true", po::value<bool>()) + + // Load booleans as bool_switch, so that a --option will set it true on the command line + // The difference between these two types does not show up when parsing a file + ("booleans.number_true", po::bool_switch()) + ("booleans.number_false", po::bool_switch()) + ("booleans.yn_true", po::bool_switch()) + ("booleans.yn_false", po::bool_switch()) + ("booleans.tf_true", po::bool_switch()) + ("booleans.tf_false", po::bool_switch()) + ("booleans.onoff_true", po::bool_switch()) + ("booleans.onoff_false", po::bool_switch()) + ("booleans.present_equal_true", po::bool_switch()) + ("booleans.present_no_equal_true", po::bool_switch()) + ; + return opts; +} + +vector<string> parse_file(stringstream &file, po::options_description &opts, po::variables_map &vm) +{ + const bool ALLOW_UNREGISTERED = true; + cout << file.str() << endl; + + po::parsed_options parsed = parse_config_file(file, opts, ALLOW_UNREGISTERED); + store(parsed, vm); + vector<string> unregistered = po::collect_unrecognized(parsed.options, po::exclude_positional); + notify(vm); + + return unregistered; +} + +void check_results(po::variables_map &vm, vector<string> unregistered) +{ + // Check that we got the correct values back + string expected_global_string = "global value"; + + string expected_unreg_option = "unregistered_entry"; + string expected_unreg_value = "unregistered value"; + + string expected_strings_word = "word"; + string expected_strings_phrase = "this is a phrase"; + string expected_strings_quoted = "\"quotes are in result\""; + + int expected_int_postitive = 41; + int expected_int_negative = -42; + int expected_int_hex = 0x43; + int expected_int_oct = 044; + int expected_int_bin = 0b101010; + + float expected_float_positive = 51.1f; + float expected_float_negative = -52.1f; + double expected_float_double = 53.1234567890; + float expected_float_int = 54.0f; + float expected_float_int_dot = 55.0f; + float expected_float_dot = .56f; + float expected_float_exp_lower = 57.1e5f; + float expected_float_exp_upper = 58.1E5f; + float expected_float_exp_decimal = .591e5f; + float expected_float_exp_negative = 60.1e-5f; + float expected_float_exp_negative_val = -61.1e5f; + float expected_float_exp_negative_negative_val = -62.1e-5f; + + bool expected_number_true = true; + bool expected_number_false = false; + bool expected_yn_true = true; + bool expected_yn_false = false; + bool expected_tf_true = true; + bool expected_tf_false = false; + bool expected_onoff_true = true; + bool expected_onoff_false = false; + bool expected_present_equal_true = true; + bool expected_present_no_equal_true = true; + + assert(vm["global_string"].as<string>() == expected_global_string); + + assert(unregistered[0] == expected_unreg_option); + assert(unregistered[1] == expected_unreg_value); + + assert(vm["strings.word"].as<string>() == expected_strings_word); + assert(vm["strings.phrase"].as<string>() == expected_strings_phrase); + assert(vm["strings.quoted"].as<string>() == expected_strings_quoted); + + assert(vm["ints.positive"].as<int>() == expected_int_postitive); + assert(vm["ints.negative"].as<int>() == expected_int_negative); + //assert(vm["ints.hex"].as<int>() == expected_int_hex); + //assert(vm["ints.oct"].as<int>() == expected_int_oct); + //assert(vm["ints.bin"].as<int>() == expected_int_bin); + + assert(check_float(vm["floats.positive"].as<float>(), expected_float_positive)); + assert(check_float(vm["floats.negative"].as<float>(), expected_float_negative)); + assert(check_float(vm["floats.double"].as<double>(), expected_float_double)); + assert(check_float(vm["floats.int"].as<float>(), expected_float_int)); + assert(check_float(vm["floats.int_dot"].as<float>(), expected_float_int_dot)); + assert(check_float(vm["floats.dot"].as<float>(), expected_float_dot)); + assert(check_float(vm["floats.exp_lower"].as<float>(), expected_float_exp_lower)); + assert(check_float(vm["floats.exp_upper"].as<float>(), expected_float_exp_upper)); + assert(check_float(vm["floats.exp_decimal"].as<float>(), expected_float_exp_decimal)); + assert(check_float(vm["floats.exp_negative"].as<float>(), expected_float_exp_negative)); + assert(check_float(vm["floats.exp_negative_val"].as<float>(), expected_float_exp_negative_val)); + assert(check_float(vm["floats.exp_negative_negative_val"].as<float>(), expected_float_exp_negative_negative_val)); + + assert(vm["booleans.number_true"].as<bool>() == expected_number_true); + assert(vm["booleans.number_false"].as<bool>() == expected_number_false); + assert(vm["booleans.yn_true"].as<bool>() == expected_yn_true); + assert(vm["booleans.yn_false"].as<bool>() == expected_yn_false); + assert(vm["booleans.tf_true"].as<bool>() == expected_tf_true); + assert(vm["booleans.tf_false"].as<bool>() == expected_tf_false); + assert(vm["booleans.onoff_true"].as<bool>() == expected_onoff_true); + assert(vm["booleans.onoff_false"].as<bool>() == expected_onoff_false); + assert(vm["booleans.present_equal_true"].as<bool>() == expected_present_equal_true); + //assert(vm["booleans.present_no_equal_true"].as<bool>() == expected_present_no_equal_true); +} + +int main(int ac, char* av[]) +{ + auto file = make_file(); + auto opts = set_options(); + po::variables_map vars; + auto unregistered = parse_file(file, opts, vars); + check_results(vars, unregistered); + + return 0; +} diff --git a/src/boost/libs/program_options/example/custom_syntax.cpp b/src/boost/libs/program_options/example/custom_syntax.cpp new file mode 100644 index 000000000..829087d9d --- /dev/null +++ b/src/boost/libs/program_options/example/custom_syntax.cpp @@ -0,0 +1,63 @@ +// Copyright Vladimir Prus 2002-2004. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +/** This example shows how to support custom options syntax. + + It's possible to install 'custom_parser'. It will be invoked on all command + line tokens and can return name/value pair, or nothing. If it returns + nothing, usual processing will be done. +*/ + + +#include <boost/program_options/options_description.hpp> +#include <boost/program_options/parsers.hpp> +#include <boost/program_options/variables_map.hpp> + +using namespace boost::program_options; + +#include <iostream> +using namespace std; + +/* This custom option parse function recognize gcc-style + option "-fbar" / "-fno-bar". +*/ +pair<string, string> reg_foo(const string& s) +{ + if (s.find("-f") == 0) { + if (s.substr(2, 3) == "no-") + return make_pair(s.substr(5), string("false")); + else + return make_pair(s.substr(2), string("true")); + } else { + return make_pair(string(), string()); + } +} + +int main(int ac, char* av[]) +{ + try { + options_description desc("Allowed options"); + desc.add_options() + ("help", "produce a help message") + ("foo", value<string>(), "just an option") + ; + + variables_map vm; + store(command_line_parser(ac, av).options(desc).extra_parser(reg_foo) + .run(), vm); + + if (vm.count("help")) { + cout << desc; + cout << "\nIn addition -ffoo and -fno-foo syntax are recognized.\n"; + } + if (vm.count("foo")) { + cout << "foo value with the value of " + << vm["foo"].as<string>() << "\n"; + } + } + catch(exception& e) { + cout << e.what() << "\n"; + } +} diff --git a/src/boost/libs/program_options/example/env_options.cpp b/src/boost/libs/program_options/example/env_options.cpp new file mode 100644 index 000000000..bab37e252 --- /dev/null +++ b/src/boost/libs/program_options/example/env_options.cpp @@ -0,0 +1,47 @@ +// Copyright Thomas Kent 2016 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/program_options.hpp> +namespace po = boost::program_options; +#include <string> +#include <iostream> + +std::string mapper(std::string env_var) +{ + // ensure the env_var is all caps + std::transform(env_var.begin(), env_var.end(), env_var.begin(), ::toupper); + + if (env_var == "PATH") return "path"; + if (env_var == "EXAMPLE_VERBOSE") return "verbosity"; + return ""; +} + +void get_env_options() +{ + po::options_description config("Configuration"); + config.add_options() + ("path", "the execution path") + ("verbosity", po::value<std::string>()->default_value("INFO"), "set verbosity: DEBUG, INFO, WARN, ERROR, FATAL") + ; + + po::variables_map vm; + store(po::parse_environment(config, boost::function1<std::string, std::string>(mapper)), vm); + notify(vm); + + if (vm.count("path")) + { + std::cout << "First 75 chars of the system path: \n"; + std::cout << vm["path"].as<std::string>().substr(0, 75) << std::endl; + } + + std::cout << "Verbosity: " << vm["verbosity"].as<std::string>() << std::endl; +} + +int main(int ac, char* av[]) +{ + get_env_options(); + + return 0; +} diff --git a/src/boost/libs/program_options/example/first.cpp b/src/boost/libs/program_options/example/first.cpp new file mode 100644 index 000000000..8763fec9c --- /dev/null +++ b/src/boost/libs/program_options/example/first.cpp @@ -0,0 +1,51 @@ +// Copyright Vladimir Prus 2002-2004. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +/* The simplest usage of the library. + */ + +#include <boost/program_options.hpp> +namespace po = boost::program_options; + +#include <iostream> +#include <iterator> +using namespace std; + +int main(int ac, char* av[]) +{ + try { + + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "produce help message") + ("compression", po::value<double>(), "set compression level") + ; + + po::variables_map vm; + po::store(po::parse_command_line(ac, av, desc), vm); + po::notify(vm); + + if (vm.count("help")) { + cout << desc << "\n"; + return 0; + } + + if (vm.count("compression")) { + cout << "Compression level was set to " + << vm["compression"].as<double>() << ".\n"; + } else { + cout << "Compression level was not set.\n"; + } + } + catch(exception& e) { + cerr << "error: " << e.what() << "\n"; + return 1; + } + catch(...) { + cerr << "Exception of unknown type!\n"; + } + + return 0; +} diff --git a/src/boost/libs/program_options/example/multiple_sources.cfg b/src/boost/libs/program_options/example/multiple_sources.cfg new file mode 100644 index 000000000..6966d0048 --- /dev/null +++ b/src/boost/libs/program_options/example/multiple_sources.cfg @@ -0,0 +1,5 @@ +# +# Comment out this line to use hard-coded default value of 10 +# +optimization = 1 +include-path = /opt
\ No newline at end of file diff --git a/src/boost/libs/program_options/example/multiple_sources.cpp b/src/boost/libs/program_options/example/multiple_sources.cpp new file mode 100644 index 000000000..22c8235bc --- /dev/null +++ b/src/boost/libs/program_options/example/multiple_sources.cpp @@ -0,0 +1,121 @@ +// Copyright Vladimir Prus 2002-2004. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +/* Shows how to use both command line and config file. */ + +#include <boost/program_options.hpp> +namespace po = boost::program_options; + + +#include <iostream> +#include <fstream> +#include <iterator> +using namespace std; + +// A helper function to simplify the main part. +template<class T> +ostream& operator<<(ostream& os, const vector<T>& v) +{ + copy(v.begin(), v.end(), ostream_iterator<T>(os, " ")); + return os; +} + + +int main(int ac, char* av[]) +{ + try { + int opt; + string config_file; + + // Declare a group of options that will be + // allowed only on command line + po::options_description generic("Generic options"); + generic.add_options() + ("version,v", "print version string") + ("help", "produce help message") + ("config,c", po::value<string>(&config_file)->default_value("multiple_sources.cfg"), + "name of a file of a configuration.") + ; + + // Declare a group of options that will be + // allowed both on command line and in + // config file + po::options_description config("Configuration"); + config.add_options() + ("optimization", po::value<int>(&opt)->default_value(10), + "optimization level") + ("include-path,I", + po::value< vector<string> >()->composing(), + "include path") + ; + + // Hidden options, will be allowed both on command line and + // in config file, but will not be shown to the user. + po::options_description hidden("Hidden options"); + hidden.add_options() + ("input-file", po::value< vector<string> >(), "input file") + ; + + + po::options_description cmdline_options; + cmdline_options.add(generic).add(config).add(hidden); + + po::options_description config_file_options; + config_file_options.add(config).add(hidden); + + po::options_description visible("Allowed options"); + visible.add(generic).add(config); + + po::positional_options_description p; + p.add("input-file", -1); + + po::variables_map vm; + store(po::command_line_parser(ac, av). + options(cmdline_options).positional(p).run(), vm); + notify(vm); + + ifstream ifs(config_file.c_str()); + if (!ifs) + { + cout << "can not open config file: " << config_file << "\n"; + return 0; + } + else + { + store(parse_config_file(ifs, config_file_options), vm); + notify(vm); + } + + if (vm.count("help")) { + cout << visible << "\n"; + return 0; + } + + if (vm.count("version")) { + cout << "Multiple sources example, version 1.0\n"; + return 0; + } + + if (vm.count("include-path")) + { + cout << "Include paths are: " + << vm["include-path"].as< vector<string> >() << "\n"; + } + + if (vm.count("input-file")) + { + cout << "Input files are: " + << vm["input-file"].as< vector<string> >() << "\n"; + } + + cout << "Optimization level is " << opt << "\n"; + } + catch(exception& e) + { + cout << e.what() << "\n"; + return 1; + } + return 0; +} diff --git a/src/boost/libs/program_options/example/option_groups.cpp b/src/boost/libs/program_options/example/option_groups.cpp new file mode 100644 index 000000000..63e1fca48 --- /dev/null +++ b/src/boost/libs/program_options/example/option_groups.cpp @@ -0,0 +1,97 @@ +// Copyright Vladimir Prus 2002-2004. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +/** This example shows how to handle options groups. + + For a test, run: + + option_groups --help + option_groups --num-threads 10 + option_groups --help-module backend + + The first invocation would show to option groups, and will not show the + '--num-threads' options. The second invocation will still get the value of + the hidden '--num-threads' option. Finally, the third invocation will show + the options for the 'backend' module, including the '--num-threads' option. + +*/ + + +#include <boost/program_options/options_description.hpp> +#include <boost/program_options/parsers.hpp> +#include <boost/program_options/variables_map.hpp> +#include <boost/tokenizer.hpp> +#include <boost/token_functions.hpp> +using namespace boost; +using namespace boost::program_options; + +#include <iostream> +#include <fstream> +#include <exception> +using namespace std; + +int main(int ac, char* av[]) +{ + try { + // Declare three groups of options. + options_description general("General options"); + general.add_options() + ("help", "produce a help message") + ("help-module", value<string>(), + "produce a help for a given module") + ("version", "output the version number") + ; + + options_description gui("GUI options"); + gui.add_options() + ("display", value<string>(), "display to use") + ; + + options_description backend("Backend options"); + backend.add_options() + ("num-threads", value<int>(), "the initial number of threads") + ; + + // Declare an options description instance which will include + // all the options + options_description all("Allowed options"); + all.add(general).add(gui).add(backend); + + // Declare an options description instance which will be shown + // to the user + options_description visible("Allowed options"); + visible.add(general).add(gui); + + + variables_map vm; + store(parse_command_line(ac, av, all), vm); + + if (vm.count("help")) + { + cout << visible; + return 0; + } + if (vm.count("help-module")) { + const string& s = vm["help-module"].as<string>(); + if (s == "gui") { + cout << gui; + } else if (s == "backend") { + cout << backend; + } else { + cout << "Unknown module '" + << s << "' in the --help-module option\n"; + return 1; + } + return 0; + } + if (vm.count("num-threads")) { + cout << "The 'num-threads' options was set to " + << vm["num-threads"].as<int>() << "\n"; + } + } + catch(std::exception& e) { + cout << e.what() << "\n"; + } +} diff --git a/src/boost/libs/program_options/example/options_description.cpp b/src/boost/libs/program_options/example/options_description.cpp new file mode 100644 index 000000000..e9ad2a67d --- /dev/null +++ b/src/boost/libs/program_options/example/options_description.cpp @@ -0,0 +1,86 @@ +// Copyright Vladimir Prus 2002-2004. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/program_options.hpp> + +using namespace boost; +namespace po = boost::program_options; + +#include <iostream> +#include <algorithm> +#include <iterator> +using namespace std; + + +// A helper function to simplify the main part. +template<class T> +ostream& operator<<(ostream& os, const vector<T>& v) +{ + copy(v.begin(), v.end(), ostream_iterator<T>(os, " ")); + return os; +} + +int main(int ac, char* av[]) +{ + try { + int opt; + int portnum; + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "produce help message") + ("optimization", po::value<int>(&opt)->default_value(10), + "optimization level") + ("verbose,v", po::value<int>()->implicit_value(1), + "enable verbosity (optionally specify level)") + ("listen,l", po::value<int>(&portnum)->implicit_value(1001) + ->default_value(0,"no"), + "listen on a port.") + ("include-path,I", po::value< vector<string> >(), + "include path") + ("input-file", po::value< vector<string> >(), "input file") + ; + + po::positional_options_description p; + p.add("input-file", -1); + + po::variables_map vm; + po::store(po::command_line_parser(ac, av). + options(desc).positional(p).run(), vm); + po::notify(vm); + + if (vm.count("help")) { + cout << "Usage: options_description [options]\n"; + cout << desc; + return 0; + } + + if (vm.count("include-path")) + { + cout << "Include paths are: " + << vm["include-path"].as< vector<string> >() << "\n"; + } + + if (vm.count("input-file")) + { + cout << "Input files are: " + << vm["input-file"].as< vector<string> >() << "\n"; + } + + if (vm.count("verbose")) { + cout << "Verbosity enabled. Level is " << vm["verbose"].as<int>() + << "\n"; + } + + cout << "Optimization level is " << opt << "\n"; + + cout << "Listen port is " << portnum << "\n"; + } + catch(std::exception& e) + { + cout << e.what() << "\n"; + return 1; + } + return 0; +} diff --git a/src/boost/libs/program_options/example/options_heirarchy.cpp b/src/boost/libs/program_options/example/options_heirarchy.cpp new file mode 100644 index 000000000..c913b149e --- /dev/null +++ b/src/boost/libs/program_options/example/options_heirarchy.cpp @@ -0,0 +1,690 @@ +// Copyright Thomas Kent 2016 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// +// This is an example of a program that uses multiple facets of the boost +// program_options library. It will go through different types of config +// options in a heirarchal manner: +// 1. Default options are set. +// 2. Command line options are set (they override defaults). +// 3. Environment options are set (they override defaults but not command +// line options). +// 4. Config files specified on the command line are read, if present, in +// the order specified. (these override defaults but not options from the +// other steps). +// 5. Default config file (default.cfg) is read, if present (it overrides +// defaults but not options from the other steps). +// +// See the bottom of this file for full usage examples +// + +#include <boost/program_options.hpp> +namespace po = boost::program_options; +#include <string> +#include <iostream> +#include <map> +#include <stdexcept> +#include <fstream> + +const std::string version("1.0"); + +// Used to exit the program if the help/version option is set +class OptionsExitsProgram : public std::exception +{}; + +struct GuiOpts +{ + unsigned int width; + unsigned int height; +}; + +struct NetworkOpts +{ + std::string address; + unsigned short port; +}; + +class OptionsHeirarchy +{ +public: + // The constructor sets up all the various options that will be parsed + OptionsHeirarchy() + { + SetOptions(); + } + + // Parse options runs through the heirarchy doing all the parsing + void ParseOptions(int argc, char* argv[]) + { + ParseCommandLine(argc, argv); + CheckForHelp(); + CheckForVersion(); + ParseEnvironment(); + ParseConfigFiles(); + ParseDefaultConfigFile(); + } + + // Below is the interface to access the data, once ParseOptions has been run + std::string Path() + { + return results["path"].as<std::string>(); + } + std::string Verbosity() + { + return results["verbosity"].as<std::string>(); + } + std::vector<std::string> IncludePath() + { + if (results.count("include-path")) + { + return results["include-path"].as<std::vector<std::string>>(); + } + return std::vector<std::string>(); + } + std::string MasterFile() + { + if (results.count("master-file")) + { + return results["master-file"].as<std::string>(); + } + return ""; + } + std::vector<std::string> Files() + { + if (results.count("file")) + { + return results["file"].as<std::vector<std::string>>(); + } + return std::vector<std::string>(); + } + bool GUI() + { + if (results["run-gui"].as<bool>()) + { + return true; + } + return false; + } + GuiOpts GuiValues() + { + GuiOpts opts; + opts.width = results["gui.width"].as<unsigned int>(); + opts.height = results["gui.height"].as<unsigned int>(); + return opts; + } + NetworkOpts NetworkValues() + { + NetworkOpts opts; + opts.address = results["network.ip"].as<std::string>(); + opts.port = results["network.port"].as<unsigned short>(); + return opts; + } + +private: + void SetOptions() + { + SetCommandLineOptions(); + SetCommonOptions(); + SetConfigOnlyOptions(); + SetEnvMapping(); + } + void SetCommandLineOptions() + { + command_line_options.add_options() + ("help,h", "display this help message") + ("version,v", "show program version") + ("config,c", po::value<std::vector<std::string>>(), + "config files to parse (always parses default.cfg)") + ; + hidden_command_line_options.add_options() + ("master-file", po::value<std::string>()) + ("file", po::value<std::vector<std::string>>()) + ; + positional_options.add("master-file", 1); + positional_options.add("file", -1); + } + void SetCommonOptions() + { + common_options.add_options() + ("path", po::value<std::string>()->default_value(""), + "the execution path to use (imports from environment if not specified)") + ("verbosity", po::value<std::string>()->default_value("INFO"), + "set verbosity: DEBUG, INFO, WARN, ERROR, FATAL") + ("include-path,I", po::value<std::vector<std::string>>()->composing(), + "paths to search for include files") + ("run-gui", po::bool_switch(), "start the GUI") + ; + } + void SetConfigOnlyOptions() + { + config_only_options.add_options() + ("log-dir", po::value<std::string>()->default_value("log")) + ("gui.height", po::value<unsigned int>()->default_value(100)) + ("gui.width", po::value<unsigned int>()->default_value(100)) + ("network.ip", po::value<std::string>()->default_value("127.0.0.1")) + ("network.port", po::value<unsigned short>()->default_value(12345)) + ; + // Run a parser here (with no command line options) to add these defaults into + // results, this way they will be enabled even if no config files are parsed. + store(po::command_line_parser(0, 0).options(config_only_options).run(), results); + notify(results); + } + void SetEnvMapping() + { + env_to_option["PATH"] = "path"; + env_to_option["EXAMPLE_VERBOSE"] = "verbosity"; + } + + + void ParseCommandLine(int argc, char* argv[]) + { + po::options_description cmd_opts; + cmd_opts.add(command_line_options).add(hidden_command_line_options).add(common_options); + store(po::command_line_parser(argc, argv). + options(cmd_opts).positional(positional_options).run(), results); + notify(results); + } + void CheckForHelp() + { + if (results.count("help")) + { + PrintHelp(); + } + } + void PrintHelp() + { + std::cout << "Program Options Example" << std::endl; + std::cout << "Usage: example [OPTION]... MASTER-FILE [FILE]...\n"; + std::cout << " or example [OPTION] --run-gui\n"; + po::options_description help_opts; + help_opts.add(command_line_options).add(common_options); + std::cout << help_opts << std::endl; + throw OptionsExitsProgram(); + } + void CheckForVersion() + { + if (results.count("version")) + { + PrintVersion(); + } + } + void PrintVersion() + { + std::cout << "Program Options Example " << version << std::endl; + throw OptionsExitsProgram(); + } + void ParseEnvironment() + { + store(po::parse_environment(common_options, + // The next two lines are the crazy syntax to use EnvironmentMapper as + // the lookup function for env->config name conversions + boost::function1<std::string, std::string>( + std::bind1st(std::mem_fun(&OptionsHeirarchy::EnvironmentMapper), this))), + results); + notify(results); + } + std::string EnvironmentMapper(std::string env_var) + { + // ensure the env_var is all caps + std::transform(env_var.begin(), env_var.end(), env_var.begin(), ::toupper); + + auto entry = env_to_option.find(env_var); + if (entry != env_to_option.end()) + { + return entry->second; + } + return ""; + } + void ParseConfigFiles() + { + if (results.count("config")) + { + auto files = results["config"].as<std::vector<std::string>>(); + for (auto file = files.begin(); file != files.end(); file++) + { + LoadAConfigFile(*file); + } + } + } + void LoadAConfigFile(std::string filename) + { + bool ALLOW_UNREGISTERED = true; + + po::options_description config_opts; + config_opts.add(config_only_options).add(common_options); + + std::ifstream cfg_file(filename.c_str()); + if (cfg_file) + { + store(parse_config_file(cfg_file, config_opts, ALLOW_UNREGISTERED), results); + notify(results); + } + } + void ParseDefaultConfigFile() + { + LoadAConfigFile("default.cfg"); + } + + std::map<std::string, std::string> env_to_option; + po::options_description config_only_options; + po::options_description common_options; + po::options_description command_line_options; + po::options_description hidden_command_line_options; + po::positional_options_description positional_options; + po::variables_map results; +}; + + +void get_env_options() +{ +} + +void PrintOptions(OptionsHeirarchy options) +{ + auto path = options.Path(); + if (path.length()) + { + std::cout << "First 75 chars of the system path: \n"; + std::cout << options.Path().substr(0, 75) << std::endl; + } + + std::cout << "Verbosity: " << options.Verbosity() << std::endl; + std::cout << "Include Path:\n"; + auto includePaths = options.IncludePath(); + for (auto path = includePaths.begin(); path != includePaths.end(); path++) + { + std::cout << " " << *path << std::endl; + } + std::cout << "Master-File: " << options.MasterFile() << std::endl; + std::cout << "Additional Files:\n"; + auto files = options.Files(); + for (auto file = files.begin(); file != files.end(); file++) + { + std::cout << " " << *file << std::endl; + } + + std::cout << "GUI Enabled: " << std::boolalpha << options.GUI() << std::endl; + if (options.GUI()) + { + auto gui_values = options.GuiValues(); + std::cout << "GUI Height: " << gui_values.height << std::endl; + std::cout << "GUI Width: " << gui_values.width << std::endl; + } + + auto network_values = options.NetworkValues(); + std::cout << "Network Address: " << network_values.address << std::endl; + std::cout << "Network Port: " << network_values.port << std::endl; +} + +int main(int ac, char* av[]) +{ + OptionsHeirarchy options; + try + { + options.ParseOptions(ac, av); + PrintOptions(options); + } + catch (OptionsExitsProgram){} + + return 0; +} + +/* +Full Usage Examples +=================== + +These were run on windows, so some results may show that environment, but +results should be similar on POSIX platforms. + +Help +---- +To see the help screen, with the available options just pass the --help (or -h) +parameter. The program will then exit. + + > example.exe --help + Program Options Example + Usage: example [OPTION]... MASTER-FILE [FILE]... + or example [OPTION] --run-gui + + -h [ --help ] display this help message + -v [ --version ] show program version + -c [ --config ] arg config files to parse (always parses default.cfg) + + --path arg the execution path to use (imports from + environment if not specified) + --verbosity arg (=INFO) set verbosity: DEBUG, INFO, WARN, ERROR, FATAL + -I [ --include-path ] arg paths to search for include files + --run-gui start the GUI + +Version is similar to help (--version or -v). + + > example.exe -v + Program Options Example 1.0 + +Basics +------ +Running without any options will get the default values (path is set from the +environment): + + > example.exe + First 75 chars of the system path: + C:\Program Files (x86)\MSBuild\14.0\bin;C:\Perl\site\bin;C:\Perl\bin;C:\Pro + Verbosity: INFO + Include Path: + Master-File: + Additional Files: + GUI Enabled: false + Network Address: 127.0.0.1 + Network Port: 12345 + +We can easily override that environment path with a simple option: + + > example.exe --path a/b/c;d/e/f + First 75 chars of the system path: + a/b/c;d/e/f + Verbosity: INFO + Include Path: + Master-File: + Additional Files: + GUI Enabled: false + Network Address: 127.0.0.1 + Network Port: 12345 + +You can use a space or equals sign after long options, also backslashes are +treated literally on windows, on POSIX they need to be escaped. + + > example.exe --path=a\b\c\;d\e\\f + First 75 chars of the system path: + a\b\c\;d\e\\f + Verbosity: INFO + Include Path: + Master-File: + Additional Files: + GUI Enabled: false + Network Address: 127.0.0.1 + Network Port: 12345 + +For short options you can use a space: + + > example.exe -I path/to/includes + First 75 chars of the system path: + C:\Program Files (x86)\MSBuild\14.0\bin;C:\Perl\site\bin;C:\Perl\bin;C:\Pro + Verbosity: INFO + Include Path: + path\to\includes + Master-File: + Additional Files: + GUI Enabled: false + Network Address: 127.0.0.1 + Network Port: 12345 + +Or you can put the option immediately after it: + + > example.exe -Ipath/to/includes + First 75 chars of the system path: + C:\Program Files (x86)\MSBuild\14.0\bin;C:\Perl\site\bin;C:\Perl\bin;C:\Pro + Verbosity: INFO + Include Path: + path\to\includes + Master-File: + Additional Files: + GUI Enabled: false + Network Address: 127.0.0.1 + Network Port: 12345 + +The include path (--include-path or -I) option allows for multiple paths to be +specified (both on the command line and in config files) and combined into a +vector for use by the program. + + > example.exe --include-path=a/b/c --include-path d/e/f -I g/h/i -Ij/k/l + First 75 chars of the system path: + C:\Program Files (x86)\MSBuild\14.0\bin;C:\Perl\site\bin;C:\Perl\bin;C:\Pro + Verbosity: INFO + Include Path: + a/b/c + d/e/f + g/h/i + j/k/l + Master-File: + Additional Files: + GUI Enabled: false + Network Address: 127.0.0.1 + Network Port: 12345 + +There are also the option of flags that do not take parameters and just set a +boolean value to true. In this case, running the gui also causes default values +for the gui to be output to the screen. + + > example.exe --run-gui + First 75 chars of the system path: + C:\Program Files (x86)\MSBuild\14.0\bin;C:\Perl\site\bin;C:\Perl\bin;C:\Pro + Verbosity: INFO + Include Path: + Master-File: + Additional Files: + GUI Enabled: true + GUI Height: 100 + GUI Width: 100 + Network Address: 127.0.0.1 + Network Port: 12345 + +There are also "positional" options at the end of the command line. The first +one specifies the "master" file the others are additional files. + + > example.exe --path=a-path -I an-include master.cpp additional1.cpp additional2.cpp + First 75 chars of the system path: + a-path + Verbosity: INFO + Include Path: + an-include + Master-File: master.cpp + Additional Files: + additional1.cpp + additional2.cpp + GUI Enabled: false + Network Address: 127.0.0.1 + Network Port: 12345 + +Environment Variables +--------------------- +In addition to the PATH environment variable, it also knows how to read the +EXAMPLE_VERBOSE environmental variable and use that to set the verbosity +option/ + + > set EXAMPLE_VERBOSE=DEBUG + > example.exe + First 75 chars of the system path: + C:\Program Files (x86)\MSBuild\14.0\bin;C:\Perl\site\bin;C:\Perl\bin;C:\Pro + Verbosity: DEBUG + Include Path: + Master-File: + Additional Files: + GUI Enabled: false + Network Address: 127.0.0.1 + Network Port: 12345 + +However, if the --verboseity flag is also set, it will override the env +variable. This illustrates an important example, the way program_options works, +is that a parser will not override a value that has previously been set by +another parser. Thus the env parser doesn't override the command line parser. +(We will see this again in config files.) Default values are seperate from this +heirarcy, they only apply if no parser has set the value and it is being read. + + > set EXAMPLE_VERBOSE=DEBUG + > example.exe --verbosity=WARN + First 75 chars of the system path: + C:\Program Files (x86)\MSBuild\14.0\bin;C:\Perl\site\bin;C:\Perl\bin;C:\Pro + Verbosity: WARN + Include Path: + Master-File: + Additional Files: + GUI Enabled: false + Network Address: 127.0.0.1 + Network Port: 12345 + +(You can unset an environmental variable with an empty set command) + + > set EXAMPLE_VERBOSE= + > example.exe + First 75 chars of the system path: + C:\Program Files (x86)\MSBuild\14.0\bin;C:\Perl\site\bin;C:\Perl\bin;C:\Pro + Verbosity: INFO + Include Path: + Master-File: + Additional Files: + GUI Enabled: false + Network Address: 127.0.0.1 + Network Port: 12345 + + +Config Files +------------ +Config files generally follow the [INI file format] +(https://en.wikipedia.org/wiki/INI_file) with a few exceptions. + +Values can be simply added tp options with an equal sign. Here are two include +paths added via the default config file (default.cfg), you can have optional +spaces around the equal sign. + + # You can use comments in a config file + include-path=first/default/path + include-path = second/default/path + +Results in + + > example.exe + First 75 chars of the system path: + C:\Program Files (x86)\MSBuild\14.0\bin;C:\Perl\site\bin;C:\Perl\bin;C:\Pro + Verbosity: INFO + Include Path: + first/default/path + second/default/path + Master-File: + Additional Files: + GUI Enabled: false + Network Address: 127.0.0.1 + Network Port: 12345 + +Values can also be in sections of the config file. Again, editing default.cfg + + include-path=first/default/path + include-path = second/default/path + + [network] + ip=1.2.3.4 + port=3000 + +Results in + + > example.exe + First 75 chars of the system path: + C:\Program Files (x86)\MSBuild\14.0\bin;C:\Perl\site\bin;C:\Perl\bin;C:\Pro + Verbosity: INFO + Include Path: + first/default/path + second/default/path + Master-File: + Additional Files: + GUI Enabled: false + Network Address: 1.2.3.4 + Network Port: 3000 + +This example is also setup to allow multiple config files to be specified on +the command line, which are checked before the default.cfg file is read (but +after the environment and command line parsing). Thus we can set the first.cfg +file to contain the following: + + verbosity=ERROR + + [network] + ip = 5.6.7.8 + +Results in: + + > example.exe --config first.cfg + First 75 chars of the system path: + C:\Program Files (x86)\MSBuild\14.0\bin;C:\Perl\site\bin;C:\Perl\bin;C:\Pro + Verbosity: ERROR + Include Path: + first/default/path + second/default/path + Master-File: + Additional Files: + GUI Enabled: false + Network Address: 5.6.7.8 + Network Port: 3000 + +But since the config files are read after the command line, setting the +verbosity there causes the value in the file to be ignored. + + > example.exe --config first.cfg --verbosity=WARN + First 75 chars of the system path: + C:\Program Files (x86)\MSBuild\14.0\bin;C:\Perl\site\bin;C:\Perl\bin;C:\Pro + Verbosity: WARN + Include Path: + first/default/path + second/default/path + Master-File: + Additional Files: + GUI Enabled: false + Network Address: 5.6.7.8 + Network Port: 3000 + +The config files are parsed in the order they are received on the command line. +So adding the second.cfg file: + + verbosity=FATAL + run-gui=true + + [gui] + height=720 + width=1280 + +Results in a combination of all three config files: + + > example.exe --config first.cfg --config second.cfg + First 75 chars of the system path: + C:\Program Files (x86)\MSBuild\14.0\bin;C:\Perl\site\bin;C:\Perl\bin;C:\Pro + Verbosity: ERROR + Include Path: + first/default/path + second/default/path + Master-File: + Additional Files: + GUI Enabled: true + GUI Height: 720 + GUI Width: 1280 + Network Address: 5.6.7.8 + Network Port: 3000 + +Incidently the boolean run-gui option could have been set a number of ways +that all result in the C++ boolean value of true: + + run-gui=true + run-gui=on + run-gui=1 + run-gui=yes + run-gui= + +Since run-gui is an option that was set with the bool_switch type, which +forces its use on the command line without a parameter (i.e. --run-gui instead +of --run-gui=true) it can't be given a "false" option, bool_switch values can +only be turned true. If instead we had a value ("my-switch", po::value<bool>()) +that could be set at the command line --my-switch=true or --my-switch=false, or +any of the other types of boolean keywords true: true, on, 1, yes; +false: false, off, 0, no. In a config file this could look like: + + my-switch=true + my-switch=on + my-switch=1 + my-switch=yes + my-switch= + + my-switch=false + my-switch=off + my-switch=0 + my-switch=no + +*/ diff --git a/src/boost/libs/program_options/example/real.cpp b/src/boost/libs/program_options/example/real.cpp new file mode 100644 index 000000000..1c5d13221 --- /dev/null +++ b/src/boost/libs/program_options/example/real.cpp @@ -0,0 +1,96 @@ +// Copyright Vladimir Prus 2002-2004. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + + +#include <boost/program_options.hpp> +using namespace boost::program_options; + +#include <iostream> +using namespace std; + +/* Auxiliary functions for checking input for validity. */ + +/* Function used to check that 'opt1' and 'opt2' are not specified + at the same time. */ +void conflicting_options(const variables_map& vm, + const char* opt1, const char* opt2) +{ + if (vm.count(opt1) && !vm[opt1].defaulted() + && vm.count(opt2) && !vm[opt2].defaulted()) + throw logic_error(string("Conflicting options '") + + opt1 + "' and '" + opt2 + "'."); +} + +/* Function used to check that of 'for_what' is specified, then + 'required_option' is specified too. */ +void option_dependency(const variables_map& vm, + const char* for_what, const char* required_option) +{ + if (vm.count(for_what) && !vm[for_what].defaulted()) + if (vm.count(required_option) == 0 || vm[required_option].defaulted()) + throw logic_error(string("Option '") + for_what + + "' requires option '" + required_option + "'."); +} + +int main(int argc, char* argv[]) +{ + try { + string ofile; + string macrofile, libmakfile; + bool t_given = false; + bool b_given = false; + string mainpackage; + string depends = "deps_file"; + string sources = "src_file"; + string root = "."; + + options_description desc("Allowed options"); + desc.add_options() + // First parameter describes option name/short name + // The second is parameter to option + // The third is description + ("help,h", "print usage message") + ("output,o", value(&ofile), "pathname for output") + ("macrofile,m", value(¯ofile), "full pathname of macro.h") + ("two,t", bool_switch(&t_given), "preprocess both header and body") + ("body,b", bool_switch(&b_given), "preprocess body in the header context") + ("libmakfile,l", value(&libmakfile), + "write include makefile for library") + ("mainpackage,p", value(&mainpackage), + "output dependency information") + ("depends,d", value(&depends), + "write dependencies to <pathname>") + ("sources,s", value(&sources), "write source package list to <pathname>") + ("root,r", value(&root), "treat <dirname> as project root directory") + ; + + variables_map vm; + store(parse_command_line(argc, argv, desc), vm); + + if (vm.count("help")) { + cout << desc << "\n"; + return 0; + } + + conflicting_options(vm, "output", "two"); + conflicting_options(vm, "output", "body"); + conflicting_options(vm, "output", "mainpackage"); + conflicting_options(vm, "two", "mainpackage"); + conflicting_options(vm, "body", "mainpackage"); + + conflicting_options(vm, "two", "body"); + conflicting_options(vm, "libmakfile", "mainpackage"); + conflicting_options(vm, "libmakfile", "mainpackage"); + + option_dependency(vm, "depends", "mainpackage"); + option_dependency(vm, "sources", "mainpackage"); + option_dependency(vm, "root", "mainpackage"); + + cout << "two = " << vm["two"].as<bool>() << "\n"; + } + catch(exception& e) { + cerr << e.what() << "\n"; + } +} diff --git a/src/boost/libs/program_options/example/regex.cpp b/src/boost/libs/program_options/example/regex.cpp new file mode 100644 index 000000000..df98f77a0 --- /dev/null +++ b/src/boost/libs/program_options/example/regex.cpp @@ -0,0 +1,101 @@ +// Copyright Vladimir Prus 2002-2004. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +// This example shows how a user-defined class can be parsed using +// specific mechanism -- not the iostream operations used by default. +// +// A new class 'magic_number' is defined and the 'validate' method is overloaded +// to validate the values of that class using Boost.Regex. +// To test, run +// +// regex -m 123-456 +// regex -m 123-4567 +// +// The first invocation should output: +// +// The magic is "456" +// +// and the second invocation should issue an error message. + +#include <boost/program_options.hpp> +#include <boost/regex.hpp> + +using namespace boost; +using namespace boost::program_options; + +#include <iostream> +using namespace std; + +/* Define a completely non-sensical class. */ +struct magic_number { +public: + magic_number(int n) : n(n) {} + int n; +}; + +/* Overload the 'validate' function for the user-defined class. + It makes sure that value is of form XXX-XXX + where X are digits and converts the second group to an integer. + This has no practical meaning, meant only to show how + regex can be used to validate values. +*/ +void validate(boost::any& v, + const std::vector<std::string>& values, + magic_number*, int) +{ + static regex r("\\d\\d\\d-(\\d\\d\\d)"); + + using namespace boost::program_options; + + // Make sure no previous assignment to 'a' was made. + validators::check_first_occurrence(v); + // Extract the first string from 'values'. If there is more than + // one string, it's an error, and exception will be thrown. + const string& s = validators::get_single_string(values); + + // Do regex match and convert the interesting part to + // int. + smatch match; + if (regex_match(s, match, r)) { + v = any(magic_number(lexical_cast<int>(match[1]))); + } else { + throw validation_error(validation_error::invalid_option_value); + } +} + + +int main(int ac, char* av[]) +{ + try { + options_description desc("Allowed options"); + desc.add_options() + ("help", "produce a help screen") + ("version,v", "print the version number") + ("magic,m", value<magic_number>(), + "magic value (in NNN-NNN format)") + ; + + variables_map vm; + store(parse_command_line(ac, av, desc), vm); + + if (vm.count("help")) { + cout << "Usage: regex [options]\n"; + cout << desc; + return 0; + } + if (vm.count("version")) { + cout << "Version 1.\n"; + return 0; + } + if (vm.count("magic")) { + cout << "The magic is \"" + << vm["magic"].as<magic_number>().n << "\"\n"; + } + } + catch(std::exception& e) + { + cout << e.what() << "\n"; + } +} diff --git a/src/boost/libs/program_options/example/response_file.cpp b/src/boost/libs/program_options/example/response_file.cpp new file mode 100644 index 000000000..ce80f76a9 --- /dev/null +++ b/src/boost/libs/program_options/example/response_file.cpp @@ -0,0 +1,94 @@ +// Copyright Vladimir Prus 2002-2004. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +/** This example shows how to handle response file. + + For a test, build and run: + response_file -I foo @response_file.rsp + + The expected output is: + Include paths: foo bar biz + + Thanks to Hartmut Kaiser who raised the issue of response files + and discussed the possible approach. +*/ + + +#include <boost/program_options/options_description.hpp> +#include <boost/program_options/parsers.hpp> +#include <boost/program_options/variables_map.hpp> +#include <boost/tokenizer.hpp> +#include <boost/token_functions.hpp> +using namespace boost; +using namespace boost::program_options; + +#include <iostream> +#include <fstream> +using namespace std; + +// Additional command line parser which interprets '@something' as a +// option "config-file" with the value "something" +pair<string, string> at_option_parser(string const&s) +{ + if ('@' == s[0]) + return std::make_pair(string("response-file"), s.substr(1)); + else + return pair<string, string>(); +} + +int main(int ac, char* av[]) +{ + try { + options_description desc("Allowed options"); + desc.add_options() + ("help", "produce a help message") + ("include-path,I", value< vector<string> >()->composing(), + "include path") + ("magic", value<int>(), "magic value") + ("response-file", value<string>(), + "can be specified with '@name', too") + ; + + variables_map vm; + store(command_line_parser(ac, av).options(desc) + .extra_parser(at_option_parser).run(), vm); + + if (vm.count("help")) { + cout << desc; + } + if (vm.count("response-file")) { + // Load the file and tokenize it + ifstream ifs(vm["response-file"].as<string>().c_str()); + if (!ifs) { + cout << "Could not open the response file\n"; + return 1; + } + // Read the whole file into a string + stringstream ss; + ss << ifs.rdbuf(); + // Split the file content + char_separator<char> sep(" \n\r"); + string sstr = ss.str(); + tokenizer<char_separator<char> > tok(sstr, sep); + vector<string> args; + copy(tok.begin(), tok.end(), back_inserter(args)); + // Parse the file and store the options + store(command_line_parser(args).options(desc).run(), vm); + } + + if (vm.count("include-path")) { + const vector<string>& s = vm["include-path"].as<vector< string> >(); + cout << "Include paths: "; + copy(s.begin(), s.end(), ostream_iterator<string>(cout, " ")); + cout << "\n"; + } + if (vm.count("magic")) { + cout << "Magic value: " << vm["magic"].as<int>() << "\n"; + } + } + catch (std::exception& e) { + cout << e.what() << "\n"; + } +} diff --git a/src/boost/libs/program_options/example/response_file.rsp b/src/boost/libs/program_options/example/response_file.rsp new file mode 100644 index 000000000..d7c677730 --- /dev/null +++ b/src/boost/libs/program_options/example/response_file.rsp @@ -0,0 +1,3 @@ +-I bar +-I biz +--magic 10
\ No newline at end of file |