mirror of
https://github.com/boostorg/program_options.git
synced 2026-01-20 04:42:24 +00:00
Compare commits
64 Commits
pr/bcp-nam
...
boost-1.57
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d7c987526 | ||
|
|
0a7005d7c6 | ||
|
|
fb4f36f3ee | ||
|
|
2ceb54f9a2 | ||
|
|
e8e538036d | ||
|
|
f271e1ffce | ||
|
|
63e8f1c954 | ||
|
|
43e53664f2 | ||
|
|
cddd2c593f | ||
|
|
c054a3b034 | ||
|
|
cf09cfde1f | ||
|
|
ec3192a6c8 | ||
|
|
abd32c88fc | ||
|
|
0c04bde7e0 | ||
|
|
cd1b58aac2 | ||
|
|
310a638dc8 | ||
|
|
cbacc90d8f | ||
|
|
ab9901f553 | ||
|
|
5820ee9f7f | ||
|
|
67ba23b8d9 | ||
|
|
c3cb7cf05d | ||
|
|
bdbd3dfc42 | ||
|
|
15c990b7af | ||
|
|
1a884cef74 | ||
|
|
3c6401b19a | ||
|
|
ed4847e0a7 | ||
|
|
6eef67f5ba | ||
|
|
91d9cabb51 | ||
|
|
22e8d11888 | ||
|
|
b55001a061 | ||
|
|
2a16575f98 | ||
|
|
f14a369077 | ||
|
|
9df5124fed | ||
|
|
86487c7b63 | ||
|
|
6cd68a2fd9 | ||
|
|
f0eae2ccfe | ||
|
|
b2a01d9405 | ||
|
|
2d0c627d34 | ||
|
|
2cc29f6dfa | ||
|
|
198b29d107 | ||
|
|
f407b6ce47 | ||
|
|
87938cfa8e | ||
|
|
9a73a1c412 | ||
|
|
37143a449d | ||
|
|
2e0e9fd30b | ||
|
|
1bd588d677 | ||
|
|
d83e0dea37 | ||
|
|
54daca4c09 | ||
|
|
f4eac99310 | ||
|
|
a367a1b021 | ||
|
|
720d0455dd | ||
|
|
aad1a60172 | ||
|
|
1e4d1dee3d | ||
|
|
e718d0a8a5 | ||
|
|
ab30ec28eb | ||
|
|
682f1b7670 | ||
|
|
43577d0ca8 | ||
|
|
d05b400b13 | ||
|
|
4863727509 | ||
|
|
7d90a1b1b2 | ||
|
|
ac9830625b | ||
|
|
252a3f9ebd | ||
|
|
b1dc87da3c | ||
|
|
1fbf955272 |
@@ -1,3 +0,0 @@
|
||||
fixes:
|
||||
- home/travis/build/*/boost-root/boost/::include/boost/
|
||||
- home/travis/build/*/boost-root/libs/*/src/::src/
|
||||
146
.travis.yml
146
.travis.yml
@@ -1,146 +0,0 @@
|
||||
# Copyright 2016 Peter Dimov
|
||||
# Copyright 2017, 2018 James E. King III
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#
|
||||
# Generic Travis CI build script for boostorg repositories
|
||||
#
|
||||
# Instructions for customizing this script for your library:
|
||||
#
|
||||
# 1. Copy the ci/ directory from the same source into your project:
|
||||
# ci/build.sh runs the build
|
||||
# ci/codecov.sh is used to run a profiling build and upload results to codecov.io
|
||||
# ci/coverity.sh is used to run a coverity build and upload results coverity scan
|
||||
# 2. Customize the compilers and language levels you want. Default is C++03.
|
||||
# 3. Update the global B2 environment settings to your liking.
|
||||
# 4. If you have more than include/, src/, and test/ directories then
|
||||
# add them to the depinst.py line as "--include tools" for tools/ (you
|
||||
# can put multiple --include on the command line).
|
||||
# 5. If you want to enable Coverity Scan, you need to provide the environment
|
||||
# variables COVERITY_SCAN_TOKEN and COVERITY_SCAN_NOTIFICATION_EMAIL in
|
||||
# your github settings.
|
||||
# 6. Enable pull request builds in your boostorg/<library> account.
|
||||
# 7. Change the default C++ version in ci/*.sh (search for CXXSTD)
|
||||
#
|
||||
# That's it - the scripts will do everything else for you.
|
||||
|
||||
sudo: false
|
||||
dist: trusty
|
||||
language: cpp
|
||||
|
||||
env:
|
||||
global:
|
||||
# see: http://www.boost.org/build/doc/html/bbv2/overview/invocation.html#bbv2.overview.invocation.properties
|
||||
# to use the default for a given environment, comment it out; recommend you build debug and release however..
|
||||
# - B2_ADDRESS_MODEL=address-model=64,32
|
||||
# - B2_LINK=link=shared,static
|
||||
# - B2_THREADING=threading=multi,single
|
||||
- B2_VARIANT=variant=release,debug
|
||||
|
||||
install:
|
||||
- export SELF=`basename $TRAVIS_BUILD_DIR`
|
||||
- cd ..
|
||||
- git clone -b $TRAVIS_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
- cd boost-root
|
||||
- git submodule update -q --init tools/boostdep
|
||||
- git submodule update -q --init tools/build
|
||||
- git submodule update -q --init tools/inspect
|
||||
- cp -r $TRAVIS_BUILD_DIR/* libs/$SELF
|
||||
- export BOOST_ROOT="`pwd`"
|
||||
- export PATH="`pwd`":$PATH
|
||||
- python tools/boostdep/depinst/depinst.py $SELF --include example
|
||||
- ./bootstrap.sh
|
||||
- ./b2 headers
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- binutils-gold
|
||||
- gdb
|
||||
- libc6-dbg
|
||||
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- master
|
||||
|
||||
script:
|
||||
- cd libs/$SELF
|
||||
- ci/build.sh
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- os: linux
|
||||
env:
|
||||
- COMMENT="C++03"
|
||||
- TOOLSET=gcc,gcc-7
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-7
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- os: linux
|
||||
env:
|
||||
- COMMENT="C++11"
|
||||
- TOOLSET=clang
|
||||
- CXXSTD=11
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-7
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- os: linux
|
||||
env:
|
||||
- COMMENT=valgrind
|
||||
- TOOLSET=clang
|
||||
- B2_VARIANT=variant=debug
|
||||
- TESTFLAGS=testing.launcher=valgrind
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-5.0
|
||||
- libstdc++-7-dev
|
||||
- valgrind
|
||||
sources:
|
||||
- llvm-toolchain-trusty-5.0
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
- os: linux
|
||||
env:
|
||||
- COMMENT=cppcheck
|
||||
script:
|
||||
- libs/$SELF/ci/cppcheck.sh
|
||||
|
||||
- os: linux
|
||||
env:
|
||||
- COMMENT=CodeCov
|
||||
- TOOLSET=gcc-7
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-7
|
||||
- g++-7
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
script:
|
||||
- pushd /tmp && git clone https://github.com/linux-test-project/lcov.git && cd lcov && sudo make install && which lcov && lcov --version && popd
|
||||
- cd libs/$SELF
|
||||
- ci/codecov.sh
|
||||
|
||||
#################### Jobs to run on every pull request ####################
|
||||
# osx was disabled because it is very slow to start (can delay builds by 30 minutes)
|
||||
# - os: osx
|
||||
# osx_image: xcode9
|
||||
# env:
|
||||
# - TOOLSET=clang
|
||||
# - CXXSTD=03,11
|
||||
|
||||
#################### Jobs to run on pushes to master, develop ###################
|
||||
|
||||
notifications:
|
||||
email:
|
||||
false
|
||||
|
||||
11
Jamfile
11
Jamfile
@@ -1,11 +0,0 @@
|
||||
# Boost.ProgramOptions Library Jamfile
|
||||
#
|
||||
# Copyright (c) 2018 James E. King III
|
||||
#
|
||||
# Use, modification, and distribution are subject to 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)
|
||||
|
||||
# please order by name to ease maintenance
|
||||
build-project example ;
|
||||
build-project test ;
|
||||
37
README.md
37
README.md
@@ -1,37 +0,0 @@
|
||||
Program Options, part of the collection of [Boost C++ Libraries](http://github.com/boostorg), allows for definition and acquisition of (name, value) pairs from the user via conventional methods such as command line and config file. It is roughly analogous to getopt_long, but for use with C++.
|
||||
|
||||
### License
|
||||
|
||||
Distributed under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt).
|
||||
|
||||
### Properties
|
||||
|
||||
* C++03
|
||||
* Requires Linking
|
||||
|
||||
### Build Status
|
||||
(in progress...)
|
||||
|
||||
|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
|
||||
|
||||
| Name | Purpose |
|
||||
| --------- | ------------------------------ |
|
||||
| `build` | build script for link library |
|
||||
| `ci` | continuous integration scripts |
|
||||
| `doc` | documentation |
|
||||
| `example` | use case examples |
|
||||
| `include` | headers |
|
||||
| `src` | source code for link library |
|
||||
| `test` | unit tests |
|
||||
|
||||
### More information
|
||||
|
||||
* [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 `[program_options]` tag at the beginning of the subject line.
|
||||
78
appveyor.yml
78
appveyor.yml
@@ -1,78 +0,0 @@
|
||||
# Copyright 2016, 2017 Peter Dimov
|
||||
# Copyright (C) 2017, 2018 James E. King III
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# When copying this to a new library, be sure to update the name of the library
|
||||
# in two places (once each at the top of install: and test_script:)
|
||||
|
||||
version: 1.0.{build}-{branch}
|
||||
|
||||
shallow_clone: true
|
||||
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- master
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- MAYFAIL: true
|
||||
|
||||
environment:
|
||||
global:
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
# see: http://www.boost.org/build/doc/html/bbv2/overview/invocation.html#bbv2.overview.invocation.properties
|
||||
# to use the default for a given environment, comment it out; recommend you build debug and release however..
|
||||
# on Windows it is important to exercise all the possibilities, especially shared vs static
|
||||
# B2_ADDRESS_MODEL: address-model=64,32
|
||||
# B2_LINK: link=shared,static
|
||||
# B2_THREADING: threading=multi,single
|
||||
B2_VARIANT: variant=release,debug
|
||||
CXXSTD: 03
|
||||
|
||||
matrix:
|
||||
- FLAVOR: Visual Studio 2017
|
||||
TOOLSET: msvc-14.1
|
||||
B2_ADDRESS_MODEL: address-model=64,32
|
||||
- FLAVOR: Visual Studio 2013
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
|
||||
TOOLSET: msvc-12.0
|
||||
- FLAVOR: mingw32
|
||||
ARCH: i686
|
||||
B2_ADDRESS_MODEL: address-model=32
|
||||
SCRIPT: ci\mingw.bat
|
||||
- FLAVOR: mingw64
|
||||
ARCH: x86_64
|
||||
B2_ADDRESS_MODEL: address-model=64
|
||||
SCRIPT: ci\mingw.bat
|
||||
- FLAVOR: cygwin (64-bit)
|
||||
ADDPATH: C:\cygwin64\bin;
|
||||
B2_ADDRESS_MODEL: address-model=64
|
||||
TOOLSET: gcc
|
||||
MAYFAIL: true
|
||||
- FLAVOR: cygwin (32-bit)
|
||||
ADDPATH: C:\cygwin\bin;
|
||||
B2_ADDRESS_MODEL: address-model=32
|
||||
TOOLSET: gcc
|
||||
MAYFAIL: true
|
||||
|
||||
install:
|
||||
- set SELF=program_options
|
||||
- cd ..
|
||||
- git clone -b %APPVEYOR_REPO_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
- cd boost-root
|
||||
- git submodule update -q --init tools/boostdep
|
||||
- git submodule update -q --init tools/build
|
||||
- git submodule update -q --init tools/inspect
|
||||
- xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\%SELF%
|
||||
- python tools/boostdep/depinst/depinst.py --include example %SELF%
|
||||
- cmd /c bootstrap
|
||||
- b2 headers
|
||||
|
||||
build: off
|
||||
|
||||
test_script:
|
||||
- set SELF=program_options
|
||||
- PATH=%ADDPATH%%PATH%
|
||||
- IF DEFINED SCRIPT (call libs\%SELF%\%SCRIPT%) ELSE (b2 libs/%SELF% toolset=%TOOLSET% cxxstd=%CXXSTD% %CXXFLAGS% %DEFINES% %B2_ADDRESS_MODEL% %B2_LINK% %B2_THREADING% %B2_VARIANT% -j3)
|
||||
@@ -9,8 +9,13 @@ SOURCES =
|
||||
convert winmain split
|
||||
;
|
||||
|
||||
boost-lib program_options
|
||||
lib boost_program_options
|
||||
: $(SOURCES).cpp
|
||||
: # See https://svn.boost.org/trac/boost/ticket/5049
|
||||
: <link>shared:<define>BOOST_PROGRAM_OPTIONS_DYN_LINK=1 # tell source we're building dll's
|
||||
# See https://svn.boost.org/trac/boost/ticket/5049
|
||||
<target-os>hpux,<toolset>gcc:<define>_INCLUDE_STDC__SOURCE_199901
|
||||
;
|
||||
:
|
||||
: <link>shared:<define>BOOST_PROGRAM_OPTIONS_DYN_LINK=1
|
||||
;
|
||||
|
||||
boost-install boost_program_options ;
|
||||
|
||||
19
ci/build.sh
19
ci/build.sh
@@ -1,19 +0,0 @@
|
||||
#! /bin/bash
|
||||
#
|
||||
# Copyright 2017 James E. King III
|
||||
# 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)
|
||||
#
|
||||
# Bash script to run in travis to perform a bjam build
|
||||
# cwd should be $BOOST_ROOT/libs/$SELF before running
|
||||
#
|
||||
|
||||
set -ex
|
||||
|
||||
# default language level: c++03
|
||||
if [[ -z "$CXXSTD" ]]; then
|
||||
CXXSTD=03
|
||||
fi
|
||||
|
||||
$BOOST_ROOT/b2 . toolset=$TOOLSET cxxstd=$CXXSTD $CXXFLAGS $DEFINES $LINKFLAGS $TESTFLAGS $B2_ADDRESS_MODEL $B2_LINK $B2_THREADING $B2_VARIANT -j3 $*
|
||||
@@ -1,43 +0,0 @@
|
||||
#! /bin/bash
|
||||
#
|
||||
# Copyright 2017, 2018 James E. King III
|
||||
# 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)
|
||||
#
|
||||
# Bash script to run in travis to perform codecov.io integration
|
||||
#
|
||||
|
||||
###
|
||||
### NOTE: Make sure you grab .codecov.yml
|
||||
###
|
||||
|
||||
# assumes cwd is the top level directory of the boost project
|
||||
# assumes an environment variable $SELF is the boost project name
|
||||
|
||||
set -ex
|
||||
|
||||
B2_VARIANT=debug
|
||||
ci/build.sh cxxflags=-fprofile-arcs cxxflags=-ftest-coverage linkflags=-fprofile-arcs linkflags=-ftest-coverage
|
||||
|
||||
# switch back to the original source code directory
|
||||
cd $TRAVIS_BUILD_DIR
|
||||
|
||||
# get the version of lcov
|
||||
lcov --version
|
||||
|
||||
# coverage files are in ../../b2 from this location
|
||||
lcov --gcov-tool=gcov-7 --rc lcov_branch_coverage=1 --base-directory "$BOOST_ROOT/libs/$SELF" --directory "$BOOST_ROOT" --capture --output-file all.info
|
||||
|
||||
# all.info contains all the coverage info for all projects - limit to ours
|
||||
lcov --gcov-tool=gcov-7 --rc lcov_branch_coverage=1 --extract all.info "*/boost/$SELF/*" "*/libs/$SELF/src/*" --output-file coverage.info
|
||||
|
||||
# dump a summary on the console - helps us identify problems in pathing
|
||||
lcov --gcov-tool=gcov-7 --rc lcov_branch_coverage=1 --list coverage.info
|
||||
|
||||
#
|
||||
# upload to codecov.io
|
||||
#
|
||||
curl -s https://codecov.io/bash > .codecov
|
||||
chmod +x .codecov
|
||||
./.codecov -f coverage.info -X gcov -x "gcov-7"
|
||||
@@ -1,42 +0,0 @@
|
||||
#! /bin/bash
|
||||
#
|
||||
# Copyright 2017 James E. King III
|
||||
# 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)
|
||||
#
|
||||
# Bash script to run in travis to perform a Coverity Scan build
|
||||
# To skip the coverity integration download (which is huge) if
|
||||
# you already have it from a previous run, add --skipdownload
|
||||
#
|
||||
|
||||
#
|
||||
# Environment Variables
|
||||
#
|
||||
# COVERITY_SCAN_NOTIFICATION_EMAIL - email address to notify
|
||||
# COVERITY_SCAN_TOKEN - the Coverity Scan token (should be secure)
|
||||
# SELF - the boost libs directory name
|
||||
|
||||
set -ex
|
||||
|
||||
pushd /tmp
|
||||
if [[ "$1" != "--skipdownload" ]]; then
|
||||
rm -rf coverity_tool.tgz cov-analysis*
|
||||
wget https://scan.coverity.com/download/linux64 --post-data "token=$COVERITY_SCAN_TOKEN&project=boostorg/$SELF" -O coverity_tool.tgz
|
||||
tar xzf coverity_tool.tgz
|
||||
fi
|
||||
COVBIN=$(echo $(pwd)/cov-analysis*/bin)
|
||||
export PATH=$COVBIN:$PATH
|
||||
popd
|
||||
|
||||
ci/build.sh clean
|
||||
rm -rf cov-int/
|
||||
cov-build --dir cov-int ci/build.sh
|
||||
tar cJf cov-int.tar.xz cov-int/
|
||||
curl --form token="$COVERITY_SCAN_TOKEN" \
|
||||
--form email="$COVERITY_SCAN_NOTIFICATION_EMAIL" \
|
||||
--form file=@cov-int.tar.xz \
|
||||
--form version="$(git describe --tags)" \
|
||||
--form description="boostorg/$SELF" \
|
||||
https://scan.coverity.com/builds?project="boostorg/$SELF"
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
#! /bin/bash
|
||||
#
|
||||
# Copyright 2018 James E. King III
|
||||
# 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)
|
||||
#
|
||||
# Bash script to run in travis to perform a cppcheck
|
||||
# cwd should be $BOOST_ROOT before running
|
||||
#
|
||||
|
||||
set -ex
|
||||
|
||||
# default language level: c++03
|
||||
if [[ -z "$CXXSTD" ]]; then
|
||||
CXXSTD=03
|
||||
fi
|
||||
|
||||
# Travis' ubuntu-trusty comes with cppcheck 1.62 which is pretty old
|
||||
# default cppcheck version: 1.82
|
||||
if [[ -z "$CPPCHKVER" ]]; then
|
||||
CPPCHKVER=1.82
|
||||
fi
|
||||
|
||||
pushd ~
|
||||
wget https://github.com/danmar/cppcheck/archive/$CPPCHKVER.tar.gz
|
||||
tar xzf $CPPCHKVER.tar.gz
|
||||
mkdir cppcheck-build
|
||||
cd cppcheck-build
|
||||
cmake ../cppcheck-$CPPCHKVER -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX=~/cppcheck
|
||||
make -j3 install
|
||||
popd
|
||||
|
||||
~/cppcheck/bin/cppcheck -I. --std=c++$CXXSTD --enable=all --error-exitcode=1 \
|
||||
--force --check-config --suppress=*:boost/preprocessor/tuple/size.hpp \
|
||||
-UBOOST_USER_CONFIG -UBOOST_COMPILER_CONFIG -UBOOST_STDLIB_CONFIG -UBOOST_PLATFORM_CONFIG \
|
||||
libs/$SELF 2>&1 | grep -v 'Cppcheck does not need standard library headers'
|
||||
|
||||
50
ci/mingw.bat
50
ci/mingw.bat
@@ -1,50 +0,0 @@
|
||||
::
|
||||
:: MinGW Build Script for Appveyor, leveraging the MSYS2 installation
|
||||
:: Copyright (C) 2018 James E. King III
|
||||
:: Distributed under the Boost Software License, Version 1.0.
|
||||
:: (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
::
|
||||
|
||||
@ECHO ON
|
||||
SETLOCAL EnableDelayedExpansion
|
||||
|
||||
:: Set up the toolset
|
||||
echo using gcc : %FLAVOR% : %ARCH%-w64-mingw32-g++.exe ; > %USERPROFILE%\user-config.jam
|
||||
SET UPPERFLAVOR=%FLAVOR%
|
||||
CALL :TOUPPER UPPERFLAVOR
|
||||
|
||||
:: Install packages needed to build boost
|
||||
:: Optional: comment out ones this library does not need,
|
||||
:: so people can copy this script to another library.
|
||||
|
||||
FOR %%a IN ("gcc" "icu" "libiconv" "openssl" "xz" "zlib") DO (
|
||||
c:\msys64\usr\bin\env MSYSTEM=%UPPERFLAVOR% c:\msys64\usr\bin\bash -l -c ^
|
||||
"pacman --sync --needed --noconfirm %FLAVOR%/mingw-w64-%ARCH%-%%a" || EXIT /B
|
||||
)
|
||||
c:\msys64\usr\bin\env MSYSTEM=%UPPERFLAVOR% c:\msys64\usr\bin\bash -l -c ^
|
||||
"pacman --sync --needed --noconfirm python3" || EXIT /B
|
||||
|
||||
::
|
||||
:: Now build things...
|
||||
::
|
||||
|
||||
c:\msys64\usr\bin\env MSYSTEM=%UPPERFLAVOR% c:\msys64\usr\bin\bash -l -c ^
|
||||
"cd %CD:\=/% && ./bootstrap.sh --with-toolset=gcc" || EXIT /B
|
||||
|
||||
c:\msys64\usr\bin\env MSYSTEM=%UPPERFLAVOR% c:\msys64\usr\bin\bash -l -c ^
|
||||
"cd %CD:\=/% && ./b2 libs/%SELF% toolset=gcc-%FLAVOR% cxxstd=%CXXSTD% %CXXFLAGS% %DEFINES% %B2_ADDRESS_MODEL% %B2_LINK% %B2_THREADING% %B2_VARIANT% -j3" || EXIT /B
|
||||
|
||||
EXIT /B 0
|
||||
|
||||
::
|
||||
:: Function to uppercase a variable
|
||||
:: from: https://stackoverflow.com/questions/34713621/batch-converting-variable-to-uppercase
|
||||
::
|
||||
|
||||
:TOUPPER <variable>
|
||||
@ECHO OFF
|
||||
FOR %%a IN ("a=A" "b=B" "c=C" "d=D" "e=E" "f=F" "g=G" "h=H" "i=I"
|
||||
"j=J" "k=K" "l=L" "m=M" "n=N" "o=O" "p=P" "q=Q" "r=R"
|
||||
"s=S" "t=T" "u=U" "v=V" "w=W" "x=X" "y=Y" "z=Z" ) DO ( CALL SET %~1=%%%~1:%%~a%% )
|
||||
@ECHO ON
|
||||
GOTO :EOF
|
||||
@@ -10,14 +10,4 @@ boostbook program_option
|
||||
;
|
||||
|
||||
doxygen autodoc
|
||||
: [ glob ../../../boost/program_options/*.hpp ] ;
|
||||
|
||||
###############################################################################
|
||||
alias boostdoc
|
||||
: program_options.xml
|
||||
:
|
||||
: <dependency>autodoc
|
||||
: ;
|
||||
explicit boostdoc ;
|
||||
alias boostrelease ;
|
||||
explicit boostrelease ;
|
||||
: [ glob ../../../boost/program_options/*.hpp ] ;
|
||||
@@ -22,7 +22,7 @@
|
||||
not mean strict 7-bit ASCII encoding, but rather "char" strings in local
|
||||
8-bit encoding.
|
||||
</para>
|
||||
|
||||
|
||||
<para>
|
||||
Generally, "Unicode support" can mean
|
||||
many things, but for the program_options library it means that:
|
||||
@@ -54,7 +54,7 @@
|
||||
passed to an ascii value will be converted using a codecvt
|
||||
facet (which may be specified by the user).
|
||||
</para>
|
||||
</listitem>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</listitem>
|
||||
@@ -68,8 +68,8 @@
|
||||
Second, imagine a reusable library which has some options and exposes
|
||||
options description in its interface. If <emphasis>all</emphasis>
|
||||
options are either ascii or Unicode, and the library does not use any
|
||||
Unicode strings, then the author is likely to use ascii options, making
|
||||
the library unusable inside Unicode
|
||||
Unicode strings, then the author will likely to use ascii options, which
|
||||
would make the library unusable inside Unicode
|
||||
applications. Essentially, it would be necessary to provide two versions
|
||||
of the library -- ascii and Unicode.
|
||||
</para>
|
||||
@@ -94,7 +94,7 @@
|
||||
<para>The primary question in implementing the Unicode support is whether
|
||||
to use templates and <code>std::basic_string</code> or to use some
|
||||
internal encoding and convert between internal and external encodings on
|
||||
the interface boundaries.
|
||||
the interface boundaries.
|
||||
</para>
|
||||
|
||||
<para>The choice, mostly, is between code size and execution
|
||||
@@ -171,14 +171,14 @@
|
||||
number of new instantiations.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
|
||||
</itemizedlist>
|
||||
There's no clear leader, but the last point seems important, so UTF-8
|
||||
will be used.
|
||||
will be used.
|
||||
</para>
|
||||
|
||||
<para>Choosing the UTF-8 encoding allows the use of existing parsers,
|
||||
because 7-bit ascii characters retain their values in UTF-8,
|
||||
<para>Choosing the UTF-8 encoding allows the use of existing parsers,
|
||||
because 7-bit ascii characters retain their values in UTF-8,
|
||||
so searching for 7-bit strings is simple. However, there are
|
||||
two subtle issues:
|
||||
<itemizedlist>
|
||||
@@ -197,16 +197,16 @@
|
||||
almost universal encoding and since composing characters following '=' (and
|
||||
other characters with special meaning to the library) are not likely to appear.
|
||||
</para>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
<!--
|
||||
Local Variables:
|
||||
mode: xml
|
||||
sgml-indent-data: t
|
||||
sgml-indent-data: t
|
||||
sgml-parent-document: ("program_options.xml" "section")
|
||||
sgml-set-face: t
|
||||
End:
|
||||
|
||||
120
doc/howto.xml
120
doc/howto.xml
@@ -21,7 +21,7 @@ options groups/hidden options
|
||||
-->
|
||||
<section>
|
||||
<title>Non-conventional Syntax</title>
|
||||
|
||||
|
||||
<para>Sometimes, standard command line syntaxes are not enough. For
|
||||
example, the gcc compiler has "-frtti" and -fno-rtti" options, and this
|
||||
syntax is not directly supported.
|
||||
@@ -57,14 +57,14 @@ store(command_line_parser(ac, av).options(desc).extra_parser(reg_foo)
|
||||
.run(), vm);
|
||||
</programlisting>
|
||||
The complete example can be found in the "example/custom_syntax.cpp"
|
||||
file.
|
||||
file.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Response Files</title>
|
||||
|
||||
<indexterm><primary>response files</primary></indexterm>
|
||||
<indexterm><primary>response files</primary></indexterm>
|
||||
|
||||
<para>Some operating system have very low limits of the command line
|
||||
length. The common way to work around those limitations is using
|
||||
@@ -79,7 +79,7 @@ store(command_line_parser(ac, av).options(desc).extra_parser(reg_foo)
|
||||
<para>
|
||||
First, you need to define an option for the response file:
|
||||
<programlisting>
|
||||
("response-file", value<string>(),
|
||||
("response-file", value<string>(),
|
||||
"can be specified with '@name', too")
|
||||
</programlisting>
|
||||
</para>
|
||||
@@ -120,14 +120,14 @@ if (vm.count("response-file")) {
|
||||
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);
|
||||
store(command_line_parser(args).options(desc).run(), vm);
|
||||
}
|
||||
]]>
|
||||
</programlisting>
|
||||
The complete example can be found in the "example/response_file.cpp"
|
||||
file.
|
||||
file.
|
||||
</para>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -146,7 +146,7 @@ if (vm.count("response-file")) {
|
||||
<programlisting>
|
||||
vector<string> args = split_winmain(lpCmdLine);
|
||||
store(command_line_parser(args).options(desc).run(), vm);
|
||||
</programlisting>
|
||||
</programlisting>
|
||||
The <code>split_winmain</code> function is overloaded for <code>wchar_t</code> strings, so can
|
||||
also be used in Unicode applications.
|
||||
</para>
|
||||
@@ -223,7 +223,7 @@ visible.add(general).add(gui);
|
||||
variables_map vm;
|
||||
store(parse_command_line(ac, av, all), vm);
|
||||
|
||||
if (vm.count("help"))
|
||||
if (vm.count("help"))
|
||||
{
|
||||
cout << visible;
|
||||
return 0;
|
||||
@@ -235,7 +235,7 @@ if (vm.count("help-module")) {
|
||||
} else if (s == "backend") {
|
||||
cout << backend;
|
||||
} else {
|
||||
cout << "Unknown module '"
|
||||
cout << "Unknown module '"
|
||||
<< s << "' in the --help-module option\n";
|
||||
return 1;
|
||||
}
|
||||
@@ -243,8 +243,8 @@ if (vm.count("help-module")) {
|
||||
}
|
||||
if (vm.count("num-threads")) {
|
||||
cout << "The 'num-threads' options was set to "
|
||||
<< vm["num-threads"].as<int>() << "\n";
|
||||
}
|
||||
<< vm["num-threads"].as<int>() << "\n";
|
||||
}
|
||||
]]></programlisting>
|
||||
When parsing the command line, all options are allowed. The "--help"
|
||||
message, however, does not include the "Backend options" group -- the
|
||||
@@ -253,7 +253,7 @@ if (vm.count("num-threads")) {
|
||||
option. The complete example can be found in the
|
||||
"example/option_groups.cpp" file.
|
||||
</para>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -276,7 +276,7 @@ public:
|
||||
};
|
||||
]]></programlisting> and then overload the <code>validate</code> function:
|
||||
<programlisting><![CDATA[
|
||||
void validate(boost::any& v,
|
||||
void validate(boost::any& v,
|
||||
const std::vector<std::string>& values,
|
||||
magic_number* target_type, int)
|
||||
{
|
||||
@@ -290,16 +290,16 @@ void validate(boost::any& v,
|
||||
// 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
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
]]>
|
||||
]]>
|
||||
</programlisting>The function takes four parameters. The first is the storage
|
||||
for the value, and in this case is either empty or contains an instance of
|
||||
the <code>magic_number</code> class. The second is the list of strings
|
||||
@@ -372,7 +372,7 @@ void validate(boost::any& v,
|
||||
locale::global(locale(""));
|
||||
</programlisting>
|
||||
which would set up the conversion facet according to the user's selected
|
||||
locale.
|
||||
locale.
|
||||
</para>
|
||||
|
||||
<para>It's wise to check the status of the C++ locale support on your
|
||||
@@ -382,7 +382,7 @@ locale::global(locale(""));
|
||||
<para>Go the the "test" directory and build the "test_convert" binary.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Set some non-ascii locale in the environment. On Linux, one can
|
||||
<para>Set some non-ascii locale in the environmemt. On Linux, one can
|
||||
run, for example: <screen>
|
||||
$ export LC_CTYPE=ru_RU.KOI8-R
|
||||
</screen>
|
||||
@@ -402,89 +402,37 @@ $ export LC_CTYPE=ru_RU.KOI8-R
|
||||
<section>
|
||||
<title>Allowing Unknown Options</title>
|
||||
|
||||
<para>Usually, the library throws an exception on unknown option names. This
|
||||
behaviour can be changed. For example, only some part of your application uses
|
||||
<para>Usually, the library throws an exception on unknown option names. This
|
||||
behaviour can be changed. For example, only some part of your application uses
|
||||
<libraryname>Program_options</libraryname>, and you wish to pass unrecognized options to another part of
|
||||
the program, or even to another application.</para>
|
||||
|
||||
<para>To allow unregistered options on the command line, you need to use
|
||||
<para>To allow unregistered options on the command line, you need to use
|
||||
the &basic_command_line_parser; class for parsing (not &parse_command_line;)
|
||||
and call the <methodname alt="boost::program_options::basic_command_line_parser::allow_unregistered">allow_unregistered</methodname>
|
||||
and call the <methodname alt="boost::program_options::basic_command_line_parser::allow_unregistered">allow_unregistered</methodname>
|
||||
method of that class:
|
||||
<programlisting>
|
||||
parsed_options parsed =
|
||||
command_line_parser(argc, argv).options(desc).allow_unregistered().run();
|
||||
parsed_options parsed =
|
||||
command_line_parser(argc, argv).options(desc).allow_unregistered().run();
|
||||
</programlisting>
|
||||
|
||||
For each token that looks like an option, but does not have a known name,
|
||||
an instance of &basic_option; will be added to the result.
|
||||
The <code>string_key</code> and <code>value</code> fields of the instance will contain results
|
||||
|
||||
For each token that looks like an option, but does not have a known name,
|
||||
an instance of &basic_option; will be added to the result.
|
||||
The <code>string_key</code> and <code>value</code> fields of the instance will contain results
|
||||
of syntactic parsing of the token, the <code>unregistered</code> field will be set to <code>true</code>,
|
||||
and the <code>original_tokens</code> field will contain the token as it appeared on the command line.
|
||||
</para>
|
||||
|
||||
<para>If you want to pass the unrecognized options further, the
|
||||
<para>If you want to pass the unrecognized options further, the
|
||||
<functionname alt="boost::program_options::collect_unrecognized">collect_unrecognized</functionname> function can be used.
|
||||
The function will collect original tokens for all unrecognized values, and optionally, all found positional options.
|
||||
Say, if your code handles a few options, but does not handle positional options at all, you can use the function like this:
|
||||
Say, if your code handles a few options, but does not handles positional options at all, you can use the function like this:
|
||||
<programlisting>
|
||||
vector<string> to_pass_further = collect_unrecognized(parsed.options, include_positional);
|
||||
</programlisting>
|
||||
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Testing Option Presence</title>
|
||||
|
||||
<para>Until now we have tested whether an option has been set using the
|
||||
<methodname alt="boost::program_options::variables_map::count">count</methodname> method on the &variables_map;
|
||||
class; as you are repeating the (string literal) name of the option this is prone to typos and/or errors
|
||||
resulting from renaming the option in one place but not the other:
|
||||
<programlisting><![CDATA[
|
||||
po::options_description desc("Allowed options");
|
||||
desc.add_options()
|
||||
("compression", po::value<int>(), "set compression level")
|
||||
;
|
||||
|
||||
po::variables_map vm;
|
||||
po::store(po::parse_command_line(ac, av, desc), vm);
|
||||
po::notify(vm);
|
||||
|
||||
if (vm.count("compression")) {
|
||||
cout << "Compression level was set to "
|
||||
<< vm["compression"].as<int>() << ".\n";
|
||||
} else {
|
||||
cout << "Compression level was not set.\n";
|
||||
}
|
||||
]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>Instead, you can use a variable of type <classname alt="boost::optional">boost::optional</classname>;
|
||||
<libraryname>Program_options</libraryname> provides special support for <libraryname>Boost.Optional</libraryname>
|
||||
such that if the user specifies the option the <classname alt="boost::optional">boost::optional</classname>
|
||||
variable will be initialized to the appropriate value:
|
||||
<programlisting><![CDATA[
|
||||
po::options_description desc("Allowed options");
|
||||
boost::optional<int> compression;
|
||||
desc.add_options()
|
||||
("compression", po::value(&compression), "set compression level")
|
||||
;
|
||||
|
||||
po::variables_map vm;
|
||||
po::store(po::parse_command_line(ac, av, desc), vm);
|
||||
po::notify(vm);
|
||||
|
||||
if (compression) {
|
||||
cout << "Compression level was set to " << *compression << ".\n";
|
||||
} else {
|
||||
cout << "Compression level was not set.\n";
|
||||
}
|
||||
]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
157
doc/overview.xml
157
doc/overview.xml
@@ -22,7 +22,7 @@
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>The parsers component, which uses this information to find option names
|
||||
and values in the input sources and return them.
|
||||
and values in the input sources and return them.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
@@ -72,10 +72,10 @@
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>The storage component is focused on storing options values. It
|
||||
<para>The storage component is focused on storing options values. It
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
@@ -105,7 +105,7 @@ desc.add_options()
|
||||
("help", "produce help")
|
||||
("optimization", value<int>()->default_value(10), "optimization level")
|
||||
;
|
||||
</programlisting>
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>The call to the <code>value</code> function creates an instance of
|
||||
@@ -116,14 +116,14 @@ desc.add_options()
|
||||
essentially emulates named parameters of the constructor.) Calls to
|
||||
<code>operator()</code> on the object returned by <code>add_options</code>
|
||||
forward arguments to the constructor of the <code>option_description</code>
|
||||
class and add the new instance.
|
||||
class and add the new instance.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Note that in addition to the
|
||||
<code>value</code>, library provides the <code>bool_switch</code>
|
||||
function, and user can write his own function which will return
|
||||
other subclasses of <code>value_semantic</code> with
|
||||
other subclasses of <code>value_semantic</code> with
|
||||
different behaviour. For the remainder of this section, we'll talk only
|
||||
about the <code>value</code> function.
|
||||
</para>
|
||||
@@ -135,7 +135,7 @@ desc.add_options()
|
||||
where value is just a vector of strings
|
||||
(<code>std::vector<std::string></code>). The semantic layer
|
||||
is responsible for converting the value of the option into more usable C++
|
||||
types.
|
||||
types.
|
||||
</para>
|
||||
|
||||
<para>This separation is an important part of library design. The parsers
|
||||
@@ -153,7 +153,7 @@ desc.add_options()
|
||||
<classname>boost::program_options::options_description</classname> class
|
||||
and some methods of the
|
||||
<classname>boost::program_options::value_semantic</classname> class
|
||||
and includes:
|
||||
and includes:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
@@ -193,7 +193,7 @@ desc.add_options()
|
||||
span several tokens. For example, the following command line is OK:
|
||||
<screen>
|
||||
test --help --compression 10 --verbose --email beadle@mars beadle2@mars
|
||||
</screen>
|
||||
</screen>
|
||||
</para>
|
||||
|
||||
<section>
|
||||
@@ -208,18 +208,18 @@ desc.add_options()
|
||||
<para>The description string has one or more paragraphs, separated by
|
||||
the newline character ('\n'). When an option is output, the library
|
||||
will compute the indentation for options's description. Each of the
|
||||
paragraph is output as a separate line with that intentation. If
|
||||
paragraph is output as a separate line with that intentation. If
|
||||
a paragraph does not fit on one line it is spanned over multiple
|
||||
lines (which will have the same indentation).
|
||||
</para>
|
||||
|
||||
<para>You may specify additional indent for the first specified by
|
||||
inserting spaces at the beginning of a paragraph. For example:
|
||||
inserting spaces at the beginning of a paragraph. For example:
|
||||
<programlisting>
|
||||
options.add_options()
|
||||
("help", " A long help msg a long help msg a long help msg a long help
|
||||
msg a long help msg a long help msg a long help msg a long help msg ")
|
||||
;
|
||||
;
|
||||
</programlisting>
|
||||
will specify a four-space indent for the first line. The output will
|
||||
look like:
|
||||
@@ -230,14 +230,14 @@ msg a long help msg a long help msg a long help msg a long help msg ")
|
||||
help msg a long help msg
|
||||
a long help msg a long
|
||||
help msg
|
||||
|
||||
|
||||
</screen>
|
||||
</para>
|
||||
|
||||
<para>For the case where line is wrapped, you can want an additional
|
||||
indent for wrapped text. This can be done by
|
||||
inserting a tabulator character ('\t') at the desired position. For
|
||||
example:
|
||||
example:
|
||||
<programlisting>
|
||||
options.add_options()
|
||||
("well_formated", "As you can see this is a very well formatted
|
||||
@@ -249,7 +249,7 @@ bla bla bla bla bla bla bla bla bla bla bla\n"
|
||||
" Value2: \tdoes something else, bla bla bla bla
|
||||
bla bla bla bla bla bla bla bla bla bla bla\n\n"
|
||||
" This paragraph has a first line indent only,
|
||||
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla");
|
||||
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla");
|
||||
</programlisting>
|
||||
will produce:
|
||||
<screen>
|
||||
@@ -280,20 +280,20 @@ bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla");
|
||||
bla bla bla
|
||||
</screen>
|
||||
The tab character is removed before output. Only one tabulator per
|
||||
paragraph is allowed, otherwise an exception of type
|
||||
paragraph is allowed, otherwisee an exception of type
|
||||
program_options::error is thrown. Finally, the tabulator is ignored if
|
||||
it is not on the first line of the paragraph or is on the last
|
||||
it's is not on the first line of the paragraph or is on the last
|
||||
possible position of the first line.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<section>
|
||||
<title>Semantic Information</title>
|
||||
|
||||
<para>The semantic information is completely provided by the
|
||||
|
||||
<para>The semantic information is completely provided by the
|
||||
<classname>boost::program_options::value_semantic</classname> class. For
|
||||
example:
|
||||
<programlisting>
|
||||
@@ -303,18 +303,18 @@ desc.add_options()
|
||||
("email", value< vector<string> >()
|
||||
->composing()->notifier(&your_function), "email")
|
||||
;
|
||||
</programlisting>
|
||||
</programlisting>
|
||||
These declarations specify that default value of the first option is 10,
|
||||
that the second option can appear several times and all instances should
|
||||
be merged, and that after parsing is done, the library will call
|
||||
function <code>&your_function</code>, passing the value of the
|
||||
"email" option as argument.
|
||||
"email" option as argument.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
<section>
|
||||
<title>Positional Options</title>
|
||||
|
||||
|
||||
<para>Our definition of option as (name, value) pairs is simple and
|
||||
useful, but in one special case of the command line, there's a
|
||||
problem. A command line can include a <firstterm>positional option</firstterm>,
|
||||
@@ -324,7 +324,7 @@ desc.add_options()
|
||||
</screen>
|
||||
Here, the "/etc/passwd" element does not have any option name.
|
||||
</para>
|
||||
|
||||
|
||||
<para>One solution is to ask the user to extract positional options
|
||||
himself and process them as he likes. However, there's a nicer approach
|
||||
-- provide a method to automatically assign the names for positional
|
||||
@@ -334,7 +334,7 @@ desc.add_options()
|
||||
archiver --compression=9 --input-file=/etc/passwd
|
||||
</screen>
|
||||
</para>
|
||||
|
||||
|
||||
<para>The &positional_options_desc; class allows the command line
|
||||
parser to assign the names. The class specifies how many positional options
|
||||
are allowed, and for each allowed option, specifies the name. For example:
|
||||
@@ -343,7 +343,7 @@ positional_options_description pd; pd.add("input-file", 1);
|
||||
</programlisting> specifies that for exactly one, first, positional
|
||||
option the name will be "input-file".
|
||||
</para>
|
||||
|
||||
|
||||
<para>It's possible to specify that a number, or even all positional options, be
|
||||
given the same name.
|
||||
<programlisting>
|
||||
@@ -360,11 +360,11 @@ pd.add("output-file", 2).add("input-file", -1);
|
||||
an instance of the &options_description; class.</para>
|
||||
</warning>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<!-- Note that the classes are not modified during parsing -->
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -390,7 +390,7 @@ pd.add("output-file", 2).add("input-file", -1);
|
||||
The results of parsing are returned as an instance of the &parsed_options;
|
||||
class. Typically, that object is passed directly to the storage
|
||||
component. However, it also can be used directly, or undergo some additional
|
||||
processing.
|
||||
processing.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@@ -422,8 +422,8 @@ pd.add("output-file", 2).add("input-file", -1);
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
@@ -512,13 +512,7 @@ visual_bell=yes
|
||||
<screen>
|
||||
gui.accessibility.visual_bell=yes
|
||||
</screen>
|
||||
<para>When the option "gui.accessibility.visual_bell" has been added to the options</para>
|
||||
<programlisting>
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("gui.accessibility.visual_bell", value<string>(), "flash screen for bell")
|
||||
;
|
||||
</programlisting>
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -544,7 +538,7 @@ desc.add_options()
|
||||
what option names must correspond to it. To describe the second
|
||||
parameter we need to consider naming conventions for environment
|
||||
variables.</para>
|
||||
|
||||
|
||||
<para>If you have an option that should be specified via environment
|
||||
variable, you need make up the variable's name. To avoid name clashes,
|
||||
we suggest that you use a sufficiently unique prefix for environment
|
||||
@@ -557,82 +551,45 @@ desc.add_options()
|
||||
Say, if you pass <literal>BOOST_</literal> as the prefix, and there are
|
||||
two variables, <envar>CVSROOT</envar> and <envar>BOOST_PROXY</envar>, the
|
||||
first variable will be ignored, and the second one will be converted to
|
||||
option <literal>proxy</literal>.
|
||||
option <literal>proxy</literal>.
|
||||
</para>
|
||||
|
||||
|
||||
<para>The above logic is sufficient in many cases, but it is also
|
||||
possible to pass, as the second parameter of the &parse_environment;
|
||||
function, any function taking a <code>std::string</code> and returning
|
||||
<code>std::string</code>. 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. An example showing this
|
||||
method can be found in "example/env_options.cpp".
|
||||
empty string if the variable should be ignored.
|
||||
</para>
|
||||
|
||||
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Types</title>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>Booleans a special in that there are multiple ways to come at them.
|
||||
Similar to another value type, it can be specified as <code>("my-option",
|
||||
value<bool>())</code>, and then set as:</para>
|
||||
<screen>
|
||||
example --my-option=true
|
||||
</screen>
|
||||
<para>However, more typical is that boolean values are set by the simple
|
||||
presence of a switch. This is enabled by &bool_switch; as in <code>
|
||||
("other-option", bool_switch())</code>. This will cause the value to
|
||||
default to false and it will become true if the switch is found:</para>
|
||||
<screen>
|
||||
example --other-switch
|
||||
</screen>
|
||||
<para>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.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Annotated List of Symbols</title>
|
||||
|
||||
|
||||
<para>The following table describes all the important symbols in the
|
||||
library, for quick access.</para>
|
||||
|
||||
|
||||
<informaltable pgwide="1">
|
||||
|
||||
|
||||
<tgroup cols="2">
|
||||
<colspec colname='c1'/>
|
||||
<colspec colname='c2'/>
|
||||
<thead>
|
||||
|
||||
<row>
|
||||
|
||||
<row>
|
||||
<entry>Symbol</entry>
|
||||
<entry>Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
|
||||
<tbody>
|
||||
|
||||
<row>
|
||||
|
||||
<row>
|
||||
<entry namest='c1' nameend='c2'>Options description component</entry>
|
||||
</row>
|
||||
|
||||
|
||||
<row>
|
||||
<entry>&options_description;</entry>
|
||||
<entry>describes a number of options</entry>
|
||||
@@ -642,10 +599,10 @@ example --other-switch
|
||||
<entry>defines the option's value</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<row>
|
||||
<entry namest='c1' nameend='c2'>Parsers component</entry>
|
||||
</row>
|
||||
|
||||
|
||||
<row>
|
||||
<entry>&parse_command_line;</entry>
|
||||
<entry>parses command line (simpified interface)</entry>
|
||||
@@ -667,7 +624,7 @@ example --other-switch
|
||||
<entry>parses environment</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<row>
|
||||
<entry namest='c1' nameend='c2'>Storage component</entry>
|
||||
</row>
|
||||
|
||||
@@ -675,21 +632,21 @@ example --other-switch
|
||||
<entry>&variables_map;</entry>
|
||||
<entry>storage for option values</entry>
|
||||
</row>
|
||||
|
||||
|
||||
</tbody>
|
||||
</tgroup>
|
||||
|
||||
|
||||
</informaltable>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
<!--
|
||||
Local Variables:
|
||||
mode: nxml
|
||||
sgml-indent-data: t
|
||||
sgml-indent-data: t
|
||||
sgml-parent-document: ("program_options.xml" "section")
|
||||
sgml-set-face: t
|
||||
End:
|
||||
-->
|
||||
-->
|
||||
@@ -178,4 +178,5 @@
|
||||
|
||||
12. Deferred
|
||||
|
||||
- storing value to boost::optional
|
||||
- setting a flag when option is found
|
||||
|
||||
@@ -44,5 +44,3 @@
|
||||
<!ENTITY basic_option
|
||||
"<classname alt='boost::program_options::basic_option'>basic_option</classname>">
|
||||
|
||||
<!ENTITY bool_switch
|
||||
"<functionname alt='boost::program_options::bool_switch'>bool_switch</functionname>">
|
||||
|
||||
@@ -4,12 +4,12 @@ implement generic composition classes. The former was choosen,
|
||||
mostly because of simplicity.
|
||||
|
||||
There were two implementation approaches for multiple option
|
||||
occurrences in options_and_arguments. First is store them
|
||||
occurences in options_and_arguments. First is store them
|
||||
separately. The advantage is that it's easy to obtain all
|
||||
occurrences before certain position on command line. The
|
||||
occurences before certain position on command line. The
|
||||
disadvantage is that we cannot return a reference to
|
||||
vector<vector<string> > in get_all_values. It was considered
|
||||
that if support for position-dependent options is to be
|
||||
added, then we're be mostly interested in occurrences of
|
||||
added, then we're be mostly interested in occurences of
|
||||
a single option that were before some point. That's possible
|
||||
with vector<vector<string> > storage.
|
||||
with vector<vector<string> > storage.
|
||||
@@ -81,7 +81,7 @@
|
||||
|
||||
@section help_handling Handling of --help
|
||||
|
||||
It was suggested by Gennadiy Rozental that occurrence of <tt>--help</tt>
|
||||
It was suggested by Gennadiy Rozental that occurence of <tt>--help</tt>
|
||||
on command line results in throwing an exception. Actually, the
|
||||
"special" option must have been configurable. This was not
|
||||
implemented, because applications might reasonable want to process
|
||||
|
||||
@@ -208,9 +208,9 @@ Allowed options:
|
||||
--input-file arg : input file
|
||||
$ <userinput>bin/gcc/debug/options_description</userinput>
|
||||
Optimization level is 10
|
||||
$ <userinput>bin/gcc/debug/options_description --optimization 4 -I foo -I another/path --include-path third/include/path a.cpp b.cpp</userinput>
|
||||
Include paths are: foo another/path third/include/path
|
||||
Input files are: a.cpp b.cpp
|
||||
$ <userinput>bin/gcc/debug/options_description --optimization 4 -I foo a.cpp</userinput>
|
||||
Include paths are: foo
|
||||
Input files are: a.cpp
|
||||
Optimization level is 4
|
||||
</screen>
|
||||
</para>
|
||||
@@ -350,4 +350,4 @@ Optimization level is 4
|
||||
sgml-parent-document: ("program_options.xml" "section")
|
||||
sgml-set-face: t
|
||||
End:
|
||||
-->
|
||||
-->
|
||||
@@ -12,10 +12,3 @@ 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 ;
|
||||
|
||||
@@ -1,242 +0,0 @@
|
||||
// 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;
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
// 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;
|
||||
}
|
||||
@@ -29,9 +29,9 @@ using namespace boost::program_options;
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <exception>
|
||||
using namespace std;
|
||||
|
||||
|
||||
int main(int ac, char* av[])
|
||||
{
|
||||
try {
|
||||
@@ -39,7 +39,7 @@ int main(int ac, char* av[])
|
||||
options_description general("General options");
|
||||
general.add_options()
|
||||
("help", "produce a help message")
|
||||
("help-module", value<string>(),
|
||||
("help-module", value<string>()->implicit(),
|
||||
"produce a help for a given module")
|
||||
("version", "output the version number")
|
||||
;
|
||||
@@ -91,7 +91,7 @@ int main(int ac, char* av[])
|
||||
<< vm["num-threads"].as<int>() << "\n";
|
||||
}
|
||||
}
|
||||
catch(std::exception& e) {
|
||||
catch(exception& e) {
|
||||
cout << e.what() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ using namespace std;
|
||||
template<class T>
|
||||
ostream& operator<<(ostream& os, const vector<T>& v)
|
||||
{
|
||||
copy(v.begin(), v.end(), ostream_iterator<T>(os, " "));
|
||||
copy(v.begin(), v.end(), ostream_iterator<T>(os, " "));
|
||||
return os;
|
||||
}
|
||||
|
||||
@@ -30,26 +30,26 @@ int main(int ac, char* av[])
|
||||
po::options_description desc("Allowed options");
|
||||
desc.add_options()
|
||||
("help", "produce help message")
|
||||
("optimization", po::value<int>(&opt)->default_value(10),
|
||||
("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,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;
|
||||
@@ -58,13 +58,13 @@ int main(int ac, char* av[])
|
||||
|
||||
if (vm.count("include-path"))
|
||||
{
|
||||
cout << "Include paths are: "
|
||||
cout << "Include paths are: "
|
||||
<< vm["include-path"].as< vector<string> >() << "\n";
|
||||
}
|
||||
|
||||
if (vm.count("input-file"))
|
||||
{
|
||||
cout << "Input files are: "
|
||||
cout << "Input files are: "
|
||||
<< vm["input-file"].as< vector<string> >() << "\n";
|
||||
}
|
||||
|
||||
@@ -73,14 +73,14 @@ int main(int ac, char* av[])
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
cout << "Optimization level is " << opt << "\n";
|
||||
cout << "Optimization level is " << opt << "\n";
|
||||
|
||||
cout << "Listen port is " << portnum << "\n";
|
||||
cout << "Listen port is " << portnum << "\n";
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
cout << e.what() << "\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,690 +0,0 @@
|
||||
// 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
|
||||
|
||||
*/
|
||||
@@ -136,7 +136,7 @@ namespace boost { namespace program_options { namespace detail {
|
||||
const std::vector<style_parser>& style_parsers);
|
||||
|
||||
// Copies of input.
|
||||
std::vector<std::string> m_args;
|
||||
std::vector<std::string> args;
|
||||
style_t m_style;
|
||||
bool m_allow_unregistered;
|
||||
|
||||
|
||||
@@ -27,11 +27,6 @@
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4251) // class XYZ needs to have dll-interface to be used by clients of class XYZ
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace boost { namespace program_options { namespace detail {
|
||||
@@ -67,7 +62,7 @@ namespace boost { namespace program_options { namespace detail {
|
||||
TODO: maybe, we should just accept a pointer to options_description
|
||||
class.
|
||||
*/
|
||||
class BOOST_PROGRAM_OPTIONS_DECL common_config_file_iterator
|
||||
class common_config_file_iterator
|
||||
: public eof_iterator<common_config_file_iterator, option>
|
||||
{
|
||||
public:
|
||||
@@ -82,11 +77,6 @@ namespace boost { namespace program_options { namespace detail {
|
||||
|
||||
void get();
|
||||
|
||||
#if BOOST_WORKAROUND(_MSC_VER, <= 1900)
|
||||
void decrement() {}
|
||||
void advance(difference_type) {}
|
||||
#endif
|
||||
|
||||
protected: // Stubs for derived classes
|
||||
|
||||
// Obtains next line from the config file
|
||||
@@ -187,8 +177,4 @@ namespace boost { namespace program_options { namespace detail {
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,6 +12,20 @@
|
||||
|
||||
namespace boost { namespace program_options {
|
||||
|
||||
namespace detail {
|
||||
template<class charT, class Iterator>
|
||||
std::vector<std::basic_string<charT> >
|
||||
make_vector(Iterator i, Iterator e)
|
||||
{
|
||||
std::vector<std::basic_string<charT> > result;
|
||||
// Some compilers don't have templated constructor for
|
||||
// vector, so we can't create vector from (argv+1, argv+argc) range
|
||||
for(; i != e; ++i)
|
||||
result.push_back(*i);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
template<class charT>
|
||||
basic_command_line_parser<charT>::
|
||||
basic_command_line_parser(const std::vector<
|
||||
@@ -24,8 +38,9 @@ namespace boost { namespace program_options {
|
||||
basic_command_line_parser<charT>::
|
||||
basic_command_line_parser(int argc, const charT* const argv[])
|
||||
: detail::cmdline(
|
||||
to_internal(std::vector<std::basic_string<charT> >(argv+1, argv+argc))),
|
||||
m_desc()
|
||||
// Explicit template arguments are required by gcc 3.3.1
|
||||
// (at least mingw version), and do no harm on other compilers.
|
||||
to_internal(detail::make_vector<charT, const charT* const*>(argv+1, argv+argc+!argc)))
|
||||
{}
|
||||
|
||||
|
||||
@@ -33,7 +48,7 @@ namespace boost { namespace program_options {
|
||||
basic_command_line_parser<charT>&
|
||||
basic_command_line_parser<charT>::options(const options_description& desc)
|
||||
{
|
||||
detail::cmdline::set_options_description(desc);
|
||||
detail::cmdline::set_options_description(desc);
|
||||
m_desc = &desc;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
// forward declaration
|
||||
namespace boost { template<class T> class optional; }
|
||||
|
||||
namespace boost { namespace program_options {
|
||||
|
||||
extern BOOST_PROGRAM_OPTIONS_DECL std::string arg;
|
||||
@@ -155,20 +152,6 @@ namespace boost { namespace program_options {
|
||||
}
|
||||
}
|
||||
|
||||
/** Validates optional arguments. */
|
||||
template<class T, class charT>
|
||||
void validate(boost::any& v,
|
||||
const std::vector<std::basic_string<charT> >& s,
|
||||
boost::optional<T>*,
|
||||
int)
|
||||
{
|
||||
validators::check_first_occurrence(v);
|
||||
validators::get_single_string(s);
|
||||
boost::any a;
|
||||
validate(a, s, (T*)0, 0);
|
||||
v = boost::any(boost::optional<T>(boost::any_cast<T>(a)));
|
||||
}
|
||||
|
||||
template<class T, class charT>
|
||||
void
|
||||
typed_value<T, charT>::
|
||||
|
||||
@@ -40,9 +40,8 @@ namespace boost {
|
||||
assert(n != s.npos);
|
||||
value().first = s.substr(0, n);
|
||||
value().second = s.substr(n+1);
|
||||
|
||||
++m_environment;
|
||||
}
|
||||
}
|
||||
++m_environment;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -10,17 +10,17 @@
|
||||
|
||||
namespace boost {
|
||||
|
||||
/** The 'eof_iterator' class is useful for constructing forward iterators
|
||||
in cases where iterator extract data from some source and it's easy
|
||||
to detect 'eof' \-- i.e. the situation where there's no data. One
|
||||
/** The 'eof_iterator' class is useful for constructing forward iterators
|
||||
in cases where iterator extract data from some source and it's easy
|
||||
to detect 'eof' -- i.e. the situation where there's no data. One
|
||||
apparent example is reading lines from a file.
|
||||
|
||||
|
||||
Implementing such iterators using 'iterator_facade' directly would
|
||||
require to create class with three core operation, a couple of
|
||||
constructors. When using 'eof_iterator', the derived class should define
|
||||
require to create class with three core operation, a couple of
|
||||
constructors. When using 'eof_iterator', the derived class should define
|
||||
only one method to get new value, plus a couple of constructors.
|
||||
|
||||
The basic idea is that iterator has 'eof' bit. Two iterators are equal
|
||||
The basic idea is that iterator has 'eof' bit. Two iterators are equal
|
||||
only if both have their 'eof' bits set. The 'get' method either obtains
|
||||
the new value or sets the 'eof' bit.
|
||||
|
||||
@@ -33,13 +33,13 @@ namespace boost {
|
||||
3. The 'get' method. It should operate this way:
|
||||
- look at some 'data pointer' to see if new element is available;
|
||||
if not, it should call 'found_eof'.
|
||||
- extract new element and store it at location returned by the 'value'
|
||||
- extract new element and store it at location returned by the 'value'
|
||||
method.
|
||||
- advance the data pointer.
|
||||
|
||||
Essentially, the 'get' method has the functionality of both 'increment'
|
||||
and 'dereference'. It's very good for the cases where data extraction
|
||||
implicitly moves data pointer, like for stream operation.
|
||||
Essentially, the 'get' method has the functionality of both 'increment'
|
||||
and 'dereference'. It's very good for the cases where data extraction
|
||||
implicitly moves data pointer, like for stream operation.
|
||||
*/
|
||||
template<class Derived, class ValueType>
|
||||
class eof_iterator : public iterator_facade<Derived, const ValueType,
|
||||
@@ -65,20 +65,16 @@ namespace boost {
|
||||
{
|
||||
m_at_eof = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private: // iterator core operations
|
||||
#ifdef __DCC__
|
||||
friend class boost::iterator_core_access;
|
||||
#else
|
||||
friend class iterator_core_access;
|
||||
#endif
|
||||
|
||||
void increment()
|
||||
friend class iterator_core_access;
|
||||
|
||||
void increment()
|
||||
{
|
||||
static_cast<Derived&>(*this).get();
|
||||
}
|
||||
|
||||
|
||||
bool equal(const eof_iterator& other) const
|
||||
{
|
||||
if (m_at_eof && other.m_at_eof)
|
||||
@@ -86,14 +82,14 @@ namespace boost {
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const ValueType& dereference() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
bool m_at_eof;
|
||||
ValueType m_value;
|
||||
ValueType m_value;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -26,12 +26,7 @@ namespace boost { namespace program_options {
|
||||
inline std::string strip_prefixes(const std::string& text)
|
||||
{
|
||||
// "--foo-bar" -> "foo-bar"
|
||||
std::string::size_type i = text.find_first_not_of("-/");
|
||||
if (i == std::string::npos) {
|
||||
return text;
|
||||
} else {
|
||||
return text.substr(i);
|
||||
}
|
||||
return text.substr(text.find_first_not_of("-/"));
|
||||
}
|
||||
|
||||
/** Base class for all errors in the library. */
|
||||
@@ -110,13 +105,13 @@ namespace boost { namespace program_options {
|
||||
std::map<std::string, string_pair > m_substitution_defaults;
|
||||
|
||||
public:
|
||||
/** template with placeholders */
|
||||
std::string m_error_template;
|
||||
/** template with placeholders */
|
||||
std::string m_error_template;
|
||||
|
||||
error_with_option_name(const std::string& template_,
|
||||
const std::string& option_name = "",
|
||||
const std::string& original_token = "",
|
||||
int option_style = 0);
|
||||
error_with_option_name(const std::string& template_,
|
||||
const std::string& option_name = "",
|
||||
const std::string& original_token = "",
|
||||
int option_style = 0);
|
||||
|
||||
/** gcc says that throw specification on dtor is loosened
|
||||
* without this line
|
||||
@@ -174,7 +169,7 @@ namespace boost { namespace program_options {
|
||||
virtual void set_option_name(const std::string& option_name)
|
||||
{ set_substitute("option", option_name);}
|
||||
|
||||
std::string get_option_name() const
|
||||
std::string get_option_name() const throw()
|
||||
{ return get_canonical_option_name(); }
|
||||
|
||||
void set_original_token(const std::string& original_token)
|
||||
@@ -375,15 +370,12 @@ namespace boost { namespace program_options {
|
||||
const std::string& option_name = "",
|
||||
const std::string& original_token = "",
|
||||
int option_style = 0):
|
||||
error_with_option_name(get_template(kind), option_name, original_token, option_style),
|
||||
m_kind(kind)
|
||||
error_with_option_name(get_template(kind), option_name, original_token, option_style)
|
||||
{
|
||||
}
|
||||
|
||||
~validation_error() throw() {}
|
||||
|
||||
kind_t kind() const { return m_kind; }
|
||||
|
||||
protected:
|
||||
/** Used to convert kind_t to a related error text */
|
||||
std::string get_template(kind_t kind);
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace boost { namespace program_options {
|
||||
|
||||
/** Option found in input source.
|
||||
Contains a key and a value. The key, in turn, can be a string (name of
|
||||
an option), or an integer (position in input source) \-- in case no name
|
||||
an option), or an integer (position in input source) -- in case no name
|
||||
is specified. The latter is only possible for command line.
|
||||
The template parameter specifies the type of char used for storing the
|
||||
option's value.
|
||||
@@ -31,7 +31,6 @@ namespace boost { namespace program_options {
|
||||
basic_option(const std::string& xstring_key,
|
||||
const std::vector< std::string> &xvalue)
|
||||
: string_key(xstring_key)
|
||||
, position_key(-1)
|
||||
, value(xvalue)
|
||||
, unregistered(false)
|
||||
, case_insensitive(false)
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
@@ -42,7 +41,7 @@ namespace program_options {
|
||||
are used only to validate input. Second affect interpretation of the
|
||||
option, for example default value for it or function that should be
|
||||
called when the value is finally known. Routines which perform parsing
|
||||
never use second kind of properties \-- they are side effect free.
|
||||
never use second kind of properties -- they are side effect free.
|
||||
@sa options_description
|
||||
*/
|
||||
class BOOST_PROGRAM_OPTIONS_DECL option_description {
|
||||
@@ -72,7 +71,7 @@ namespace program_options {
|
||||
The 'name' parameter is interpreted by the following rules:
|
||||
- if there's no "," character in 'name', it specifies long name
|
||||
- otherwise, the part before "," specifies long name and the part
|
||||
after \-- short name.
|
||||
after -- short name.
|
||||
*/
|
||||
option_description(const char* name,
|
||||
const value_semantic* s);
|
||||
@@ -107,16 +106,14 @@ namespace program_options {
|
||||
/** Returns the canonical name for the option description to enable the user to
|
||||
recognised a matching option.
|
||||
1) For short options ('-', '/'), returns the short name prefixed.
|
||||
2) For long options ('--' / '-') returns the first long name prefixed
|
||||
3) All other cases, returns the first long name (if present) or the short
|
||||
name, unprefixed.
|
||||
2) For long options ('--' / '-') returns the long name prefixed
|
||||
3) All other cases, returns the long name (if present) or the short name,
|
||||
unprefixed.
|
||||
*/
|
||||
std::string canonical_display_name(int canonical_option_style = 0) const;
|
||||
|
||||
const std::string& long_name() const;
|
||||
|
||||
const std::pair<const std::string*, std::size_t> long_names() const;
|
||||
|
||||
/// Explanation of this option
|
||||
const std::string& description() const;
|
||||
|
||||
@@ -132,24 +129,9 @@ namespace program_options {
|
||||
|
||||
private:
|
||||
|
||||
option_description& set_names(const char* name);
|
||||
|
||||
/**
|
||||
* a one-character "switch" name - with its prefix,
|
||||
* so that this is either empty or has length 2 (e.g. "-c"
|
||||
*/
|
||||
std::string m_short_name;
|
||||
|
||||
/**
|
||||
* one or more names by which this option may be specified
|
||||
* on a command-line or in a config file, which are not
|
||||
* a single-letter switch. The names here are _without_
|
||||
* any prefix.
|
||||
*/
|
||||
std::vector<std::string> m_long_names;
|
||||
|
||||
std::string m_description;
|
||||
option_description& set_name(const char* name);
|
||||
|
||||
std::string m_short_name, m_long_name, m_description;
|
||||
// shared_ptr is needed to simplify memory management in
|
||||
// copy ctor and destructor.
|
||||
shared_ptr<const value_semantic> m_value_semantic;
|
||||
@@ -254,11 +236,6 @@ namespace program_options {
|
||||
void print(std::ostream& os, unsigned width = 0) const;
|
||||
|
||||
private:
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1800))
|
||||
// prevent warning C4512: assignment operator could not be generated
|
||||
options_description& operator=(const options_description&);
|
||||
#endif
|
||||
|
||||
typedef std::map<std::string, int>::const_iterator name2index_iterator;
|
||||
typedef std::pair<name2index_iterator, name2index_iterator>
|
||||
approximation_range;
|
||||
|
||||
@@ -28,20 +28,20 @@ namespace boost { namespace program_options {
|
||||
class positional_options_description;
|
||||
|
||||
|
||||
/** Results of parsing an input source.
|
||||
The primary use of this class is passing information from parsers
|
||||
/** Results of parsing an input source.
|
||||
The primary use of this class is passing information from parsers
|
||||
component to value storage component. This class does not makes
|
||||
much sense itself.
|
||||
much sense itself.
|
||||
*/
|
||||
template<class charT>
|
||||
class basic_parsed_options {
|
||||
public:
|
||||
explicit basic_parsed_options(const options_description* xdescription, int options_prefix = 0)
|
||||
explicit basic_parsed_options(const options_description* xdescription, int options_prefix = 0)
|
||||
: description(xdescription), m_options_prefix(options_prefix) {}
|
||||
/** Options found in the source. */
|
||||
std::vector< basic_option<charT> > options;
|
||||
/** Options description that was used for parsing.
|
||||
Parsers should return pointer to the instance of
|
||||
/** Options description that was used for parsing.
|
||||
Parsers should return pointer to the instance of
|
||||
option_description passed to them, and issues of lifetime are
|
||||
up to the caller. Can be NULL.
|
||||
*/
|
||||
@@ -55,7 +55,7 @@ namespace boost { namespace program_options {
|
||||
* allow_long_disguise
|
||||
* allow_dash_for_short
|
||||
* allow_slash_for_short
|
||||
*/
|
||||
*/
|
||||
int m_options_prefix;
|
||||
};
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace boost { namespace program_options {
|
||||
|
||||
/** Stores UTF8 encoded options that were passed to constructor,
|
||||
to avoid reverse conversion in some cases. */
|
||||
basic_parsed_options<char> utf8_encoded_options;
|
||||
basic_parsed_options<char> utf8_encoded_options;
|
||||
|
||||
/** Mainly used for the diagnostic messages in exceptions.
|
||||
* The canonical option prefix for the parser which generated these results,
|
||||
@@ -84,7 +84,7 @@ namespace boost { namespace program_options {
|
||||
* allow_long_disguise
|
||||
* allow_dash_for_short
|
||||
* allow_slash_for_short
|
||||
*/
|
||||
*/
|
||||
int m_options_prefix;
|
||||
};
|
||||
|
||||
@@ -101,14 +101,14 @@ namespace boost { namespace program_options {
|
||||
|
||||
The class allows one to specify all the information needed for parsing
|
||||
and to parse the command line. It is primarily needed to
|
||||
emulate named function parameters \-- a regular function with 5
|
||||
emulate named function parameters -- a regular function with 5
|
||||
parameters will be hard to use and creating overloads with a smaller
|
||||
number of parameters will be confusing.
|
||||
nuber of parameters will be confusing.
|
||||
|
||||
For the most common case, the function parse_command_line is a better
|
||||
alternative.
|
||||
For the most common case, the function parse_command_line is a better
|
||||
alternative.
|
||||
|
||||
There are two typedefs \-- command_line_parser and wcommand_line_parser,
|
||||
There are two typedefs -- command_line_parser and wcommand_line_parser,
|
||||
for charT == char and charT == wchar_t cases.
|
||||
*/
|
||||
template<class charT>
|
||||
@@ -146,10 +146,10 @@ namespace boost { namespace program_options {
|
||||
instance of basic_option<charT> will be added to result,
|
||||
with 'unrecognized' field set to 'true'. It's possible to
|
||||
collect all unrecognized options with the 'collect_unrecognized'
|
||||
funciton.
|
||||
funciton.
|
||||
*/
|
||||
basic_command_line_parser& allow_unregistered();
|
||||
|
||||
|
||||
using detail::cmdline::style_parser;
|
||||
|
||||
basic_command_line_parser& extra_style_parser(style_parser s);
|
||||
@@ -162,19 +162,19 @@ namespace boost { namespace program_options {
|
||||
typedef basic_command_line_parser<wchar_t> wcommand_line_parser;
|
||||
|
||||
/** Creates instance of 'command_line_parser', passes parameters to it,
|
||||
and returns the result of calling the 'run' method.
|
||||
and returns the result of calling the 'run' method.
|
||||
*/
|
||||
template<class charT>
|
||||
basic_parsed_options<charT>
|
||||
parse_command_line(int argc, const charT* const argv[],
|
||||
const options_description&,
|
||||
int style = 0,
|
||||
function1<std::pair<std::string, std::string>,
|
||||
function1<std::pair<std::string, std::string>,
|
||||
const std::string&> ext
|
||||
= ext_parser());
|
||||
|
||||
/** Parse a config file.
|
||||
|
||||
/** Parse a config file.
|
||||
|
||||
Read from given stream.
|
||||
*/
|
||||
template<class charT>
|
||||
@@ -185,16 +185,12 @@ namespace boost { namespace program_options {
|
||||
parse_config_file(std::basic_istream<charT>&, const options_description&,
|
||||
bool allow_unregistered = false);
|
||||
|
||||
/** Parse a config file.
|
||||
|
||||
/** Parse a config file.
|
||||
|
||||
Read from file with the given name. The character type is
|
||||
passed to the file stream.
|
||||
passed to the file stream.
|
||||
*/
|
||||
#ifdef BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS
|
||||
template<class charT>
|
||||
#else
|
||||
template<class charT = char>
|
||||
#endif
|
||||
#if ! BOOST_WORKAROUND(__ICL, BOOST_TESTED_AT(700))
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
#endif
|
||||
@@ -204,7 +200,7 @@ namespace boost { namespace program_options {
|
||||
|
||||
/** Controls if the 'collect_unregistered' function should
|
||||
include positional options, or not. */
|
||||
enum collect_unrecognized_mode
|
||||
enum collect_unrecognized_mode
|
||||
{ include_positional, exclude_positional };
|
||||
|
||||
/** Collects the original tokens for all named options with
|
||||
@@ -214,34 +210,34 @@ namespace boost { namespace program_options {
|
||||
options.
|
||||
*/
|
||||
template<class charT>
|
||||
std::vector< std::basic_string<charT> >
|
||||
std::vector< std::basic_string<charT> >
|
||||
collect_unrecognized(const std::vector< basic_option<charT> >& options,
|
||||
enum collect_unrecognized_mode mode);
|
||||
|
||||
/** Parse environment.
|
||||
/** Parse environment.
|
||||
|
||||
For each environment variable, the 'name_mapper' function is called to
|
||||
obtain the option name. If it returns empty string, the variable is
|
||||
ignored.
|
||||
obtain the option name. If it returns empty string, the variable is
|
||||
ignored.
|
||||
|
||||
This is done since naming of environment variables is typically
|
||||
different from the naming of command line options.
|
||||
This is done since naming of environment variables is typically
|
||||
different from the naming of command line options.
|
||||
*/
|
||||
BOOST_PROGRAM_OPTIONS_DECL parsed_options
|
||||
parse_environment(const options_description&,
|
||||
parse_environment(const options_description&,
|
||||
const function1<std::string, std::string>& name_mapper);
|
||||
|
||||
/** Parse environment.
|
||||
|
||||
Takes all environment variables which start with 'prefix'. The option
|
||||
name is obtained from variable name by removing the prefix and
|
||||
name is obtained from variable name by removing the prefix and
|
||||
converting the remaining string into lower case.
|
||||
*/
|
||||
BOOST_PROGRAM_OPTIONS_DECL parsed_options
|
||||
parse_environment(const options_description&, const std::string& prefix);
|
||||
|
||||
/** @overload
|
||||
This function exists to resolve ambiguity between the two above
|
||||
This function exists to resolve ambiguity between the two above
|
||||
functions when second argument is of 'char*' type. There's implicit
|
||||
conversion to both function1 and string.
|
||||
*/
|
||||
@@ -256,13 +252,13 @@ namespace boost { namespace program_options {
|
||||
and escape characters '\'
|
||||
*/
|
||||
BOOST_PROGRAM_OPTIONS_DECL std::vector<std::string>
|
||||
split_unix(const std::string& cmdline, const std::string& seperator = " \t",
|
||||
split_unix(const std::string& cmdline, const std::string& seperator = " \t",
|
||||
const std::string& quote = "'\"", const std::string& escape = "\\");
|
||||
|
||||
|
||||
#ifndef BOOST_NO_STD_WSTRING
|
||||
/** @overload */
|
||||
BOOST_PROGRAM_OPTIONS_DECL std::vector<std::wstring>
|
||||
split_unix(const std::wstring& cmdline, const std::wstring& seperator = L" \t",
|
||||
split_unix(const std::wstring& cmdline, const std::wstring& seperator = L" \t",
|
||||
const std::wstring& quote = L"'\"", const std::wstring& escape = L"\\");
|
||||
#endif
|
||||
|
||||
@@ -282,7 +278,7 @@ namespace boost { namespace program_options {
|
||||
split_winmain(const std::wstring& cmdline);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
}}
|
||||
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
#include <boost/function/function1.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <typeinfo>
|
||||
#include <limits>
|
||||
|
||||
namespace boost { namespace program_options {
|
||||
|
||||
@@ -156,7 +156,6 @@ namespace boost { namespace program_options {
|
||||
bool m_zero_tokens;
|
||||
};
|
||||
|
||||
#ifndef BOOST_NO_RTTI
|
||||
/** Base class for all option that have a fixed type, and are
|
||||
willing to announce this type to the outside world.
|
||||
Any 'value_semantics' for which you want to find out the
|
||||
@@ -173,23 +172,20 @@ namespace boost { namespace program_options {
|
||||
// class is silly, but just in case.
|
||||
virtual ~typed_value_base() {}
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/** Class which handles value of a specific type. */
|
||||
template<class T, class charT = char>
|
||||
class typed_value : public value_semantic_codecvt_helper<charT>
|
||||
#ifndef BOOST_NO_RTTI
|
||||
, public typed_value_base
|
||||
#endif
|
||||
class typed_value : public value_semantic_codecvt_helper<charT>,
|
||||
public typed_value_base
|
||||
{
|
||||
public:
|
||||
/** Ctor. The 'store_to' parameter tells where to store
|
||||
the value when it's known. The parameter can be NULL. */
|
||||
typed_value(T* store_to)
|
||||
: m_store_to(store_to), m_composing(false),
|
||||
m_implicit(false), m_multitoken(false),
|
||||
m_zero_tokens(false), m_required(false)
|
||||
m_multitoken(false), m_zero_tokens(false),
|
||||
m_required(false)
|
||||
{}
|
||||
|
||||
/** Specifies default value, which will be used
|
||||
@@ -218,7 +214,10 @@ namespace boost { namespace program_options {
|
||||
|
||||
/** Specifies an implicit value, which will be used
|
||||
if the option is given, but without an adjacent value.
|
||||
Using this implies that an explicit value is optional,
|
||||
Using this implies that an explicit value is optional, but if
|
||||
given, must be strictly adjacent to the option, i.e.: '-ovalue'
|
||||
or '--option=value'. Giving '-o' or '--option' will cause the
|
||||
implicit value to be applied.
|
||||
*/
|
||||
typed_value* implicit_value(const T &v)
|
||||
{
|
||||
@@ -314,7 +313,7 @@ namespace boost { namespace program_options {
|
||||
|
||||
unsigned max_tokens() const {
|
||||
if (m_multitoken) {
|
||||
return std::numeric_limits<unsigned>::max BOOST_PREVENT_MACRO_SUBSTITUTION();
|
||||
return 32000;
|
||||
} else if (m_zero_tokens) {
|
||||
return 0;
|
||||
} else {
|
||||
@@ -351,12 +350,10 @@ namespace boost { namespace program_options {
|
||||
|
||||
public: // typed_value_base overrides
|
||||
|
||||
#ifndef BOOST_NO_RTTI
|
||||
const std::type_info& value_type() const
|
||||
{
|
||||
return typeid(T);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
private:
|
||||
|
||||
@@ -31,35 +31,35 @@ namespace boost { namespace program_options {
|
||||
|
||||
// forward declaration
|
||||
|
||||
/** Stores in 'm' all options that are defined in 'options'.
|
||||
/** Stores in 'm' all options that are defined in 'options'.
|
||||
If 'm' already has a non-defaulted value of an option, that value
|
||||
is not changed, even if 'options' specify some value.
|
||||
is not changed, even if 'options' specify some value.
|
||||
*/
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
void store(const basic_parsed_options<char>& options, variables_map& m,
|
||||
bool utf8 = false);
|
||||
|
||||
/** Stores in 'm' all options that are defined in 'options'.
|
||||
/** Stores in 'm' all options that are defined in 'options'.
|
||||
If 'm' already has a non-defaulted value of an option, that value
|
||||
is not changed, even if 'options' specify some value.
|
||||
is not changed, even if 'options' specify some value.
|
||||
This is wide character variant.
|
||||
*/
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
void store(const basic_parsed_options<wchar_t>& options,
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
void store(const basic_parsed_options<wchar_t>& options,
|
||||
variables_map& m);
|
||||
|
||||
|
||||
/** Runs all 'notify' function for options in 'm'. */
|
||||
BOOST_PROGRAM_OPTIONS_DECL void notify(variables_map& m);
|
||||
|
||||
/** Class holding value of option. Contains details about how the
|
||||
/** Class holding value of option. Contains details about how the
|
||||
value is set and allows to conveniently obtain the value.
|
||||
*/
|
||||
class BOOST_PROGRAM_OPTIONS_DECL variable_value {
|
||||
public:
|
||||
variable_value() : m_defaulted(false) {}
|
||||
variable_value(const boost::any& xv, bool xdefaulted)
|
||||
: v(xv), m_defaulted(xdefaulted)
|
||||
variable_value(const boost::any& xv, bool xdefaulted)
|
||||
: v(xv), m_defaulted(xdefaulted)
|
||||
{}
|
||||
|
||||
/** If stored value if of type T, returns that value. Otherwise,
|
||||
@@ -95,7 +95,7 @@ namespace boost { namespace program_options {
|
||||
shared_ptr<const value_semantic> m_value_semantic;
|
||||
|
||||
friend BOOST_PROGRAM_OPTIONS_DECL
|
||||
void store(const basic_parsed_options<char>& options,
|
||||
void store(const basic_parsed_options<char>& options,
|
||||
variables_map& m, bool);
|
||||
|
||||
friend class BOOST_PROGRAM_OPTIONS_DECL variables_map;
|
||||
@@ -118,11 +118,11 @@ namespace boost { namespace program_options {
|
||||
- otherwise, returns empty value
|
||||
|
||||
- if there's defaulted value
|
||||
- if there's next variable map, which has a non-defaulted
|
||||
- if there's next varaible map, which has a non-defauled
|
||||
value, return that
|
||||
- otherwise, return value from *this
|
||||
|
||||
- if there's a non-defaulted value, returns it.
|
||||
- if there's a non-defauled value, returns it.
|
||||
*/
|
||||
const variable_value& operator[](const std::string& name) const;
|
||||
|
||||
@@ -138,8 +138,8 @@ namespace boost { namespace program_options {
|
||||
const abstract_variables_map* m_next;
|
||||
};
|
||||
|
||||
/** Concrete variables map which store variables in real map.
|
||||
|
||||
/** Concrete variables map which store variables in real map.
|
||||
|
||||
This class is derived from std::map<std::string, variable_value>,
|
||||
so you can use all map operators to examine its content.
|
||||
*/
|
||||
@@ -155,8 +155,8 @@ namespace boost { namespace program_options {
|
||||
{ return abstract_variables_map::operator[](name); }
|
||||
|
||||
// Override to clear some extra fields.
|
||||
void clear();
|
||||
|
||||
void clear();
|
||||
|
||||
void notify();
|
||||
|
||||
private:
|
||||
@@ -164,15 +164,15 @@ namespace boost { namespace program_options {
|
||||
which does 'find' in *this. */
|
||||
const variable_value& get(const std::string& name) const;
|
||||
|
||||
/** Names of option with 'final' values \-- which should not
|
||||
/** Names of option with 'final' values -- which should not
|
||||
be changed by subsequence assignments. */
|
||||
std::set<std::string> m_final;
|
||||
|
||||
friend BOOST_PROGRAM_OPTIONS_DECL
|
||||
void store(const basic_parsed_options<char>& options,
|
||||
void store(const basic_parsed_options<char>& options,
|
||||
variables_map& xm,
|
||||
bool utf8);
|
||||
|
||||
|
||||
/** Names of required options, filled by parser which has
|
||||
access to options_description.
|
||||
The map values are the "canonical" names for each corresponding option.
|
||||
|
||||
@@ -15,8 +15,5 @@
|
||||
#endif
|
||||
#define BOOST_PROGRAM_OPTIONS_VERSION 2
|
||||
|
||||
// Signal that implicit options will use values from next
|
||||
// token, if available.
|
||||
#define BOOST_PROGRAM_OPTIONS_IMPLICIT_VALUE_NEXT_TOKEN 1
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"key": "program_options",
|
||||
"name": "Program Options",
|
||||
"authors": [
|
||||
"Vladimir Prus"
|
||||
],
|
||||
"description": "The program_options library allows program developers to obtain program options, that is (name, value) pairs from the user, via conventional methods such as command line and config file.",
|
||||
"category": [
|
||||
"IO",
|
||||
"Miscellaneous"
|
||||
],
|
||||
"maintainers": [
|
||||
"Vladimir Prus <vladimir.prus -at- gmail.com>"
|
||||
]
|
||||
}
|
||||
@@ -103,7 +103,7 @@ namespace boost { namespace program_options { namespace detail {
|
||||
void
|
||||
cmdline::init(const vector<string>& args)
|
||||
{
|
||||
this->m_args = args;
|
||||
this->args = args;
|
||||
m_style = command_line_style::default_style;
|
||||
m_desc = 0;
|
||||
m_positional = 0;
|
||||
@@ -244,7 +244,6 @@ namespace boost { namespace program_options { namespace detail {
|
||||
style_parsers.push_back(boost::bind(&cmdline::parse_terminator, this, _1));
|
||||
|
||||
vector<option> result;
|
||||
vector<string>& args = m_args;
|
||||
while(!args.empty())
|
||||
{
|
||||
bool ok = false;
|
||||
@@ -435,6 +434,9 @@ namespace boost { namespace program_options { namespace detail {
|
||||
// (the value in --foo=1) counts as a separate token, and if present
|
||||
// must be consumed. The following tokens on the command line may be
|
||||
// left unconsumed.
|
||||
|
||||
// We don't check if those tokens look like option, or not!
|
||||
|
||||
unsigned min_tokens = d.semantic()->min_tokens();
|
||||
unsigned max_tokens = d.semantic()->max_tokens();
|
||||
|
||||
@@ -448,8 +450,9 @@ namespace boost { namespace program_options { namespace detail {
|
||||
invalid_command_line_syntax(invalid_command_line_syntax::extra_parameter));
|
||||
}
|
||||
|
||||
// Grab min_tokens values from other_tokens, but only if those tokens
|
||||
// are not recognized as options themselves.
|
||||
// If an option wants, at minimum, N tokens, we grab them there,
|
||||
// when adding these tokens as values to current option we check
|
||||
// if they look like options
|
||||
if (opt.value.size() <= min_tokens)
|
||||
{
|
||||
min_tokens -= static_cast<unsigned>(opt.value.size());
|
||||
@@ -459,7 +462,7 @@ namespace boost { namespace program_options { namespace detail {
|
||||
min_tokens = 0;
|
||||
}
|
||||
|
||||
// Everything's OK, move the values to the result.
|
||||
// Everything's OK, move the values to the result.
|
||||
for(;!other_tokens.empty() && min_tokens--; )
|
||||
{
|
||||
// check if extra parameter looks like a known option
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#define BOOST_PROGRAM_OPTIONS_SOURCE
|
||||
#include <boost/program_options/config.hpp>
|
||||
#include <boost/program_options/options_description.hpp>
|
||||
// FIXME: this is only to get multiple_occurrences class
|
||||
// FIXME: this is only to get multiple_occurences class
|
||||
// should move that to a separate headers.
|
||||
#include <boost/program_options/parsers.hpp>
|
||||
|
||||
@@ -49,21 +49,21 @@ namespace boost { namespace program_options {
|
||||
}
|
||||
|
||||
option_description::
|
||||
option_description(const char* names,
|
||||
option_description(const char* name,
|
||||
const value_semantic* s)
|
||||
: m_value_semantic(s)
|
||||
{
|
||||
this->set_names(names);
|
||||
this->set_name(name);
|
||||
}
|
||||
|
||||
|
||||
option_description::
|
||||
option_description(const char* names,
|
||||
option_description(const char* name,
|
||||
const value_semantic* s,
|
||||
const char* description)
|
||||
: m_description(description), m_value_semantic(s)
|
||||
{
|
||||
this->set_names(names);
|
||||
this->set_name(name);
|
||||
}
|
||||
|
||||
option_description::~option_description()
|
||||
@@ -77,42 +77,38 @@ namespace boost { namespace program_options {
|
||||
bool short_ignore_case) const
|
||||
{
|
||||
match_result result = no_match;
|
||||
std::string local_option = (long_ignore_case ? tolower_(option) : option);
|
||||
|
||||
for(std::vector<std::string>::const_iterator it(m_long_names.begin()); it != m_long_names.end(); it++)
|
||||
{
|
||||
std::string local_long_name((long_ignore_case ? tolower_(*it) : *it));
|
||||
std::string local_long_name((long_ignore_case ? tolower_(m_long_name) : m_long_name));
|
||||
|
||||
if (!local_long_name.empty()) {
|
||||
|
||||
std::string local_option = (long_ignore_case ? tolower_(option) : option);
|
||||
|
||||
if (!local_long_name.empty()) {
|
||||
|
||||
|
||||
if ((result == no_match) && (*local_long_name.rbegin() == '*'))
|
||||
{
|
||||
// The name ends with '*'. Any specified name with the given
|
||||
// prefix is OK.
|
||||
if (local_option.find(local_long_name.substr(0, local_long_name.length()-1))
|
||||
== 0)
|
||||
result = approximate_match;
|
||||
}
|
||||
|
||||
if (local_long_name == local_option)
|
||||
{
|
||||
result = full_match;
|
||||
break;
|
||||
}
|
||||
else if (approx)
|
||||
{
|
||||
if (local_long_name.find(local_option) == 0)
|
||||
{
|
||||
result = approximate_match;
|
||||
}
|
||||
}
|
||||
if (*local_long_name.rbegin() == '*')
|
||||
{
|
||||
// The name ends with '*'. Any specified name with the given
|
||||
// prefix is OK.
|
||||
if (local_option.find(local_long_name.substr(0, local_long_name.length()-1))
|
||||
== 0)
|
||||
result = approximate_match;
|
||||
}
|
||||
|
||||
if (local_long_name == local_option)
|
||||
{
|
||||
result = full_match;
|
||||
}
|
||||
else if (approx)
|
||||
{
|
||||
if (local_long_name.find(local_option) == 0)
|
||||
{
|
||||
result = approximate_match;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (result != full_match)
|
||||
{
|
||||
std::string local_option(short_ignore_case ? tolower_(option) : option);
|
||||
std::string local_short_name(short_ignore_case ? tolower_(m_short_name) : m_short_name);
|
||||
|
||||
if (local_short_name == local_option)
|
||||
@@ -126,12 +122,9 @@ namespace boost { namespace program_options {
|
||||
|
||||
const std::string&
|
||||
option_description::key(const std::string& option) const
|
||||
{
|
||||
// We make the arbitrary choise of using the first long
|
||||
// name as the key, regardless of anything else
|
||||
if (!m_long_names.empty()) {
|
||||
const std::string& first_long_name = *m_long_names.begin();
|
||||
if (first_long_name.find('*') != string::npos)
|
||||
{
|
||||
if (!m_long_name.empty())
|
||||
if (m_long_name.find('*') != string::npos)
|
||||
// The '*' character means we're long_name
|
||||
// matches only part of the input. So, returning
|
||||
// long name will remove some of the information,
|
||||
@@ -139,8 +132,7 @@ namespace boost { namespace program_options {
|
||||
// in the source.
|
||||
return option;
|
||||
else
|
||||
return first_long_name;
|
||||
}
|
||||
return m_long_name;
|
||||
else
|
||||
return m_short_name;
|
||||
}
|
||||
@@ -148,13 +140,12 @@ namespace boost { namespace program_options {
|
||||
std::string
|
||||
option_description::canonical_display_name(int prefix_style) const
|
||||
{
|
||||
// We prefer the first long name over any others
|
||||
if (!m_long_names.empty())
|
||||
if (!m_long_name.empty())
|
||||
{
|
||||
if (prefix_style == command_line_style::allow_long)
|
||||
return "--" + *m_long_names.begin();
|
||||
return "--" + m_long_name;
|
||||
if (prefix_style == command_line_style::allow_long_disguise)
|
||||
return "-" + *m_long_names.begin();
|
||||
return "-" + m_long_name;
|
||||
}
|
||||
// sanity check: m_short_name[0] should be '-' or '/'
|
||||
if (m_short_name.length() == 2)
|
||||
@@ -164,8 +155,8 @@ namespace boost { namespace program_options {
|
||||
if (prefix_style == command_line_style::allow_dash_for_short)
|
||||
return string("-") + m_short_name[1];
|
||||
}
|
||||
if (!m_long_names.empty())
|
||||
return *m_long_names.begin();
|
||||
if (!m_long_name.empty())
|
||||
return m_long_name;
|
||||
else
|
||||
return m_short_name;
|
||||
}
|
||||
@@ -174,47 +165,21 @@ namespace boost { namespace program_options {
|
||||
const std::string&
|
||||
option_description::long_name() const
|
||||
{
|
||||
static std::string empty_string("");
|
||||
return m_long_names.empty() ? empty_string : *m_long_names.begin();
|
||||
}
|
||||
|
||||
const std::pair<const std::string*, std::size_t>
|
||||
option_description::long_names() const
|
||||
{
|
||||
// reinterpret_cast is to please msvc 10.
|
||||
return (m_long_names.empty())
|
||||
? std::pair<const std::string*, size_t>(reinterpret_cast<const std::string*>(0), 0 )
|
||||
: std::pair<const std::string*, size_t>( &(*m_long_names.begin()), m_long_names.size());
|
||||
return m_long_name;
|
||||
}
|
||||
|
||||
option_description&
|
||||
option_description::set_names(const char* _names)
|
||||
option_description::set_name(const char* _name)
|
||||
{
|
||||
m_long_names.clear();
|
||||
std::istringstream iss(_names);
|
||||
std::string name;
|
||||
|
||||
while(std::getline(iss, name, ',')) {
|
||||
m_long_names.push_back(name);
|
||||
std::string name(_name);
|
||||
string::size_type n = name.find(',');
|
||||
if (n != string::npos) {
|
||||
assert(n == name.size()-2);
|
||||
m_long_name = name.substr(0, n);
|
||||
m_short_name = '-' + name.substr(n+1,1);
|
||||
} else {
|
||||
m_long_name = name;
|
||||
}
|
||||
assert(!m_long_names.empty() && "No option names were specified");
|
||||
|
||||
bool try_interpreting_last_name_as_a_switch = m_long_names.size() > 1;
|
||||
if (try_interpreting_last_name_as_a_switch) {
|
||||
const std::string& last_name = *m_long_names.rbegin();
|
||||
if (last_name.length() == 1) {
|
||||
m_short_name = '-' + last_name;
|
||||
m_long_names.pop_back();
|
||||
// The following caters to the (valid) input of ",c" for some
|
||||
// character c, where the caller only wants this option to have
|
||||
// a short name.
|
||||
if (m_long_names.size() == 1 && (*m_long_names.begin()).empty()) {
|
||||
m_long_names.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
// We could theoretically also ensure no remaining long names
|
||||
// are empty, or that none of them have length 1
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -235,12 +200,12 @@ namespace boost { namespace program_options {
|
||||
{
|
||||
if (!m_short_name.empty())
|
||||
{
|
||||
return m_long_names.empty()
|
||||
return m_long_name.empty()
|
||||
? m_short_name
|
||||
: string(m_short_name).append(" [ --").
|
||||
append(*m_long_names.begin()).append(" ]");
|
||||
append(m_long_name).append(" ]");
|
||||
}
|
||||
return string("--").append(*m_long_names.begin());
|
||||
return string("--").append(m_long_name);
|
||||
}
|
||||
|
||||
std::string
|
||||
|
||||
@@ -220,7 +220,7 @@ namespace boost { namespace program_options {
|
||||
{
|
||||
// Intel-Win-7.1 does not understand
|
||||
// push_back on string.
|
||||
result += static_cast<char>(tolower(s[n]));
|
||||
result += tolower(s[n]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -268,7 +268,7 @@ namespace boost { namespace program_options {
|
||||
|
||||
void error_with_option_name::replace_token(const string& from, const string& to) const
|
||||
{
|
||||
for (;;)
|
||||
while (1)
|
||||
{
|
||||
std::size_t pos = m_message.find(from.c_str(), 0, from.length());
|
||||
// not found: all replaced
|
||||
|
||||
@@ -17,12 +17,12 @@ namespace boost { namespace program_options {
|
||||
|
||||
using namespace std;
|
||||
|
||||
// First, performs semantic actions for 'oa'.
|
||||
// Then, stores in 'm' all options that are defined in 'desc'.
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
// First, performs semantic actions for 'oa'.
|
||||
// Then, stores in 'm' all options that are defined in 'desc'.
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
void store(const parsed_options& options, variables_map& xm,
|
||||
bool utf8)
|
||||
{
|
||||
{
|
||||
// TODO: what if we have different definition
|
||||
// for the same option name during different calls
|
||||
// 'store'.
|
||||
@@ -42,15 +42,16 @@ namespace boost { namespace program_options {
|
||||
string option_name;
|
||||
string original_token;
|
||||
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try
|
||||
#endif
|
||||
{
|
||||
|
||||
// First, convert/store all given options
|
||||
for (i = 0; i < options.options.size(); ++i) {
|
||||
|
||||
option_name = options.options[i].string_key;
|
||||
original_token = options.options[i].original_tokens.size() ?
|
||||
options.options[i].original_tokens[0] :
|
||||
option_name;
|
||||
// Skip positional options without name
|
||||
if (option_name.empty())
|
||||
continue;
|
||||
@@ -58,7 +59,7 @@ namespace boost { namespace program_options {
|
||||
// Ignore unregistered option. The 'unregistered'
|
||||
// field can be true only if user has explicitly asked
|
||||
// to allow unregistered options. We can't store them
|
||||
// to variables map (lacking any information about paring),
|
||||
// to variables map (lacking any information about paring),
|
||||
// so just ignore them.
|
||||
if (options.options[i].unregistered)
|
||||
continue;
|
||||
@@ -67,21 +68,21 @@ namespace boost { namespace program_options {
|
||||
if (xm.m_final.count(option_name))
|
||||
continue;
|
||||
|
||||
original_token = options.options[i].original_tokens.size() ?
|
||||
string original_token = options.options[i].original_tokens.size() ?
|
||||
options.options[i].original_tokens[0] : "";
|
||||
const option_description& d = desc.find(option_name, false,
|
||||
const option_description& d = desc.find(option_name, false,
|
||||
false, false);
|
||||
|
||||
variable_value& v = m[option_name];
|
||||
variable_value& v = m[option_name];
|
||||
if (v.defaulted()) {
|
||||
// Explicit assignment here erases defaulted value
|
||||
v = variable_value();
|
||||
}
|
||||
|
||||
|
||||
d.semantic()->parse(v.value(), options.options[i].value, utf8);
|
||||
|
||||
v.m_value_semantic = d.semantic();
|
||||
|
||||
|
||||
// The option is not composing, and the value is explicitly
|
||||
// provided. Ignore values of this option for subsequent
|
||||
// calls to 'store'. We store this to a temporary set,
|
||||
@@ -90,7 +91,7 @@ namespace boost { namespace program_options {
|
||||
if (!d.semantic()->is_composing())
|
||||
new_final.insert(option_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
catch(error_with_option_name& e)
|
||||
{
|
||||
@@ -101,8 +102,8 @@ namespace boost { namespace program_options {
|
||||
#endif
|
||||
xm.m_final.insert(new_final.begin(), new_final.end());
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Second, apply default values and store required options.
|
||||
const vector<shared_ptr<option_description> >& all = desc.options();
|
||||
for(i = 0; i < all.size(); ++i)
|
||||
@@ -111,21 +112,21 @@ namespace boost { namespace program_options {
|
||||
string key = d.key("");
|
||||
// FIXME: this logic relies on knowledge of option_description
|
||||
// internals.
|
||||
// The 'key' is empty if options description contains '*'.
|
||||
// In that
|
||||
// The 'key' is empty if options description contains '*'.
|
||||
// In that
|
||||
// case, default value makes no sense at all.
|
||||
if (key.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (m.count(key) == 0) {
|
||||
|
||||
|
||||
boost::any def;
|
||||
if (d.semantic()->apply_default(def)) {
|
||||
m[key] = variable_value(def, true);
|
||||
m[key].m_value_semantic = d.semantic();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add empty value if this is an required option
|
||||
if (d.semantic()->is_required()) {
|
||||
@@ -141,16 +142,16 @@ namespace boost { namespace program_options {
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
void store(const wparsed_options& options, variables_map& m)
|
||||
{
|
||||
store(options.utf8_encoded_options, m, true);
|
||||
}
|
||||
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
void notify(variables_map& vm)
|
||||
{
|
||||
vm.notify();
|
||||
{
|
||||
vm.notify();
|
||||
}
|
||||
|
||||
abstract_variables_map::abstract_variables_map()
|
||||
@@ -162,7 +163,7 @@ namespace boost { namespace program_options {
|
||||
: m_next(next)
|
||||
{}
|
||||
|
||||
const variable_value&
|
||||
const variable_value&
|
||||
abstract_variables_map::operator[](const std::string& name) const
|
||||
{
|
||||
const variable_value& v = get(name);
|
||||
@@ -178,7 +179,7 @@ namespace boost { namespace program_options {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
abstract_variables_map::next(abstract_variables_map* next)
|
||||
{
|
||||
m_next = next;
|
||||
@@ -208,7 +209,7 @@ namespace boost { namespace program_options {
|
||||
else
|
||||
return i->second;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
variables_map::notify()
|
||||
{
|
||||
@@ -220,29 +221,29 @@ namespace boost { namespace program_options {
|
||||
const string& opt = r->first;
|
||||
const string& display_opt = r->second;
|
||||
map<string, variable_value>::const_iterator iter = find(opt);
|
||||
if (iter == end() || iter->second.empty())
|
||||
if (iter == end() || iter->second.empty())
|
||||
{
|
||||
boost::throw_exception(required_option(display_opt));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Lastly, run notify actions.
|
||||
for (map<string, variable_value>::iterator k = begin();
|
||||
k != end();
|
||||
++k)
|
||||
for (map<string, variable_value>::iterator k = begin();
|
||||
k != end();
|
||||
++k)
|
||||
{
|
||||
/* Users might wish to use variables_map to store their own values
|
||||
that are not parsed, and therefore will not have value_semantics
|
||||
defined. Do not crash on such values. In multi-module programs,
|
||||
defined. Do no crash on such values. In multi-module programs,
|
||||
one module might add custom values, and the 'notify' function
|
||||
will be called after that, so we check that value_sematics is
|
||||
will be called after that, so we check that value_sematics is
|
||||
not NULL. See:
|
||||
https://svn.boost.org/trac/boost/ticket/2782
|
||||
*/
|
||||
if (k->second.m_value_semantic)
|
||||
k->second.m_value_semantic->notify(k->second.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
import testing ;
|
||||
|
||||
project
|
||||
: requirements
|
||||
<library>/boost//program_options
|
||||
<library>../build//boost_program_options
|
||||
<link>static
|
||||
<variant>debug
|
||||
|
||||
# <define>_GLIBCXX_CONCEPT_CHECKS
|
||||
# <define>_GLIBCXX_DEBUG
|
||||
;
|
||||
|
||||
|
||||
rule po-test ( source : input-file ? )
|
||||
{
|
||||
return
|
||||
[ run $(source) : : $(input-file) ]
|
||||
[ run $(source) : : $(input-file)
|
||||
: <link>shared
|
||||
: <link>shared <define>BOOST_PROGRAM_OPTIONS_DYN_LINK=1
|
||||
: $(source:B)_dll ]
|
||||
;
|
||||
}
|
||||
@@ -34,11 +33,7 @@ test-suite program_options :
|
||||
[ po-test unrecognized_test.cpp ]
|
||||
[ po-test required_test.cpp : required_test.cfg ]
|
||||
[ po-test exception_txt_test.cpp ]
|
||||
[ po-test optional_test.cpp ]
|
||||
[ run options_description_test.cpp : : : <rtti>off <define>BOOST_NO_RTTI <define>BOOST_NO_TYPEID : options_description_no_rtti_test ]
|
||||
;
|
||||
|
||||
|
||||
exe test_convert : test_convert.cpp ;
|
||||
|
||||
# `quick` target (for CI)
|
||||
run quick.cpp : --path=initial ;
|
||||
|
||||
@@ -77,7 +77,8 @@ void apply_syntax(options_description& desc,
|
||||
v = value<string>();
|
||||
s.resize(s.size()-1);
|
||||
} else if (*(s.end()-1) == '?') {
|
||||
v = value<string>()->implicit_value("default");
|
||||
//v = value<string>()->implicit();
|
||||
v = value<string>();
|
||||
s.resize(s.size()-1);
|
||||
} else if (*(s.end()-1) == '*') {
|
||||
v = value<vector<string> >()->multitoken();
|
||||
@@ -125,9 +126,9 @@ void test_cmdline(const char* syntax,
|
||||
try {
|
||||
vector<option> options = cmd.run();
|
||||
|
||||
for(unsigned j = 0; j < options.size(); ++j)
|
||||
for(unsigned i = 0; i < options.size(); ++i)
|
||||
{
|
||||
option opt = options[j];
|
||||
option opt = options[i];
|
||||
|
||||
if (opt.position_key != -1) {
|
||||
if (!result.empty())
|
||||
@@ -137,18 +138,18 @@ void test_cmdline(const char* syntax,
|
||||
if (!result.empty())
|
||||
result += " ";
|
||||
result += opt.string_key + ":";
|
||||
for (size_t k = 0; k < opt.value.size(); ++k) {
|
||||
if (k != 0)
|
||||
for (size_t j = 0; j < opt.value.size(); ++j) {
|
||||
if (j != 0)
|
||||
result += "-";
|
||||
result += opt.value[k];
|
||||
result += opt.value[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(unknown_option&) {
|
||||
catch(unknown_option& e) {
|
||||
status = s_unknown_option;
|
||||
}
|
||||
catch(ambiguous_option&) {
|
||||
catch(ambiguous_option& e) {
|
||||
status = s_ambiguous_option;
|
||||
}
|
||||
catch(invalid_command_line_syntax& e) {
|
||||
@@ -463,13 +464,11 @@ void test_additional_parser()
|
||||
desc.add_options()
|
||||
("response-file", value<string>(), "response file")
|
||||
("foo", value<int>(), "foo")
|
||||
("bar,baz", value<int>(), "bar")
|
||||
;
|
||||
|
||||
vector<string> input;
|
||||
input.push_back("@config");
|
||||
input.push_back("--foo=1");
|
||||
input.push_back("--baz=11");
|
||||
|
||||
cmdline cmd(input);
|
||||
cmd.set_options_description(desc);
|
||||
@@ -477,13 +476,11 @@ void test_additional_parser()
|
||||
|
||||
vector<option> result = cmd.run();
|
||||
|
||||
BOOST_REQUIRE(result.size() == 3);
|
||||
BOOST_REQUIRE(result.size() == 2);
|
||||
BOOST_CHECK_EQUAL(result[0].string_key, "response-file");
|
||||
BOOST_CHECK_EQUAL(result[0].value[0], "config");
|
||||
BOOST_CHECK_EQUAL(result[1].string_key, "foo");
|
||||
BOOST_CHECK_EQUAL(result[1].value[0], "1");
|
||||
BOOST_CHECK_EQUAL(result[2].string_key, "bar");
|
||||
BOOST_CHECK_EQUAL(result[2].value[0], "11");
|
||||
|
||||
// Test that invalid options returned by additional style
|
||||
// parser are detected.
|
||||
@@ -610,34 +607,6 @@ void test_unregistered()
|
||||
// It's not clear yet, so I'm leaving the decision till later.
|
||||
}
|
||||
|
||||
void test_implicit_value()
|
||||
{
|
||||
using namespace command_line_style;
|
||||
cmdline::style_t style;
|
||||
|
||||
style = cmdline::style_t(
|
||||
allow_long | long_allow_adjacent
|
||||
);
|
||||
|
||||
test_case test_cases1[] = {
|
||||
// 'bar' does not even look like option, so is consumed
|
||||
{"--foo bar", s_success, "foo:bar"},
|
||||
// '--bar' looks like option, and such option exists, so we don't consume this token
|
||||
{"--foo --bar", s_success, "foo: bar:"},
|
||||
// '--biz' looks like option, but does not match any existing one.
|
||||
// Presently this results in parse error, since
|
||||
// (1) in cmdline.cpp:finish_option, we only consume following tokens if they are
|
||||
// requires
|
||||
// (2) in cmdline.cpp:run, we let options consume following positional options
|
||||
// For --biz, an exception is thrown between 1 and 2.
|
||||
// We might want to fix that in future.
|
||||
{"--foo --biz", s_unknown_option, ""},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
test_cmdline("foo? bar?", style, test_cases1);
|
||||
}
|
||||
|
||||
int main(int /*ac*/, char** /*av*/)
|
||||
{
|
||||
test_long_options();
|
||||
@@ -650,7 +619,6 @@ int main(int /*ac*/, char** /*av*/)
|
||||
test_additional_parser();
|
||||
test_style_parser();
|
||||
test_unregistered();
|
||||
test_implicit_value();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -5,5 +5,5 @@ b = true
|
||||
|
||||
[m1]
|
||||
v1 = 1
|
||||
|
||||
v2 = 2
|
||||
v3 = 3
|
||||
|
||||
@@ -45,56 +45,6 @@ void test_ambiguous()
|
||||
}
|
||||
|
||||
|
||||
void test_ambiguous_long()
|
||||
{
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("cfgfile,c", value<string>()->multitoken(), "the config file")
|
||||
("output,c", value<string>(), "the output file")
|
||||
("output,o", value<string>(), "the output file")
|
||||
;
|
||||
|
||||
const char* cmdline[] = {"program", "--cfgfile", "file", "--output", "anotherfile"};
|
||||
|
||||
variables_map vm;
|
||||
try {
|
||||
store(parse_command_line(sizeof(cmdline)/sizeof(const char*),
|
||||
const_cast<char**>(cmdline), desc), vm);
|
||||
}
|
||||
catch (ambiguous_option& e)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(e.alternatives().size(), 2);
|
||||
BOOST_CHECK_EQUAL(e.get_option_name(), "--output");
|
||||
BOOST_CHECK_EQUAL(e.alternatives()[0], "output");
|
||||
BOOST_CHECK_EQUAL(e.alternatives()[1], "output");
|
||||
}
|
||||
}
|
||||
|
||||
void test_ambiguous_multiple_long_names()
|
||||
{
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("cfgfile,foo,c", value<string>()->multitoken(), "the config file")
|
||||
("output,foo,o", value<string>(), "the output file")
|
||||
;
|
||||
|
||||
const char* cmdline[] = {"program", "--foo", "file"};
|
||||
|
||||
variables_map vm;
|
||||
try {
|
||||
store(parse_command_line(sizeof(cmdline)/sizeof(const char*),
|
||||
const_cast<char**>(cmdline), desc), vm);
|
||||
}
|
||||
catch (ambiguous_option& e)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(e.alternatives().size(), 2);
|
||||
BOOST_CHECK_EQUAL(e.get_option_name(), "--foo");
|
||||
BOOST_CHECK_EQUAL(e.alternatives()[0], "cfgfile");
|
||||
BOOST_CHECK_EQUAL(e.alternatives()[1], "output");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void test_unknown_option()
|
||||
{
|
||||
@@ -150,6 +100,7 @@ void test_multiple_values()
|
||||
}
|
||||
|
||||
|
||||
|
||||
void test_multiple_occurrences()
|
||||
{
|
||||
options_description desc;
|
||||
@@ -158,67 +109,20 @@ void test_multiple_occurrences()
|
||||
;
|
||||
|
||||
const char* cmdline[] = {"program", "--cfgfile", "file", "-c", "anotherfile"};
|
||||
|
||||
|
||||
variables_map vm;
|
||||
try {
|
||||
store(parse_command_line(sizeof(cmdline)/sizeof(const char*),
|
||||
store(parse_command_line(sizeof(cmdline)/sizeof(const char*),
|
||||
const_cast<char**>(cmdline), desc), vm);
|
||||
notify(vm);
|
||||
}
|
||||
catch (multiple_occurrences& e)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(e.get_option_name(), "--cfgfile");
|
||||
BOOST_CHECK_EQUAL(e.get_option_name(), "--cfgfile");
|
||||
BOOST_CHECK_EQUAL(string(e.what()), "option '--cfgfile' cannot be specified more than once");
|
||||
}
|
||||
}
|
||||
|
||||
void test_multiple_occurrences_with_different_names()
|
||||
{
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("cfgfile,config-file,c", value<string>(), "the configfile")
|
||||
;
|
||||
|
||||
const char* cmdline[] = {"program", "--config-file", "file", "--cfgfile", "anotherfile"};
|
||||
|
||||
variables_map vm;
|
||||
try {
|
||||
store(parse_command_line(sizeof(cmdline)/sizeof(const char*),
|
||||
const_cast<char**>(cmdline), desc), vm);
|
||||
notify(vm);
|
||||
}
|
||||
catch (multiple_occurrences& e)
|
||||
{
|
||||
BOOST_CHECK( (e.get_option_name() == "--cfgfile") || (e.get_option_name() == "--config-file"));
|
||||
BOOST_CHECK(
|
||||
(string(e.what()) == "option '--cfgfile' cannot be specified more than once") ||
|
||||
(string(e.what()) == "option '--config-file' cannot be specified more than once")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_multiple_occurrences_with_non_key_names()
|
||||
{
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("cfgfile,config-file,c", value<string>(), "the configfile")
|
||||
;
|
||||
|
||||
const char* cmdline[] = {"program", "--config-file", "file", "-c", "anotherfile"};
|
||||
|
||||
variables_map vm;
|
||||
try {
|
||||
store(parse_command_line(sizeof(cmdline)/sizeof(const char*),
|
||||
const_cast<char**>(cmdline), desc), vm);
|
||||
notify(vm);
|
||||
}
|
||||
catch (multiple_occurrences& e)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(e.get_option_name(), "--cfgfile");
|
||||
BOOST_CHECK_EQUAL(string(e.what()), "option '--cfgfile' cannot be specified more than once");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_missing_value()
|
||||
@@ -250,13 +154,9 @@ void test_missing_value()
|
||||
int main(int /*ac*/, char** /*av*/)
|
||||
{
|
||||
test_ambiguous();
|
||||
test_ambiguous_long();
|
||||
test_ambiguous_multiple_long_names();
|
||||
test_unknown_option();
|
||||
test_multiple_values();
|
||||
test_multiple_occurrences();
|
||||
test_multiple_occurrences_with_different_names();
|
||||
test_multiple_occurrences_with_non_key_names();
|
||||
test_missing_value();
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -59,7 +59,7 @@ void test_each_exception_message(const string& test_description, const vector<co
|
||||
if (style == -1)
|
||||
store(parse_config_file(is, desc), vm);
|
||||
else
|
||||
store(parse_command_line(argv.size(), &argv[0], desc, style), vm);
|
||||
store(parse_command_line(argv.size(), argv.data(), desc, style), vm);
|
||||
notify(vm);
|
||||
}
|
||||
catch (EXCEPTION& e)
|
||||
@@ -152,7 +152,7 @@ void test_invalid_option_value_exception_msg()
|
||||
{
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("int-option,d", value< int >(), "An option taking an integer")
|
||||
("int-option,d", value< int >(), "An option taking an integer")
|
||||
;
|
||||
|
||||
vector<vector<const char*> > argv;
|
||||
@@ -308,7 +308,7 @@ void test_invalid_bool_value_exception_msg()
|
||||
{
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("bool_option,b", value< bool>(), "bool_option")
|
||||
("bool_option,b", value< bool>(), "bool_option")
|
||||
;
|
||||
|
||||
|
||||
@@ -620,27 +620,7 @@ void test_invalid_command_line_style_exception_msg()
|
||||
}
|
||||
}
|
||||
|
||||
void test_empty_value_inner(options_description &opts, variables_map& vm) {
|
||||
positional_options_description popts;
|
||||
opts.add_options()("foo", value<uint32_t>()->value_name("<time>")->required());
|
||||
popts.add("foo", 1);
|
||||
vector<string> tokens(1, "");
|
||||
parsed_options parsed = command_line_parser(tokens)
|
||||
.style(command_line_style::default_style & ~command_line_style::allow_guessing)
|
||||
.options(opts)
|
||||
.positional(popts)
|
||||
.run();
|
||||
store(parsed, vm);
|
||||
}
|
||||
|
||||
void test_empty_value() {
|
||||
// Test that passing empty token for an option that requires integer does not result
|
||||
// in out-of-range error in error reporting code.
|
||||
test_exception<invalid_option_value>(
|
||||
"test_empty_value",
|
||||
"the argument for option '--foo' is invalid",
|
||||
test_empty_value_inner);
|
||||
}
|
||||
|
||||
int main(int /*ac*/, char** /*av*/)
|
||||
{
|
||||
@@ -653,7 +633,6 @@ int main(int /*ac*/, char** /*av*/)
|
||||
test_multiple_values_not_allowed_exception_msg();
|
||||
test_required_option_exception_msg();
|
||||
test_at_least_one_value_required_exception_msg();
|
||||
test_empty_value();
|
||||
|
||||
string test_name;
|
||||
string expected_message;
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
// 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 <boost/optional.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "minitest.hpp"
|
||||
|
||||
std::vector<std::string> sv(const char* array[], unsigned size)
|
||||
{
|
||||
std::vector<std::string> r;
|
||||
for (unsigned i = 0; i < size; ++i)
|
||||
r.push_back(array[i]);
|
||||
return r;
|
||||
}
|
||||
|
||||
void test_optional()
|
||||
{
|
||||
boost::optional<int> foo, bar, baz;
|
||||
|
||||
po::options_description desc;
|
||||
desc.add_options()
|
||||
("foo,f", po::value(&foo), "")
|
||||
("bar,b", po::value(&bar), "")
|
||||
("baz,z", po::value(&baz), "")
|
||||
;
|
||||
|
||||
const char* cmdline1_[] = { "--foo=12", "--bar", "1"};
|
||||
std::vector<std::string> cmdline1 = sv(cmdline1_,
|
||||
sizeof(cmdline1_)/sizeof(const char*));
|
||||
po::variables_map vm;
|
||||
po::store(po::command_line_parser(cmdline1).options(desc).run(), vm);
|
||||
po::notify(vm);
|
||||
|
||||
BOOST_REQUIRE(!!foo);
|
||||
BOOST_CHECK(*foo == 12);
|
||||
|
||||
BOOST_REQUIRE(!!bar);
|
||||
BOOST_CHECK(*bar == 1);
|
||||
|
||||
BOOST_CHECK(!baz);
|
||||
}
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
test_optional();
|
||||
return 0;
|
||||
}
|
||||
@@ -25,7 +25,6 @@ void test_type()
|
||||
("bar", value<string>(), "")
|
||||
;
|
||||
|
||||
#ifndef BOOST_NO_RTTI
|
||||
const typed_value_base* b = dynamic_cast<const typed_value_base*>
|
||||
(desc.find("foo", false).semantic().get());
|
||||
BOOST_CHECK(b);
|
||||
@@ -35,7 +34,6 @@ void test_type()
|
||||
(desc.find("bar", false).semantic().get());
|
||||
BOOST_CHECK(b2);
|
||||
BOOST_CHECK(b2->value_type() == typeid(string));
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_approximation()
|
||||
@@ -74,61 +72,6 @@ void test_approximation()
|
||||
// BOOST_CHECK(*(++a.begin()) == "foo");
|
||||
}
|
||||
|
||||
void test_approximation_with_multiname_options()
|
||||
{
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("foo", new untyped_value())
|
||||
("fee", new untyped_value())
|
||||
("fe,baz", new untyped_value())
|
||||
("chroots,all-chroots", new untyped_value())
|
||||
("sessions,all-sessions", new untyped_value())
|
||||
("everything,all", new untyped_value())
|
||||
("qux,fo", new untyped_value())
|
||||
;
|
||||
|
||||
BOOST_CHECK_EQUAL(desc.find("fo", true).long_name(), "qux");
|
||||
|
||||
BOOST_CHECK_EQUAL(desc.find("all", true).long_name(), "everything");
|
||||
BOOST_CHECK_EQUAL(desc.find("all-ch", true).long_name(), "chroots");
|
||||
|
||||
BOOST_CHECK_EQUAL(desc.find("foo", false, false, false).long_names().second, 1u);
|
||||
BOOST_CHECK_EQUAL(desc.find("foo", false, false, false).long_names().first[0], "foo");
|
||||
|
||||
BOOST_CHECK_EQUAL(desc.find("fe", false, false, false).long_names().second, 2u);
|
||||
BOOST_CHECK_EQUAL(desc.find("fe", false, false, false).long_names().first[0], "fe");
|
||||
BOOST_CHECK_EQUAL(desc.find("baz", false, false, false).long_names().first[1], "baz");
|
||||
|
||||
BOOST_CHECK_EQUAL(desc.find("baz", false, false, false).long_names().second, 2u);
|
||||
BOOST_CHECK_EQUAL(desc.find("baz", false, false, false).long_names().first[0], "fizbaz");
|
||||
BOOST_CHECK_EQUAL(desc.find("baz", false, false, false).long_names().first[1], "baz");
|
||||
}
|
||||
|
||||
void test_long_names_for_option_description()
|
||||
{
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("foo", new untyped_value())
|
||||
("fe,baz", new untyped_value())
|
||||
("chroots,all-chroots", new untyped_value())
|
||||
("sessions,all-sessions", new untyped_value())
|
||||
("everything,all", new untyped_value())
|
||||
("qux,fo,q", new untyped_value())
|
||||
;
|
||||
|
||||
BOOST_CHECK_EQUAL(desc.find("foo", false, false, false).long_names().second, 1u);
|
||||
BOOST_CHECK_EQUAL(desc.find("foo", false, false, false).long_names().first[0], "foo");
|
||||
|
||||
BOOST_CHECK_EQUAL(desc.find("fe", false, false, false).long_names().second, 2u);
|
||||
BOOST_CHECK_EQUAL(desc.find("fe", false, false, false).long_names().first[0], "fe");
|
||||
BOOST_CHECK_EQUAL(desc.find("baz", false, false, false).long_names().first[1], "baz");
|
||||
|
||||
BOOST_CHECK_EQUAL(desc.find("qux", false, false, false).long_names().second, 2u);
|
||||
BOOST_CHECK_EQUAL(desc.find("qux", false, false, false).long_names().first[0], "qux");
|
||||
BOOST_CHECK_EQUAL(desc.find("qux", false, false, false).long_names().first[1], "fo");
|
||||
}
|
||||
|
||||
|
||||
void test_formatting()
|
||||
{
|
||||
// Long option descriptions used to crash on MSVC-8.0.
|
||||
@@ -179,21 +122,6 @@ void test_formatting()
|
||||
);
|
||||
}
|
||||
|
||||
void test_multiname_option_formatting()
|
||||
{
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("foo,bar", new untyped_value(), "a multiple-name option")
|
||||
;
|
||||
|
||||
stringstream ss;
|
||||
ss << desc;
|
||||
BOOST_CHECK_EQUAL(ss.str(),
|
||||
" --foo arg a multiple-name option\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void test_formatting_description_length()
|
||||
{
|
||||
{
|
||||
@@ -315,28 +243,12 @@ void test_value_name()
|
||||
);
|
||||
}
|
||||
|
||||
void test_multiname_key_and_switch_selection()
|
||||
{
|
||||
// cases:
|
||||
// foo,f -> f
|
||||
// foo, c -> c
|
||||
// foo,f,g -> g
|
||||
// f,g,h -> h
|
||||
// f,foo throws
|
||||
// foo,bar -> no switch
|
||||
// foo,f,bar -> no switch
|
||||
|
||||
// what about empty strings - consecutive ,'s ?
|
||||
}
|
||||
|
||||
int main(int, char* [])
|
||||
{
|
||||
test_type();
|
||||
test_approximation();
|
||||
test_long_names_for_option_description();
|
||||
test_formatting();
|
||||
test_multiname_key_and_switch_selection();
|
||||
test_multiname_option_formatting();
|
||||
test_formatting_description_length();
|
||||
test_long_default_value();
|
||||
test_word_wrapping();
|
||||
|
||||
@@ -16,7 +16,6 @@ using namespace boost;
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
using namespace std;
|
||||
|
||||
#if defined(__sun)
|
||||
@@ -71,18 +70,20 @@ pair<string, string> additional_parser(const std::string&)
|
||||
return pair<string, string>();
|
||||
}
|
||||
|
||||
namespace command_line {
|
||||
|
||||
#if 0
|
||||
// The following commented out blocks used to test parsing
|
||||
// command line without syntax specification behaviour.
|
||||
// It is disabled now and probably will never be enabled again:
|
||||
// it is not possible to figure out what command line means without
|
||||
// user's help.
|
||||
void test_parsing_without_specifying_options() {
|
||||
void test_command_line()
|
||||
{
|
||||
// The following commented out blocks used to test parsing
|
||||
// command line without syntax specification behaviour.
|
||||
// It is disabled now and probably will never be enabled again:
|
||||
// it is not possible to figure out what command line means without
|
||||
// user's help.
|
||||
#if 0
|
||||
char* cmdline1[] = { "--a", "--b=12", "-f", "-g4", "-", "file" };
|
||||
options_and_arguments a1 = parse_command_line(cmdline1,
|
||||
cmdline1 + sizeof(cmdline1) / sizeof(cmdline1[0]));
|
||||
|
||||
options_and_arguments a1 =
|
||||
parse_command_line(cmdline1,
|
||||
cmdline1 + sizeof(cmdline1)/sizeof(cmdline1[0]));
|
||||
|
||||
BOOST_REQUIRE(a1.options().size() == 4);
|
||||
BOOST_CHECK(a1.options()[0] == msp("a", ""));
|
||||
BOOST_CHECK(a1.options()[1] == msp("b", "12"));
|
||||
@@ -91,80 +92,71 @@ void test_parsing_without_specifying_options() {
|
||||
BOOST_REQUIRE(a1.arguments().size() == 2);
|
||||
BOOST_CHECK(a1.arguments()[0] == "-");
|
||||
BOOST_CHECK(a1.arguments()[1] == "file");
|
||||
|
||||
char* cmdline2[] = { "--a", "--", "file" };
|
||||
options_and_arguments a2 = parse_command_line(cmdline2,
|
||||
cmdline2 + sizeof(cmdline2) / sizeof(cmdline2[0]));
|
||||
|
||||
options_and_arguments a2 =
|
||||
parse_command_line(cmdline2,
|
||||
cmdline2 + sizeof(cmdline2)/sizeof(cmdline2[0]));
|
||||
|
||||
BOOST_REQUIRE(a2.options().size() == 1);
|
||||
BOOST_CHECK(a2.options()[0] == msp("a", ""));
|
||||
BOOST_CHECK(a2.arguments().size() == 1);
|
||||
BOOST_CHECK(a2.arguments()[0] == "file");
|
||||
}
|
||||
#endif
|
||||
|
||||
void test_many_different_options() {
|
||||
#endif
|
||||
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("foo,f", new untyped_value(), "")
|
||||
( // Explicit qualification is a workaround for vc6
|
||||
"bar,b", po::value<std::string>(), "")
|
||||
("car,voiture", new untyped_value())
|
||||
("dog,dawg", new untyped_value())
|
||||
// Explicit qualification is a workaround for vc6
|
||||
("bar,b", po::value<std::string>(), "")
|
||||
("baz", new untyped_value())
|
||||
("plug*", new untyped_value());
|
||||
("plug*", new untyped_value())
|
||||
;
|
||||
const char* cmdline3_[] = { "--foo=12", "-f4", "--bar=11", "-b4",
|
||||
"--voiture=15", "--dawg=16", "--dog=17", "--plug3=10" };
|
||||
"--plug3=10"};
|
||||
vector<string> cmdline3 = sv(cmdline3_,
|
||||
sizeof(cmdline3_) / sizeof(const char*));
|
||||
vector<option> a3 =
|
||||
command_line_parser(cmdline3).options(desc).run().options;
|
||||
BOOST_CHECK_EQUAL(a3.size(), 8u);
|
||||
sizeof(cmdline3_)/sizeof(const char*));
|
||||
vector<option> a3 =
|
||||
command_line_parser(cmdline3).options(desc).run().options;
|
||||
|
||||
BOOST_CHECK_EQUAL(a3.size(), 5u);
|
||||
|
||||
check_value(a3[0], "foo", "12");
|
||||
check_value(a3[1], "foo", "4");
|
||||
check_value(a3[2], "bar", "11");
|
||||
check_value(a3[3], "bar", "4");
|
||||
check_value(a3[4], "car", "15");
|
||||
check_value(a3[5], "dog", "16");
|
||||
check_value(a3[6], "dog", "17");
|
||||
check_value(a3[7], "plug3", "10");
|
||||
check_value(a3[4], "plug3", "10");
|
||||
|
||||
// Regression test: check that '0' as style is interpreted as
|
||||
// 'default_style'
|
||||
vector<option> a4 = parse_command_line(
|
||||
sizeof(cmdline3_) / sizeof(const char*), cmdline3_, desc, 0,
|
||||
additional_parser).options;
|
||||
// The default style is unix-style, where the first argument on the command-line
|
||||
// is the name of a binary, not an option value, so that should be ignored
|
||||
BOOST_CHECK_EQUAL(a4.size(), 7u);
|
||||
vector<option> a4 =
|
||||
parse_command_line(sizeof(cmdline3_)/sizeof(const char*), cmdline3_,
|
||||
desc, 0, additional_parser).options;
|
||||
|
||||
BOOST_CHECK_EQUAL(a4.size(), 4u);
|
||||
check_value(a4[0], "foo", "4");
|
||||
check_value(a4[1], "bar", "11");
|
||||
check_value(a4[2], "bar", "4");
|
||||
check_value(a4[3], "car", "15");
|
||||
check_value(a4[4], "dog", "16");
|
||||
check_value(a4[5], "dog", "17");
|
||||
check_value(a4[6], "plug3", "10");
|
||||
}
|
||||
|
||||
void test_not_crashing_with_empty_string_values() {
|
||||
// Check that we don't crash on empty values of type 'string'
|
||||
const char* cmdline4[] = { "", "--open", "" };
|
||||
const char* cmdline4[] = {"", "--open", ""};
|
||||
options_description desc2;
|
||||
desc2.add_options()("open", po::value<string>());
|
||||
desc2.add_options()
|
||||
("open", po::value<string>())
|
||||
;
|
||||
variables_map vm;
|
||||
po::store(
|
||||
po::parse_command_line(sizeof(cmdline4) / sizeof(const char*),
|
||||
const_cast<char**>(cmdline4), desc2), vm);
|
||||
}
|
||||
po::store(po::parse_command_line(sizeof(cmdline4)/sizeof(const char*), const_cast<char**>(cmdline4), desc2), vm);
|
||||
|
||||
void test_multitoken() {
|
||||
const char* cmdline5[] = { "", "-p7", "-o", "1", "2", "3", "-x8" };
|
||||
const char* cmdline5[] = {"", "-p7", "-o", "1", "2", "3", "-x8"};
|
||||
options_description desc3;
|
||||
desc3.add_options()
|
||||
(",p", po::value<string>())
|
||||
(",o", po::value<string>()->multitoken())
|
||||
(",x", po::value<string>());
|
||||
vector<option> a5 = parse_command_line(
|
||||
sizeof(cmdline5) / sizeof(const char*),
|
||||
const_cast<char**>(cmdline5), desc3, 0, additional_parser).options;
|
||||
(",x", po::value<string>())
|
||||
;
|
||||
vector<option> a5 =
|
||||
parse_command_line(sizeof(cmdline5)/sizeof(const char*), const_cast<char**>(cmdline5),
|
||||
desc3, 0, additional_parser).options;
|
||||
BOOST_CHECK_EQUAL(a5.size(), 3u);
|
||||
check_value(a5[0], "-p", "7");
|
||||
BOOST_REQUIRE(a5[1].value.size() == 3);
|
||||
@@ -172,60 +164,28 @@ void test_multitoken() {
|
||||
BOOST_CHECK_EQUAL(a5[1].value[0], "1");
|
||||
BOOST_CHECK_EQUAL(a5[1].value[1], "2");
|
||||
BOOST_CHECK_EQUAL(a5[1].value[2], "3");
|
||||
check_value(a5[2], "-x", "8");
|
||||
}
|
||||
|
||||
void test_multitoken_and_multiname() {
|
||||
const char* cmdline[] = { "program", "-fone", "-b", "two", "--foo", "three", "four", "-zfive", "--fee", "six" };
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("bar,b", po::value<string>())
|
||||
("foo,fee,f", po::value<string>()->multitoken())
|
||||
("fizbaz,baz,z", po::value<string>());
|
||||
|
||||
vector<option> parsed_options = parse_command_line(
|
||||
sizeof(cmdline) / sizeof(const char*),
|
||||
const_cast<char**>(cmdline), desc, 0, additional_parser).options;
|
||||
|
||||
BOOST_CHECK_EQUAL(parsed_options.size(), 5u);
|
||||
check_value(parsed_options[0], "foo", "one");
|
||||
check_value(parsed_options[1], "bar", "two");
|
||||
BOOST_CHECK_EQUAL(parsed_options[2].string_key, "foo");
|
||||
BOOST_REQUIRE(parsed_options[2].value.size() == 2);
|
||||
BOOST_CHECK_EQUAL(parsed_options[2].value[0], "three");
|
||||
BOOST_CHECK_EQUAL(parsed_options[2].value[1], "four");
|
||||
check_value(parsed_options[3], "fizbaz", "five");
|
||||
check_value(parsed_options[4], "foo", "six");
|
||||
|
||||
const char* cmdline_2[] = { "program", "-fone", "-b", "two", "--fee", "three", "four", "-zfive", "--foo", "six" };
|
||||
|
||||
parsed_options = parse_command_line(
|
||||
sizeof(cmdline_2) / sizeof(const char*),
|
||||
const_cast<char**>(cmdline_2), desc, 0, additional_parser).options;
|
||||
|
||||
BOOST_CHECK_EQUAL(parsed_options.size(), 5u);
|
||||
check_value(parsed_options[0], "foo", "one");
|
||||
check_value(parsed_options[1], "bar", "two");
|
||||
BOOST_CHECK_EQUAL(parsed_options[2].string_key, "foo");
|
||||
BOOST_REQUIRE(parsed_options[2].value.size() == 2);
|
||||
BOOST_CHECK_EQUAL(parsed_options[2].value[0], "three");
|
||||
BOOST_CHECK_EQUAL(parsed_options[2].value[1], "four");
|
||||
check_value(parsed_options[3], "fizbaz", "five");
|
||||
check_value(parsed_options[4], "foo", "six");
|
||||
}
|
||||
check_value(a5[2], "-x", "8");
|
||||
|
||||
|
||||
void test_multitoken_vector_option() {
|
||||
po::options_description desc4("");
|
||||
po::options_description desc4( "" );
|
||||
desc4.add_options()
|
||||
("multitoken,multi-token,m", po::value<std::vector<std::string> >()->multitoken(), "values")
|
||||
("file", po::value<std::string>(), "the file to process");
|
||||
( "multitoken,m",
|
||||
po::value< std::vector< std::string > >()->multitoken(),
|
||||
"values"
|
||||
)
|
||||
( "file",
|
||||
po::value< std::string >(),
|
||||
"the file to process"
|
||||
)
|
||||
;
|
||||
|
||||
po::positional_options_description p;
|
||||
p.add("file", 1);
|
||||
const char* cmdline6[] = { "", "-m", "token1", "token2", "--", "some_file" };
|
||||
vector<option> a6 =
|
||||
command_line_parser(sizeof(cmdline6) / sizeof(const char*),
|
||||
const_cast<char**>(cmdline6)).options(desc4).positional(p).run().options;
|
||||
p.add( "file", 1 );
|
||||
|
||||
const char* cmdline6[] = {"", "-m", "token1", "token2", "--", "some_file"};
|
||||
vector<option> a6 =
|
||||
command_line_parser(sizeof(cmdline6)/sizeof(const char*), const_cast<char**>(cmdline6)).options(desc4).positional(p)
|
||||
.run().options;
|
||||
BOOST_CHECK_EQUAL(a6.size(), 2u);
|
||||
BOOST_REQUIRE(a6[0].value.size() == 2);
|
||||
BOOST_CHECK_EQUAL(a6[0].string_key, "multitoken");
|
||||
@@ -236,21 +196,6 @@ void test_multitoken_vector_option() {
|
||||
BOOST_CHECK_EQUAL(a6[1].value[0], "some_file");
|
||||
}
|
||||
|
||||
} // namespace command_line
|
||||
|
||||
void test_command_line()
|
||||
{
|
||||
#if 0
|
||||
command_line::test_parsing_without_specifying_options();
|
||||
#endif
|
||||
command_line::test_many_different_options();
|
||||
// Check that we don't crash on empty values of type 'string'
|
||||
command_line::test_not_crashing_with_empty_string_values();
|
||||
command_line::test_multitoken();
|
||||
command_line::test_multitoken_vector_option();
|
||||
command_line::test_multitoken_and_multiname();
|
||||
}
|
||||
|
||||
void test_config_file(const char* config_file)
|
||||
{
|
||||
options_description desc;
|
||||
@@ -261,7 +206,6 @@ void test_config_file(const char* config_file)
|
||||
("plug*", new untyped_value)
|
||||
("m1.v1", new untyped_value)
|
||||
("m1.v2", new untyped_value)
|
||||
("m1.v3,alias3", new untyped_value)
|
||||
("b", bool_switch())
|
||||
;
|
||||
|
||||
@@ -274,30 +218,27 @@ void test_config_file(const char* config_file)
|
||||
"v1 = 1\n"
|
||||
"\n"
|
||||
"v2 = 2\n"
|
||||
"v3 = 3\n"
|
||||
;
|
||||
|
||||
stringstream ss(content1);
|
||||
vector<option> a1 = parse_config_file(ss, desc).options;
|
||||
BOOST_REQUIRE(a1.size() == 7);
|
||||
BOOST_REQUIRE(a1.size() == 6);
|
||||
check_value(a1[0], "gv1", "0");
|
||||
check_value(a1[1], "empty_value", "");
|
||||
check_value(a1[2], "plug3", "7");
|
||||
check_value(a1[3], "b", "true");
|
||||
check_value(a1[4], "m1.v1", "1");
|
||||
check_value(a1[5], "m1.v2", "2");
|
||||
check_value(a1[6], "m1.v3", "3");
|
||||
|
||||
// same test, but now options come from file
|
||||
vector<option> a2 = parse_config_file<char>(config_file, desc).options;
|
||||
BOOST_REQUIRE(a2.size() == 7);
|
||||
BOOST_REQUIRE(a2.size() == 6);
|
||||
check_value(a2[0], "gv1", "0");
|
||||
check_value(a2[1], "empty_value", "");
|
||||
check_value(a2[2], "plug3", "7");
|
||||
check_value(a2[3], "b", "true");
|
||||
check_value(a2[4], "m1.v1", "1");
|
||||
check_value(a2[5], "m1.v2", "2");
|
||||
check_value(a2[6], "m1.v3", "3");
|
||||
}
|
||||
|
||||
void test_environment()
|
||||
@@ -308,7 +249,7 @@ void test_environment()
|
||||
("bar", new untyped_value, "")
|
||||
;
|
||||
|
||||
#if (defined(_WIN32) && ! defined(__BORLANDC__)) || (defined(__CYGWIN__))
|
||||
#if defined(_WIN32) && ! defined(__BORLANDC__)
|
||||
_putenv("PO_TEST_FOO=1");
|
||||
#else
|
||||
putenv(const_cast<char*>("PO_TEST_FOO=1"));
|
||||
@@ -316,9 +257,9 @@ void test_environment()
|
||||
parsed_options p = parse_environment(desc, "PO_TEST_");
|
||||
|
||||
BOOST_REQUIRE(p.options.size() == 1);
|
||||
BOOST_CHECK (p.options[0].string_key == "foo");
|
||||
BOOST_CHECK(p.options[0].string_key == "foo");
|
||||
BOOST_REQUIRE(p.options[0].value.size() == 1);
|
||||
BOOST_CHECK (p.options[0].value[0] == "1");
|
||||
BOOST_CHECK(p.options[0].value[0] == "1");
|
||||
|
||||
//TODO: since 'bar' does not allow a value, it cannot appear in environemt,
|
||||
// which already has a value.
|
||||
@@ -375,8 +316,6 @@ void test_unregistered()
|
||||
check_value(a3[1], "m1.v1", "1");
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int, char* av[])
|
||||
{
|
||||
test_command_line();
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
|
||||
// Copyright 2017 Peter Dimov.
|
||||
//
|
||||
// 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
|
||||
|
||||
// See library home page at http://www.boost.org/libs/program_options
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
namespace po = boost::program_options;
|
||||
|
||||
int main( int argc, char const* argv[] )
|
||||
{
|
||||
po::options_description desc( "Allowed options" );
|
||||
|
||||
desc.add_options()
|
||||
( "path,p", po::value<std::string>(), "set initial path" )
|
||||
;
|
||||
|
||||
po::variables_map vm;
|
||||
|
||||
try
|
||||
{
|
||||
po::store( po::parse_command_line( argc, argv, desc ), vm );
|
||||
po::notify( vm );
|
||||
}
|
||||
catch( std::exception const & x )
|
||||
{
|
||||
std::cerr << "Error: " << x.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string p;
|
||||
|
||||
if( vm.count( "path" ) )
|
||||
{
|
||||
p = vm[ "path" ].as<std::string>();
|
||||
}
|
||||
|
||||
std::string expected( "initial" );
|
||||
|
||||
BOOST_TEST_EQ( p, expected );
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -23,36 +23,36 @@ void required_throw_test()
|
||||
;
|
||||
|
||||
variables_map vm;
|
||||
bool thrown = false;
|
||||
bool throwed = false;
|
||||
{
|
||||
// This test must throw exception
|
||||
string cmdline = "prg -f file.txt";
|
||||
vector< string > tokens = split_unix(cmdline);
|
||||
thrown = false;
|
||||
throwed = false;
|
||||
try {
|
||||
store(command_line_parser(tokens).options(opts).run(), vm);
|
||||
notify(vm);
|
||||
}
|
||||
catch (required_option& e) {
|
||||
BOOST_CHECK_EQUAL(e.what(), string("the option '--cfgfile' is required but missing"));
|
||||
thrown = true;
|
||||
throwed = true;
|
||||
}
|
||||
BOOST_CHECK(thrown);
|
||||
BOOST_CHECK(throwed);
|
||||
}
|
||||
|
||||
{
|
||||
// This test mustn't throw exception
|
||||
string cmdline = "prg -c config.txt";
|
||||
vector< string > tokens = split_unix(cmdline);
|
||||
thrown = false;
|
||||
throwed = false;
|
||||
try {
|
||||
store(command_line_parser(tokens).options(opts).run(), vm);
|
||||
notify(vm);
|
||||
}
|
||||
catch (required_option& e) {
|
||||
thrown = true;
|
||||
throwed = true;
|
||||
}
|
||||
BOOST_CHECK(!thrown);
|
||||
BOOST_CHECK(!throwed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,12 +67,12 @@ void simple_required_test(const char* config_file)
|
||||
;
|
||||
|
||||
variables_map vm;
|
||||
bool thrown = false;
|
||||
bool throwed = false;
|
||||
{
|
||||
// This test must throw exception
|
||||
string cmdline = "prg -f file.txt";
|
||||
vector< string > tokens = split_unix(cmdline);
|
||||
thrown = false;
|
||||
throwed = false;
|
||||
try {
|
||||
// options coming from different sources
|
||||
store(command_line_parser(tokens).options(opts).run(), vm);
|
||||
@@ -80,35 +80,9 @@ void simple_required_test(const char* config_file)
|
||||
notify(vm);
|
||||
}
|
||||
catch (required_option& e) {
|
||||
thrown = true;
|
||||
throwed = true;
|
||||
}
|
||||
BOOST_CHECK(!thrown);
|
||||
}
|
||||
}
|
||||
|
||||
void multiname_required_test()
|
||||
{
|
||||
options_description opts;
|
||||
opts.add_options()
|
||||
("foo,bar", value<string>()->required(), "the foo")
|
||||
;
|
||||
|
||||
variables_map vm;
|
||||
bool thrown = false;
|
||||
{
|
||||
// This test must throw exception
|
||||
string cmdline = "prg --bar file.txt";
|
||||
vector< string > tokens = split_unix(cmdline);
|
||||
thrown = false;
|
||||
try {
|
||||
// options coming from different sources
|
||||
store(command_line_parser(tokens).options(opts).run(), vm);
|
||||
notify(vm);
|
||||
}
|
||||
catch (required_option& e) {
|
||||
thrown = true;
|
||||
}
|
||||
BOOST_CHECK(!thrown);
|
||||
BOOST_CHECK(!throwed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +92,6 @@ int main(int /*argc*/, char* av[])
|
||||
{
|
||||
required_throw_test();
|
||||
simple_required_test(av[1]);
|
||||
multiname_required_test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ void test_command_line()
|
||||
// Explicit qualification is a workaround for vc6
|
||||
("bar,b", po::value<std::string>(), "")
|
||||
("baz", new untyped_value())
|
||||
("qux,plug*", new untyped_value())
|
||||
("plug*", new untyped_value())
|
||||
;
|
||||
|
||||
const wchar_t* cmdline4_[] = { L"--foo=1\u0FF52", L"-f4", L"--bar=11",
|
||||
@@ -126,7 +126,6 @@ void test_command_line()
|
||||
check_value(a4[0], "foo", L"1\u0FF52");
|
||||
check_value(a4[1], "foo", L"4");
|
||||
check_value(a4[2], "bar", L"11");
|
||||
check_value(a4[4], "qux", L"10");
|
||||
}
|
||||
|
||||
// Since we've already tested conversion between parser encoding and
|
||||
|
||||
Reference in New Issue
Block a user