diff --git a/.travis.yml b/.travis.yml
index 651835a..d906b49 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -114,21 +114,6 @@ jobs:
script:
- libs/$SELF/ci/cppcheck.sh
- - os: linux
- env:
- - COMMENT=UBSAN
- - B2_VARIANT=variant=debug
- - TOOLSET=gcc-7
- - CXXFLAGS="cxxflags=-fno-omit-frame-pointer cxxflags=-fsanitize=undefined cxxflags=-fno-sanitize-recover=undefined"
- - LINKFLAGS="linkflags=-fsanitize=undefined linkflags=-fno-sanitize-recover=undefined"
- - UBSAN_OPTIONS=print_stacktrace=1
- addons:
- apt:
- packages:
- - g++-7
- sources:
- - ubuntu-toolchain-r-test
-
- os: linux
env:
- COMMENT=CodeCov
@@ -154,17 +139,6 @@ jobs:
# - CXXSTD=03,11
#################### Jobs to run on pushes to master, develop ###################
-
- # Coverity Scan
- - os: linux
- if: (branch IN (develop, master)) AND (type IN (cron, push))
- env:
- - COMMENT="Coverity Scan"
- - TOOLSET=gcc
- script:
- - echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-
- - cd libs/$SELF
- - ci/coverity.sh
notifications:
email:
diff --git a/README.md b/README.md
index 9c21fd2..b2bd595 100644
--- a/README.md
+++ b/README.md
@@ -12,10 +12,10 @@ Distributed under the [Boost Software License, Version 1.0](http://www.boost.org
### Build Status
(in progress...)
-|Branch | Travis | Appveyor | Coverity Scan | codecov.io | Deps | Docs | Tests |
-|:-------------: | ------ | -------- | ------------- | ---------- | ---- | ---- | ----- |
-|[`master`](https://github.com/boostorg/program_options/tree/master) | [](https://travis-ci.org/boostorg/program_options) | [](https://ci.appveyor.com/project/jeking3/date-time-1evbf) | [](https://scan.coverity.com/projects/boostorg-program_options) | [](https://codecov.io/gh/boostorg/program_options/branch/master) | [](https://pdimov.github.io/boostdep-report/master/program_options.html) | [](http://www.boost.org/doc/libs/master/doc/html/program_options.html) | [](http://www.boost.org/development/tests/master/developer/program_options.html)
-|[`develop`](https://github.com/boostorg/program_options/tree/develop) | [](https://travis-ci.org/boostorg/program_options) | [](https://ci.appveyor.com/project/vprus/program-options/branch/develop) | [](https://scan.coverity.com/projects/boostorg-program_options) | [](https://codecov.io/gh/boostorg/program_options/branch/develop) | [](https://pdimov.github.io/boostdep-report/develop/program_options.html) | [](http://www.boost.org/doc/libs/develop/doc/html/program_options.html) | [](http://www.boost.org/development/tests/develop/developer/program_options.html)
+|Branch | Travis | Appveyor | codecov.io | Deps | Docs | Tests |
+|:-------------: | ------ | -------- | ---------- | ---- | ---- | ----- |
+|[`master`](https://github.com/boostorg/program_options/tree/master) | [](https://travis-ci.org/boostorg/program_options) | [](https://ci.appveyor.com/project/vprus/program-options/branch/master) | [](https://codecov.io/gh/boostorg/program_options/branch/master) | [](https://pdimov.github.io/boostdep-report/master/program_options.html) | [](http://www.boost.org/doc/libs/master/doc/html/program_options.html) | [](http://www.boost.org/development/tests/master/developer/program_options.html)
+|[`develop`](https://github.com/boostorg/program_options/tree/develop) | [](https://travis-ci.org/boostorg/program_options) | [](https://ci.appveyor.com/project/vprus/program-options/branch/develop) | [](https://codecov.io/gh/boostorg/program_options/branch/develop) | [](https://pdimov.github.io/boostdep-report/develop/program_options.html) | [](http://www.boost.org/doc/libs/develop/doc/html/program_options.html) | [](http://www.boost.org/development/tests/develop/developer/program_options.html)
### Directories
@@ -34,4 +34,4 @@ Distributed under the [Boost Software License, Version 1.0](http://www.boost.org
* [Ask questions](http://stackoverflow.com/questions/ask?tags=c%2B%2B,boost,boost-program_options): Be sure to read the documentation first to see if it answers your question.
* [Report bugs](https://github.com/boostorg/program_options/issues): Be sure to mention Boost version, platform and compiler you're using. A small compilable code sample to reproduce the problem is always good as well.
* [Submit Pull Requests](https://github.com/boostorg/program_options/pulls) against the **develop** branch. Note that by submitting patches you agree to license your modifications under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt). Be sure to include tests proving your changes work properly.
-* Discussions about the library are held on the [Boost developers mailing list](http://www.boost.org/community/groups.html#main). Be sure to read the [discussion policy](http://www.boost.org/community/policy.html) before posting and add the `[date_time]` tag at the beginning of the subject line.
+* Discussions about the library are held on the [Boost developers mailing list](http://www.boost.org/community/groups.html#main). Be sure to read the [discussion policy](http://www.boost.org/community/policy.html) before posting and add the `[program_options]` tag at the beginning of the subject line.
diff --git a/doc/overview.xml b/doc/overview.xml
index f7de296..52fe9b9 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,12 +565,49 @@ 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<bool>()), 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
@@ -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/program_options.ent b/doc/program_options.ent
index 084f605..cd6504b 100644
--- a/doc/program_options.ent
+++ b/doc/program_options.ent
@@ -44,3 +44,5 @@
basic_option">
+bool_switch">
diff --git a/doc/tutorial.xml b/doc/tutorial.xml
index d3e447a..b937576 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 d669d3e..9f0b1d8 100644
--- a/example/Jamfile.v2
+++ b/example/Jamfile.v2
@@ -12,3 +12,10 @@ 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/example/config_file_types.cpp b/example/config_file_types.cpp
new file mode 100644
index 0000000..e466e94
--- /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 0000000..bab37e2
--- /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 0000000..c913b14
--- /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