diff --git a/doc/overview.xml b/doc/overview.xml
index f7de2968c..b6b0f355a 100644
--- a/doc/overview.xml
+++ b/doc/overview.xml
@@ -512,7 +512,13 @@ visual_bell=yes
gui.accessibility.visual_bell=yes
-
+ When the option "gui.accessibility.visual_bell" has been added to the options
+
+options_description desc;
+desc.add_options()
+ ("gui.accessibility.visual_bell", value<string>(), "flash screen for bell")
+ ;
+
@@ -559,13 +565,50 @@ gui.accessibility.visual_bell=yes
function, any function taking a std::string and returning
std::string. That function will be called for each
environment variable and should return either the name of the option, or
- empty string if the variable should be ignored.
+ empty string if the variable should be ignored. An example showing this
+ method can be found in "example/env_options.cpp".
+ Types
+
+ Everything that is passed in on the command line, as an environmental
+ variable, or in a config file is a string. For values that need to be used
+ as a non-string type, the value in the variables_map will attempt to
+ convert it to the correct type.
+
+ Integers and floating point values are converted using Boost's
+ lexical_cast. It will accept integer values such as "41" or "-42". It will
+ accept floating point numbers such as "51.1", "-52.1", "53.1234567890" (as
+ a double), "54", "55.", ".56", "57.1e5", "58.1E5", ".591e5", "60.1e-5",
+ "-61.1e5", "-62.1e-5", etc. Unfortunately, hex, octal, and binary
+ representations that are available in C++ literals are not supported by
+ lexical_cast, and thus will not work with program_options.
+
+ Booleans a special in that there are multiple ways to come at them.
+ Similar to another value type, it can be specified as ("my-option",
+ value()), and then set as:
+
+example --my-option=true
+
+ However, more typical is that boolean values are set by the simple
+ presence of a switch. This is enabled by &bool_switch; as in
+ ("other-option", bool_switch()). This will cause the value to
+ default to false and it will become true if the switch is found:
+
+example --other-switch
+
+ When a boolean does take a parameter, there are several options.
+ Those that evaluate to true in C++ are: "true", "yes", "on", "1". Those
+ that evaluate to false in C++ are: "false", "no", "off", "0". In addition,
+ when reading from a config file, the option name with an equal sign and no
+ value after it will also evaluate to true.
+
+
+
Annotated List of Symbols
The following table describes all the important symbols in the
@@ -649,4 +692,4 @@ gui.accessibility.visual_bell=yes
sgml-parent-document: ("program_options.xml" "section")
sgml-set-face: t
End:
--->
\ No newline at end of file
+-->
diff --git a/doc/tutorial.xml b/doc/tutorial.xml
index d3e447a31..b9375766b 100644
--- a/doc/tutorial.xml
+++ b/doc/tutorial.xml
@@ -208,9 +208,9 @@ Allowed options:
--input-file arg : input file
$ bin/gcc/debug/options_description
Optimization level is 10
-$ bin/gcc/debug/options_description --optimization 4 -I foo a.cpp
-Include paths are: foo
-Input files are: a.cpp
+$ bin/gcc/debug/options_description --optimization 4 -I foo -I another/path --include-path third/include/path a.cpp b.cpp
+Include paths are: foo another/path third/include/path
+Input files are: a.cpp b.cpp
Optimization level is 4
@@ -350,4 +350,4 @@ Optimization level is 4
sgml-parent-document: ("program_options.xml" "section")
sgml-set-face: t
End:
--->
\ No newline at end of file
+-->
diff --git a/example/Jamfile.v2 b/example/Jamfile.v2
index d669d3e1b..8bd9d51bf 100644
--- a/example/Jamfile.v2
+++ b/example/Jamfile.v2
@@ -12,3 +12,7 @@ exe custom_syntax : custom_syntax.cpp ;
exe real : real.cpp ;
exe regex : regex.cpp /boost/regex//boost_regex ;
+
+exe config_file_types : config_file_types.cpp ;
+exe env_options : env_options.cpp ;
+exe options_heirarchy : options_heirarchy.cpp ;
diff --git a/example/config_file_types.cpp b/example/config_file_types.cpp
new file mode 100644
index 000000000..e466e94a1
--- /dev/null
+++ b/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
+namespace po = boost::program_options;
+
+#include
+#include
+#include
+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())
+
+ ("strings.word", po::value())
+ ("strings.phrase", po::value())
+ ("strings.quoted", po::value())
+
+ ("ints.positive", po::value())
+ ("ints.negative", po::value())
+ ("ints.hex", po::value())
+ ("ints.oct", po::value())
+ ("ints.bin", po::value())
+
+ ("floats.positive", po::value())
+ ("floats.negative", po::value())
+ ("floats.double", po::value())
+ ("floats.int", po::value())
+ ("floats.int_dot", po::value())
+ ("floats.dot", po::value())
+ ("floats.exp_lower", po::value())
+ ("floats.exp_upper", po::value())
+ ("floats.exp_decimal", po::value())
+ ("floats.exp_negative", po::value())
+ ("floats.exp_negative_val", po::value())
+ ("floats.exp_negative_negative_val", po::value())
+
+ // Load booleans as value, so they will require a --option=value on the command line
+ //("booleans.number_true", po::value())
+ //("booleans.number_false", po::value())
+ //("booleans.yn_true", po::value())
+ //("booleans.yn_false", po::value())
+ //("booleans.tf_true", po::value())
+ //("booleans.tf_false", po::value())
+ //("booleans.onoff_true", po::value())
+ //("booleans.onoff_false", po::value())
+ //("booleans.present_equal_true", po::value())
+ //("booleans.present_no_equal_true", po::value())
+
+ // 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 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 unregistered = po::collect_unrecognized(parsed.options, po::exclude_positional);
+ notify(vm);
+
+ return unregistered;
+}
+
+void check_results(po::variables_map &vm, vector 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() == expected_global_string);
+
+ assert(unregistered[0] == expected_unreg_option);
+ assert(unregistered[1] == expected_unreg_value);
+
+ assert(vm["strings.word"].as() == expected_strings_word);
+ assert(vm["strings.phrase"].as() == expected_strings_phrase);
+ assert(vm["strings.quoted"].as() == expected_strings_quoted);
+
+ assert(vm["ints.positive"].as() == expected_int_postitive);
+ assert(vm["ints.negative"].as() == expected_int_negative);
+ //assert(vm["ints.hex"].as() == expected_int_hex);
+ //assert(vm["ints.oct"].as() == expected_int_oct);
+ //assert(vm["ints.bin"].as() == expected_int_bin);
+
+ assert(check_float(vm["floats.positive"].as(), expected_float_positive));
+ assert(check_float(vm["floats.negative"].as(), expected_float_negative));
+ assert(check_float(vm["floats.double"].as(), expected_float_double));
+ assert(check_float(vm["floats.int"].as(), expected_float_int));
+ assert(check_float(vm["floats.int_dot"].as(), expected_float_int_dot));
+ assert(check_float(vm["floats.dot"].as(), expected_float_dot));
+ assert(check_float(vm["floats.exp_lower"].as(), expected_float_exp_lower));
+ assert(check_float(vm["floats.exp_upper"].as(), expected_float_exp_upper));
+ assert(check_float(vm["floats.exp_decimal"].as(), expected_float_exp_decimal));
+ assert(check_float(vm["floats.exp_negative"].as(), expected_float_exp_negative));
+ assert(check_float(vm["floats.exp_negative_val"].as(), expected_float_exp_negative_val));
+ assert(check_float(vm["floats.exp_negative_negative_val"].as(), expected_float_exp_negative_negative_val));
+
+ assert(vm["booleans.number_true"].as() == expected_number_true);
+ assert(vm["booleans.number_false"].as() == expected_number_false);
+ assert(vm["booleans.yn_true"].as() == expected_yn_true);
+ assert(vm["booleans.yn_false"].as() == expected_yn_false);
+ assert(vm["booleans.tf_true"].as() == expected_tf_true);
+ assert(vm["booleans.tf_false"].as() == expected_tf_false);
+ assert(vm["booleans.onoff_true"].as() == expected_onoff_true);
+ assert(vm["booleans.onoff_false"].as() == expected_onoff_false);
+ assert(vm["booleans.present_equal_true"].as() == expected_present_equal_true);
+ //assert(vm["booleans.present_no_equal_true"].as() == 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/example/env_options.cpp b/example/env_options.cpp
new file mode 100644
index 000000000..bab37e252
--- /dev/null
+++ b/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
+namespace po = boost::program_options;
+#include
+#include
+
+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()->default_value("INFO"), "set verbosity: DEBUG, INFO, WARN, ERROR, FATAL")
+ ;
+
+ po::variables_map vm;
+ store(po::parse_environment(config, boost::function1(mapper)), vm);
+ notify(vm);
+
+ if (vm.count("path"))
+ {
+ std::cout << "First 75 chars of the system path: \n";
+ std::cout << vm["path"].as().substr(0, 75) << std::endl;
+ }
+
+ std::cout << "Verbosity: " << vm["verbosity"].as() << std::endl;
+}
+
+int main(int ac, char* av[])
+{
+ get_env_options();
+
+ return 0;
+}
diff --git a/example/options_heirarchy.cpp b/example/options_heirarchy.cpp
new file mode 100644
index 000000000..c913b149e
--- /dev/null
+++ b/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
+namespace po = boost::program_options;
+#include
+#include
+#include