Compare commits

..

1 Commits

Author SHA1 Message Date
Beman Dawes
afb1078c1c Release 1.43.0
[SVN r61817]
2010-05-06 13:21:09 +00:00
75 changed files with 981 additions and 5115 deletions

View File

@@ -1,3 +0,0 @@
fixes:
- home/travis/build/*/boost-root/boost/::include/boost/
- home/travis/build/*/boost-root/libs/*/src/::src/

View File

@@ -1,609 +0,0 @@
name: CI
on:
pull_request:
push:
branches:
- master
- develop
- feature/**
env:
UBSAN_OPTIONS: print_stacktrace=1
jobs:
posix:
strategy:
fail-fast: false
matrix:
include:
- toolset: gcc-4.8
cxxstd: "11"
os: ubuntu-latest
container: ubuntu:18.04
install: g++-4.8
- toolset: gcc-5
cxxstd: "11,14,1z"
os: ubuntu-latest
container: ubuntu:18.04
install: g++-5
- toolset: gcc-6
cxxstd: "11,14,1z"
os: ubuntu-latest
container: ubuntu:18.04
install: g++-6
- toolset: gcc-7
cxxstd: "11,14,17"
os: ubuntu-20.04
install: g++-7
- toolset: gcc-8
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: g++-8
- toolset: gcc-9
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
- toolset: gcc-10
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: g++-10
- toolset: gcc-11
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: g++-11
- toolset: gcc-12
cxxstd: "11,14,17,20,2b"
os: ubuntu-22.04
install: g++-12
- toolset: gcc-13
cxxstd: "11,14,17,20,2b"
os: ubuntu-latest
container: ubuntu:23.04
install: g++-13
- toolset: clang
compiler: clang++-3.9
cxxstd: "11,14"
os: ubuntu-latest
container: ubuntu:18.04
install: clang-3.9
- toolset: clang
compiler: clang++-4.0
cxxstd: "11,14"
os: ubuntu-latest
container: ubuntu:18.04
install: clang-4.0
- toolset: clang
compiler: clang++-5.0
cxxstd: "11,14,1z"
os: ubuntu-latest
container: ubuntu:18.04
install: clang-5.0
- toolset: clang
compiler: clang++-6.0
cxxstd: "11,14,17"
os: ubuntu-20.04
install: clang-6.0
- toolset: clang
compiler: clang++-7
cxxstd: "11,14,17"
os: ubuntu-20.04
install: clang-7
- toolset: clang
compiler: clang++-8
cxxstd: "11,14,17"
os: ubuntu-20.04
install: clang-8
- toolset: clang
compiler: clang++-9
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: clang-9
- toolset: clang
compiler: clang++-10
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: clang-10
- toolset: clang
compiler: clang++-11
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: clang-11
- toolset: clang
compiler: clang++-12
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: clang-12
- toolset: clang
compiler: clang++-13
cxxstd: "11,14,17,20,2b"
container: ubuntu:22.04
os: ubuntu-latest
install: clang-13
- toolset: clang
compiler: clang++-14
cxxstd: "11,14,17,20,2b"
container: ubuntu:22.04
os: ubuntu-latest
install: clang-14
- toolset: clang
compiler: clang++-15
cxxstd: "11,14,17,20,2b"
container: ubuntu:22.04
os: ubuntu-latest
install: clang-15
- toolset: clang
compiler: clang++-16
cxxstd: "11,14,17,20,2b"
container: ubuntu:23.04
os: ubuntu-latest
install: clang-16
- toolset: clang
compiler: clang++-17
cxxstd: "11,14,17,20,2b"
container: ubuntu:23.10
os: ubuntu-latest
install: clang-17
- toolset: clang
cxxstd: "11,14,17,2a"
os: macos-11
- toolset: clang
cxxstd: "11,14,17,20,2b"
os: macos-12
- toolset: clang
cxxstd: "11,14,17,20,2b"
os: macos-13
runs-on: ${{matrix.os}}
container: ${{matrix.container}}
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v3
- name: Setup container environment
if: matrix.container
run: |
apt-get update
apt-get -y install sudo python3 git g++
- name: Install packages
if: matrix.install
run: |
sudo apt-get update
sudo apt-get -y install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python3 tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
./bootstrap.sh
./b2 -d0 headers
- name: Create user-config.jam
if: matrix.compiler
run: |
echo "using ${{matrix.toolset}} : : ${{matrix.compiler}} ;" > ~/user-config.jam
- name: Run tests
run: |
cd ../boost-root
./b2 -j3 libs/$LIBRARY/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} variant=debug,release
windows:
strategy:
fail-fast: false
matrix:
include:
- toolset: msvc-14.0
cxxstd: "14,latest"
addrmd: 32,64
os: windows-2019
- toolset: msvc-14.2
cxxstd: "14,17,20,latest"
addrmd: 32,64
os: windows-2019
- toolset: msvc-14.3
cxxstd: "14,17,20,latest"
addrmd: 32,64
os: windows-2022
- toolset: clang-win
cxxstd: "14,17,20,latest"
addrmd: 32,64
os: windows-2022
- toolset: gcc
cxxstd: "11,14,17,2a"
addrmd: 64
os: windows-2019
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v4
- name: Setup Boost
shell: cmd
run: |
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
echo LIBRARY: %LIBRARY%
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
echo GITHUB_REF: %GITHUB_REF%
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
set BOOST_BRANCH=develop
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
echo BOOST_BRANCH: %BOOST_BRANCH%
cd ..
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
cmd /c bootstrap
b2 -d0 headers
- name: Run tests
shell: cmd
run: |
cd ../boost-root
b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release embed-manifest-via=linker
posix-cmake-subdir:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: macos-11
- os: macos-12
- os: macos-13
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v4
- name: Install packages
if: matrix.install
run: sudo apt-get -y install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
- name: Use library with add_subdirectory
run: |
cd ../boost-root/libs/$LIBRARY/test/cmake_subdir_test
mkdir __build__ && cd __build__
cmake ..
cmake --build .
ctest --output-on-failure --no-tests=error
posix-cmake-install:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: macos-11
- os: macos-12
- os: macos-13
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v4
- name: Install packages
if: matrix.install
run: sudo apt-get -y install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
- name: Configure
run: |
cd ../boost-root
mkdir __build__ && cd __build__
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DCMAKE_INSTALL_PREFIX=~/.local ..
- name: Install
run: |
cd ../boost-root/__build__
cmake --build . --target install
- name: Use the installed library
run: |
cd ../boost-root/libs/$LIBRARY/test/cmake_install_test && mkdir __build__ && cd __build__
cmake -DCMAKE_INSTALL_PREFIX=~/.local ..
cmake --build .
ctest --output-on-failure --no-tests=error
posix-cmake-test:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: macos-11
- os: macos-12
- os: macos-13
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v4
- name: Install packages
if: matrix.install
run: sudo apt-get -y install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
- name: Configure
run: |
cd ../boost-root
mkdir __build__ && cd __build__
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DBUILD_TESTING=ON ..
- name: Build tests
run: |
cd ../boost-root/__build__
cmake --build . --target tests
- name: Run tests
run: |
cd ../boost-root/__build__
ctest --output-on-failure --no-tests=error
windows-cmake-subdir:
strategy:
fail-fast: false
matrix:
include:
- os: windows-2019
- os: windows-2022
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v4
- name: Setup Boost
shell: cmd
run: |
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
echo LIBRARY: %LIBRARY%
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
echo GITHUB_REF: %GITHUB_REF%
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
set BOOST_BRANCH=develop
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
echo BOOST_BRANCH: %BOOST_BRANCH%
cd ..
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
- name: Use library with add_subdirectory (Debug)
shell: cmd
run: |
cd ../boost-root/libs/%LIBRARY%/test/cmake_subdir_test
mkdir __build__ && cd __build__
cmake ..
cmake --build . --config Debug
ctest --output-on-failure --no-tests=error -C Debug
- name: Use library with add_subdirectory (Release)
shell: cmd
run: |
cd ../boost-root/libs/%LIBRARY%/test/cmake_subdir_test/__build__
cmake --build . --config Release
ctest --output-on-failure --no-tests=error -C Release
windows-cmake-install:
strategy:
fail-fast: false
matrix:
include:
- os: windows-2019
- os: windows-2022
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v4
- name: Setup Boost
shell: cmd
run: |
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
echo LIBRARY: %LIBRARY%
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
echo GITHUB_REF: %GITHUB_REF%
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
set BOOST_BRANCH=develop
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
echo BOOST_BRANCH: %BOOST_BRANCH%
cd ..
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
- name: Configure
shell: cmd
run: |
cd ../boost-root
mkdir __build__ && cd __build__
cmake -DBOOST_INCLUDE_LIBRARIES=%LIBRARY% -DCMAKE_INSTALL_PREFIX=C:/cmake-prefix ..
- name: Install (Debug)
shell: cmd
run: |
cd ../boost-root/__build__
cmake --build . --target install --config Debug
- name: Install (Release)
shell: cmd
run: |
cd ../boost-root/__build__
cmake --build . --target install --config Release
- name: Use the installed library (Debug)
shell: cmd
run: |
cd ../boost-root/libs/%LIBRARY%/test/cmake_install_test && mkdir __build__ && cd __build__
cmake -DCMAKE_INSTALL_PREFIX=C:/cmake-prefix ..
cmake --build . --config Debug
ctest --output-on-failure --no-tests=error -C Debug
- name: Use the installed library (Release)
shell: cmd
run: |
cd ../boost-root/libs/%LIBRARY%/test/cmake_install_test/__build__
cmake --build . --config Release
ctest --output-on-failure --no-tests=error -C Release
windows-cmake-test:
strategy:
fail-fast: false
matrix:
include:
- os: windows-2019
- os: windows-2022
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v4
- name: Setup Boost
shell: cmd
run: |
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
echo LIBRARY: %LIBRARY%
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
echo GITHUB_REF: %GITHUB_REF%
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
set BOOST_BRANCH=develop
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
echo BOOST_BRANCH: %BOOST_BRANCH%
cd ..
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
- name: Configure
shell: cmd
run: |
cd ../boost-root
mkdir __build__ && cd __build__
cmake -DBOOST_INCLUDE_LIBRARIES=%LIBRARY% -DBUILD_TESTING=ON ..
- name: Build tests (Debug)
shell: cmd
run: |
cd ../boost-root/__build__
cmake --build . --target tests --config Debug
- name: Run tests (Debug)
shell: cmd
run: |
cd ../boost-root/__build__
ctest --output-on-failure --no-tests=error -C Debug
- name: Build tests (Release)
shell: cmd
run: |
cd ../boost-root/__build__
cmake --build . --target tests --config Release
- name: Run tests (Release)
shell: cmd
run: |
cd ../boost-root/__build__
ctest --output-on-failure --no-tests=error -C Release

View File

@@ -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

View File

@@ -1,63 +0,0 @@
# Generated by `boostdep --cmake program_options`
# Copyright 2020, 2021 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
cmake_minimum_required(VERSION 3.8...3.20)
project(boost_program_options VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
add_library(boost_program_options
src/cmdline.cpp
src/config_file.cpp
src/convert.cpp
src/options_description.cpp
src/parsers.cpp
src/positional_options.cpp
src/split.cpp
src/utf8_codecvt_facet.cpp
src/value_semantic.cpp
src/variables_map.cpp
src/winmain.cpp
)
add_library(Boost::program_options ALIAS boost_program_options)
target_include_directories(boost_program_options PUBLIC include)
target_link_libraries(boost_program_options
PUBLIC
Boost::any
Boost::config
Boost::core
Boost::detail
Boost::function
Boost::iterator
Boost::lexical_cast
Boost::smart_ptr
Boost::static_assert
Boost::throw_exception
Boost::type_traits
PRIVATE
Boost::bind
Boost::tokenizer
)
target_compile_features(boost_program_options PUBLIC cxx_std_11)
target_compile_definitions(boost_program_options
PUBLIC BOOST_PROGRAM_OPTIONS_NO_LIB
PRIVATE BOOST_PROGRAM_OPTIONS_SOURCE
)
if(BUILD_SHARED_LIBS)
target_compile_definitions(boost_program_options PUBLIC BOOST_PROGRAM_OPTIONS_DYN_LINK)
else()
target_compile_definitions(boost_program_options PUBLIC BOOST_PROGRAM_OPTIONS_STATIC_LINK)
endif()
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
add_subdirectory(test)
endif()

11
Jamfile
View File

@@ -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 ;

View File

@@ -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) | [![Build Status](https://travis-ci.org/boostorg/program_options.svg?branch=master)](https://travis-ci.org/boostorg/program_options) | [![Build status](https://ci.appveyor.com/api/projects/status/e0quisadwh1v7ok5/branch/master?svg=true)](https://ci.appveyor.com/project/vprus/program-options/branch/master) | [![codecov](https://codecov.io/gh/boostorg/program_options/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/program_options/branch/master) | [![Deps](https://img.shields.io/badge/deps-master-brightgreen.svg)](https://pdimov.github.io/boostdep-report/master/program_options.html) | [![Documentation](https://img.shields.io/badge/docs-master-brightgreen.svg)](http://www.boost.org/doc/libs/master/doc/html/program_options.html) | [![Enter the Matrix](https://img.shields.io/badge/matrix-master-brightgreen.svg)](http://www.boost.org/development/tests/master/developer/program_options.html)
|[`develop`](https://github.com/boostorg/program_options/tree/develop) | [![Build Status](https://travis-ci.org/boostorg/program_options.svg?branch=develop)](https://travis-ci.org/boostorg/program_options) | [![Build status](https://ci.appveyor.com/api/projects/status/e0quisadwh1v7ok5/branch/develop?svg=true)](https://ci.appveyor.com/project/vprus/program-options/branch/develop) | [![codecov](https://codecov.io/gh/boostorg/program_options/branch/develop/graph/badge.svg)](https://codecov.io/gh/boostorg/program_options/branch/develop) | [![Deps](https://img.shields.io/badge/deps-develop-brightgreen.svg)](https://pdimov.github.io/boostdep-report/develop/program_options.html) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/develop/doc/html/program_options.html) | [![Enter the Matrix](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](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.

View File

@@ -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)

View File

@@ -9,8 +9,11 @@ SOURCES =
convert winmain split
;
boost-lib program_options
lib boost_program_options
: $(SOURCES).cpp
: # 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 # tell source we're building dll's
:
: <link>shared:<define>BOOST_PROGRAM_OPTIONS_DYN_LINK=1
;
boost-install boost_program_options ;

View File

@@ -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 $*

View File

@@ -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"

View File

@@ -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"

View File

@@ -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'

View File

@@ -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

View File

@@ -5,19 +5,8 @@ toolset.using doxygen ;
boostbook program_option
: program_options.xml
: <implicit-dependency>autodoc
<xsl:param>boost.root=../../../..
<format>pdf:<xsl:param>boost.url.prefix=http://www.boost.org/doc/libs/release/doc/html
;
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 ] ;

View File

@@ -22,7 +22,7 @@
not mean strict 7-bit ASCII encoding, but rather "char" strings in local
8-bit encoding.
</para>
<para>
Generally, &quot;Unicode support&quot; 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:

View File

@@ -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&lt;string&gt;(),
("response-file", value&lt;string&gt;(),
"can be specified with '@name', too")
</programlisting>
</para>
@@ -107,7 +107,7 @@ if (vm.count("response-file")) {
// Load the file and tokenize it
ifstream ifs(vm["response-file"].as<string>().c_str());
if (!ifs) {
cout << "Could not open the response file\n";
cout << "Could no open the response file\n";
return 1;
}
// Read the whole file into a string
@@ -115,19 +115,18 @@ if (vm.count("response-file")) {
ss << ifs.rdbuf();
// Split the file content
char_separator<char> sep(" \n\r");
std::string ResponsefileContents( ss.str() );
tokenizer<char_separator<char> > tok(ResponsefileContents, sep);
tokenizer<char_separator<char> > tok(ss.str(), sep);
vector<string> args;
copy(tok.begin(), tok.end(), back_inserter(args));
// Parse the file and store the options
store(command_line_parser(args).options(desc).run(), vm);
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,8 +145,8 @@ if (vm.count("response-file")) {
<programlisting>
vector&lt;string&gt; args = split_winmain(lpCmdLine);
store(command_line_parser(args).options(desc).run(), vm);
</programlisting>
The <code>split_winmain</code> function is overloaded for <code>wchar_t</code> strings, so can
</programlisting>
The function is an overload for <code>wchar_t</code> strings, so can
also be used in Unicode applications.
</para>
@@ -223,7 +222,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 +234,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 +242,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 +252,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 +275,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 +289,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);
}
throw validation_error("invalid 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 +371,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 +381,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 +401,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&lt;string&gt; 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>

View File

@@ -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&lt;int&gt;()->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&lt;std::string&gt;</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>
@@ -181,7 +181,7 @@ options_description desc;
desc.add_options()
("help", "produce help message")
("compression", value&lt;string&gt;(), "compression level")
("verbose", value&lt;string&gt;()->implicit_value("0"), "verbosity level")
("verbose", value&lt;string&gt;()->zero_tokens(), "verbosity level")
("email", value&lt;string&gt;()->multitoken(), "email to send to")
;
</programlisting>
@@ -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&lt; vector&lt;string&gt; &gt;()
->composing()->notifier(&amp;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>&amp;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&lt;string&gt;(), "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&lt;bool&gt;())</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:
-->
-->

View File

@@ -178,4 +178,5 @@
12. Deferred
- storing value to boost::optional
- setting a flag when option is found

View File

@@ -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>">

View File

@@ -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.

View File

@@ -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
&quot;special&quot; option must have been configurable. This was not
implemented, because applications might reasonable want to process

View File

@@ -77,13 +77,13 @@ if (vm.count(&quot;compression&quot;)) {
<para>It's now a good time to try compiling the code yourself, but if
you're not yet ready, here's an example session:
<screen>
$ <userinput>bin/gcc/debug/first</userinput>
$<userinput>bin/gcc/debug/first</userinput>
Compression level was not set.
$ <userinput>bin/gcc/debug/first --help</userinput>
$<userinput>bin/gcc/debug/first --help</userinput>
Allowed options:
--help : produce help message
--compression arg : set compression level
$ <userinput>bin/gcc/debug/first --compression 10</userinput>
$<userinput>bin/gcc/debug/first --compression 10</userinput>
Compression level was set to 10.
</screen>
</para>
@@ -199,18 +199,18 @@ cout &lt;&lt; &quot;Optimization level is &quot; &lt;&lt; opt &lt;&lt; &quot;\n&
<para>Here's an example session:
<screen>
$ <userinput>bin/gcc/debug/options_description --help</userinput>
$<userinput>bin/gcc/debug/options_description --help</userinput>
Usage: options_description [options]
Allowed options:
--help : produce help message
--optimization arg : optimization level
-I [ --include-path ] arg : include path
--input-file arg : input file
$ <userinput>bin/gcc/debug/options_description</userinput>
$bin/gcc/debug/options_description
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>
@@ -308,10 +308,10 @@ visible.add(generic).add(config);
<para>Here's an example session:
<screen>
$ <userinput>bin/gcc/debug/multiple_sources</userinput>
$<userinput>bin/gcc/debug/multiple_sources</userinput>
Include paths are: /opt
Optimization level is 1
$ <userinput>bin/gcc/debug/multiple_sources --help</userinput>
$<userinput>bin/gcc/debug/multiple_sources --help</userinput>
Allows options:
Generic options:
@@ -322,7 +322,7 @@ Configuration:
--optimization n : optimization level
-I [ --include-path ] path : include path
$ <userinput>bin/gcc/debug/multiple_sources --optimization=4 -I foo a.cpp b.cpp</userinput>
$<userinput>bin/gcc/debug/multiple_sources --optimization=4 -I foo a.cpp b.cpp</userinput>
Include paths are: foo /opt
Input files are: a.cpp b.cpp
Optimization level is 4
@@ -350,4 +350,4 @@ Optimization level is 4
sgml-parent-document: ("program_options.xml" "section")
sgml-set-face: t
End:
-->
-->

View File

@@ -2,7 +2,6 @@
project
: requirements <library>../build//boost_program_options
<hardcode-dll-paths>true
<link>static
;
exe first : first.cpp ;
@@ -12,10 +11,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 ;

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -20,7 +20,7 @@ int main(int ac, char* av[])
po::options_description desc("Allowed options");
desc.add_options()
("help", "produce help message")
("compression", po::value<double>(), "set compression level")
("compression", po::value<int>(), "set compression level")
;
po::variables_map vm;
@@ -29,12 +29,12 @@ int main(int ac, char* av[])
if (vm.count("help")) {
cout << desc << "\n";
return 0;
return 1;
}
if (vm.count("compression")) {
cout << "Compression level was set to "
<< vm["compression"].as<double>() << ".\n";
<< vm["compression"].as<int>() << ".\n";
} else {
cout << "Compression level was not set.\n";
}

View File

@@ -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>(cout, " "));
return os;
}
@@ -79,7 +79,7 @@ int main(int ac, char* av[])
ifstream ifs(config_file.c_str());
if (!ifs)
{
cout << "can not open config file: " << config_file << "\n";
cout << "can not open config file: " << config_file << "\n";
return 0;
}
else

View File

@@ -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";
}
}

View File

@@ -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>(cout, " "));
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;
}

View File

@@ -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
*/

View File

@@ -8,7 +8,7 @@
#ifndef PROGRAM_OPTIONS_VP_2003_05_19
#define PROGRAM_OPTIONS_VP_2003_05_19
#if defined(_MSC_VER)
#if _MSC_VER >= 1020
#pragma once
#endif

View File

@@ -34,14 +34,17 @@
#endif // BOOST_VERSION
///////////////////////////////////////////////////////////////////////////////
// Windows DLL suport
#ifdef BOOST_HAS_DECLSPEC
#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_PROGRAM_OPTIONS_DYN_LINK)
// export if this is our own source, otherwise import:
#ifdef BOOST_PROGRAM_OPTIONS_SOURCE
# define BOOST_PROGRAM_OPTIONS_DECL BOOST_SYMBOL_EXPORT
# define BOOST_PROGRAM_OPTIONS_DECL __declspec(dllexport)
#else
# define BOOST_PROGRAM_OPTIONS_DECL BOOST_SYMBOL_IMPORT
# define BOOST_PROGRAM_OPTIONS_DECL __declspec(dllimport)
#endif // BOOST_PROGRAM_OPTIONS_SOURCE
#endif // DYN_LINK
#endif // BOOST_HAS_DECLSPEC
#ifndef BOOST_PROGRAM_OPTIONS_DECL
#define BOOST_PROGRAM_OPTIONS_DECL

View File

@@ -22,11 +22,6 @@
#include <string>
#include <vector>
#if defined(BOOST_MSVC)
# pragma warning (push)
# pragma warning (disable:4251) // class 'std::vector<_Ty>' needs to have dll-interface to be used by clients of class 'boost::program_options::positional_options_description'
#endif
namespace boost { namespace program_options { namespace detail {
/** Command line parser class. Main requirements were:
@@ -81,18 +76,6 @@ namespace boost { namespace program_options { namespace detail {
cmdline(int argc, const char*const * argv);
void style(int style);
/** returns the canonical option prefix associated with the command_line_style
* In order of precedence:
* allow_long : allow_long
* allow_long_disguise : allow_long_disguise
* allow_dash_for_short : allow_short | allow_dash_for_short
* allow_slash_for_short: allow_short | allow_slash_for_short
*
* This is mainly used for the diagnostic messages in exceptions
*/
int get_canonical_option_prefix();
void allow_unregistered();
void set_options_description(const options_description& desc);
@@ -136,7 +119,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;
@@ -151,9 +134,5 @@ namespace boost { namespace program_options { namespace detail {
}}}
#if defined(BOOST_MSVC)
# pragma warning (pop)
#endif
#endif

View File

@@ -17,7 +17,9 @@
#include <boost/program_options/eof_iterator.hpp>
#include <boost/detail/workaround.hpp>
#if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3202))
#include <boost/program_options/detail/convert.hpp>
#endif
#if BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(60590042))
#include <istream> // std::getline
@@ -27,11 +29,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 +64,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:
@@ -76,17 +73,12 @@ namespace boost { namespace program_options { namespace detail {
const std::set<std::string>& allowed_options,
bool allow_unregistered = false);
BOOST_DEFAULTED_FUNCTION(virtual ~common_config_file_iterator(), {})
virtual ~common_config_file_iterator() {}
public: // Method required by eof_iterator
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 +179,4 @@ namespace boost { namespace program_options { namespace detail {
}}}
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
#endif

View File

@@ -12,20 +12,35 @@
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<
std::basic_string<charT> >& xargs)
: detail::cmdline(to_internal(xargs))
std::basic_string<charT> >& args)
: detail::cmdline(to_internal(args))
{}
template<class charT>
basic_command_line_parser<charT>::
basic_command_line_parser(int argc, const charT* const argv[])
basic_command_line_parser(int argc, charT* argv[])
: detail::cmdline(
to_internal(std::vector<std::basic_string<charT> >(argc ? argv+1 : argv, 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, charT**>(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;
}
@@ -49,9 +64,9 @@ namespace boost { namespace program_options {
template<class charT>
basic_command_line_parser<charT>&
basic_command_line_parser<charT>::style(int xstyle)
basic_command_line_parser<charT>::style(int style)
{
detail::cmdline::style(xstyle);
detail::cmdline::style(style);
return *this;
}
@@ -85,11 +100,7 @@ namespace boost { namespace program_options {
basic_parsed_options<charT>
basic_command_line_parser<charT>::run()
{
// save the canonical prefixes which were used by this cmdline parser
// eventually inside the parsed results
// This will be handy to format recognisable options
// for diagnostic messages if everything blows up much later on
parsed_options result(m_desc, detail::cmdline::get_canonical_option_prefix());
parsed_options result(m_desc);
result.options = detail::cmdline::run();
// Presense of parsed_options -> wparsed_options conversion
@@ -100,7 +111,7 @@ namespace boost { namespace program_options {
template<class charT>
basic_parsed_options<charT>
parse_command_line(int argc, const charT* const argv[],
parse_command_line(int argc, charT* argv[],
const options_description& desc,
int style,
function1<std::pair<std::string, std::string>,

View File

@@ -8,13 +8,6 @@
#include <boost/throw_exception.hpp>
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
# include <optional>
#endif
// forward declaration
namespace boost { template<class T> class optional; }
namespace boost { namespace program_options {
extern BOOST_PROGRAM_OPTIONS_DECL std::string arg;
@@ -23,17 +16,16 @@ namespace boost { namespace program_options {
std::string
typed_value<T, charT>::name() const
{
std::string const& var = (m_value_name.empty() ? arg : m_value_name);
if (!m_implicit_value.empty() && !m_implicit_value_as_text.empty()) {
std::string msg = "[=" + var + "(=" + m_implicit_value_as_text + ")]";
std::string msg = "[=arg(=" + m_implicit_value_as_text + ")]";
if (!m_default_value.empty() && !m_default_value_as_text.empty())
msg += " (=" + m_default_value_as_text + ")";
return msg;
}
else if (!m_default_value.empty() && !m_default_value_as_text.empty()) {
return var + " (=" + m_default_value_as_text + ")";
return arg + " (=" + m_default_value_as_text + ")";
} else {
return var;
return arg;
}
}
@@ -112,9 +104,12 @@ namespace boost { namespace program_options {
int);
#endif
// For some reason, this declaration, which is require by the standard,
// cause msvc 7.1 to not generate code to specialization defined in
// cause gcc 3.2 to not generate code to specialization defined in
// value_semantic.cpp
#if ! ( BOOST_WORKAROUND(BOOST_MSVC, == 1310) )
#if ! ( ( BOOST_WORKAROUND(__GNUC__, <= 3) &&\
BOOST_WORKAROUND(__GNUC_MINOR__, < 3) ) || \
( BOOST_WORKAROUND(BOOST_MSVC, == 1310) ) \
)
BOOST_PROGRAM_OPTIONS_DECL void validate(boost::any& v,
const std::vector<std::string>& xs,
std::string*,
@@ -148,9 +143,9 @@ namespace boost { namespace program_options {
a validator for class T, we use it even
when parsing vector<T>. */
boost::any a;
std::vector<std::basic_string<charT> > cv;
cv.push_back(s[i]);
validate(a, cv, (T*)0, 0);
std::vector<std::basic_string<charT> > v;
v.push_back(s[i]);
validate(a, v, (T*)0, 0);
tv->push_back(boost::any_cast<T>(a));
}
catch(const bad_lexical_cast& /*e*/) {
@@ -159,36 +154,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)));
}
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
/** Validates std::optional arguments. */
template<class T, class charT>
void validate(boost::any& v,
const std::vector<std::basic_string<charT> >& s,
std::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(std::optional<T>(boost::any_cast<T>(a)));
}
#endif
template<class T, class charT>
void
typed_value<T, charT>::

View File

@@ -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:

View File

@@ -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;
};
}

View File

@@ -12,294 +12,18 @@
#include <string>
#include <stdexcept>
#include <vector>
#include <map>
#if defined(BOOST_MSVC)
# pragma warning (push)
# pragma warning (disable:4275) // non dll-interface class 'std::logic_error' used as base for dll-interface class 'boost::program_options::error'
# pragma warning (disable:4251) // class 'std::vector<_Ty>' needs to have dll-interface to be used by clients of class 'boost::program_options::ambiguous_option'
#endif
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);
}
}
/** Base class for all errors in the library. */
class BOOST_PROGRAM_OPTIONS_DECL BOOST_SYMBOL_VISIBLE error : public std::logic_error {
class BOOST_PROGRAM_OPTIONS_DECL error : public std::logic_error {
public:
error(const std::string& xwhat) : std::logic_error(xwhat) {}
error(const std::string& what) : std::logic_error(what) {}
};
/** Class thrown when there are too many positional options.
This is a programming error.
*/
class BOOST_PROGRAM_OPTIONS_DECL BOOST_SYMBOL_VISIBLE too_many_positional_options_error : public error {
public:
too_many_positional_options_error()
: error("too many positional options have been specified on the command line")
{}
};
/** Class thrown when there are programming error related to style */
class BOOST_PROGRAM_OPTIONS_DECL BOOST_SYMBOL_VISIBLE invalid_command_line_style : public error {
public:
invalid_command_line_style(const std::string& msg)
: error(msg)
{}
};
/** Class thrown if config file can not be read */
class BOOST_PROGRAM_OPTIONS_DECL BOOST_SYMBOL_VISIBLE reading_file : public error {
public:
reading_file(const char* filename)
: error(std::string("can not read options configuration file '").append(filename).append("'"))
{}
};
/** Base class for most exceptions in the library.
*
* Substitutes the values for the parameter name
* placeholders in the template to create the human
* readable error message
*
* Placeholders are surrounded by % signs: %example%
* Poor man's version of boost::format
*
* If a parameter name is absent, perform default substitutions
* instead so ugly placeholders are never left in-place.
*
* Options are displayed in "canonical" form
* This is the most unambiguous form of the
* *parsed* option name and would correspond to
* option_description::format_name()
* i.e. what is shown by print_usage()
*
* The "canonical" form depends on whether the option is
* specified in short or long form, using dashes or slashes
* or without a prefix (from a configuration file)
*
* */
class BOOST_PROGRAM_OPTIONS_DECL BOOST_SYMBOL_VISIBLE error_with_option_name : public error {
protected:
/** can be
* 0 = no prefix (config file options)
* allow_long
* allow_dash_for_short
* allow_slash_for_short
* allow_long_disguise */
int m_option_style;
/** substitutions
* from placeholders to values */
std::map<std::string, std::string> m_substitutions;
typedef std::pair<std::string, std::string> string_pair;
std::map<std::string, string_pair > m_substitution_defaults;
public:
/** 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);
/** gcc says that throw specification on dtor is loosened
* without this line
* */
BOOST_DEFAULTED_FUNCTION(~error_with_option_name() throw(), {})
//void dump() const
//{
// std::cerr << "m_substitution_defaults:\n";
// for (std::map<std::string, string_pair>::const_iterator iter = m_substitution_defaults.begin();
// iter != m_substitution_defaults.end(); ++iter)
// std::cerr << "\t" << iter->first << ":" << iter->second.first << "=" << iter->second.second << "\n";
// std::cerr << "m_substitutions:\n";
// for (std::map<std::string, std::string>::const_iterator iter = m_substitutions.begin();
// iter != m_substitutions.end(); ++iter)
// std::cerr << "\t" << iter->first << "=" << iter->second << "\n";
// std::cerr << "m_error_template:\n";
// std::cerr << "\t" << m_error_template << "\n";
// std::cerr << "canonical_option_prefix:[" << get_canonical_option_prefix() << "]\n";
// std::cerr << "canonical_option_name:[" << get_canonical_option_name() <<"]\n";
// std::cerr << "what:[" << what() << "]\n";
//}
/** Substitute
* parameter_name->value to create the error message from
* the error template */
void set_substitute(const std::string& parameter_name, const std::string& value)
{ m_substitutions[parameter_name] = value; }
/** If the parameter is missing, then make the
* from->to substitution instead */
void set_substitute_default(const std::string& parameter_name,
const std::string& from,
const std::string& to)
{
m_substitution_defaults[parameter_name] = std::make_pair(from, to);
}
/** Add context to an exception */
void add_context(const std::string& option_name,
const std::string& original_token,
int option_style)
{
set_option_name(option_name);
set_original_token(original_token);
set_prefix(option_style);
}
void set_prefix(int option_style)
{ m_option_style = option_style;}
/** Overridden in error_with_no_option_name */
virtual void set_option_name(const std::string& option_name)
{ set_substitute("option", option_name);}
std::string get_option_name() const
{ return get_canonical_option_name(); }
void set_original_token(const std::string& original_token)
{ set_substitute("original_token", original_token);}
/** Creates the error_message on the fly
* Currently a thin wrapper for substitute_placeholders() */
virtual const char* what() const throw();
protected:
/** Used to hold the error text returned by what() */
mutable std::string m_message; // For on-demand formatting in 'what'
/** Makes all substitutions using the template */
virtual void substitute_placeholders(const std::string& error_template) const;
// helper function for substitute_placeholders
void replace_token(const std::string& from, const std::string& to) const;
/** Construct option name in accordance with the appropriate
* prefix style: i.e. long dash or short slash etc */
std::string get_canonical_option_name() const;
std::string get_canonical_option_prefix() const;
};
/** Class thrown when there are several option values, but
user called a method which cannot return them all. */
class BOOST_PROGRAM_OPTIONS_DECL BOOST_SYMBOL_VISIBLE multiple_values : public error_with_option_name {
public:
multiple_values()
: error_with_option_name("option '%canonical_option%' only takes a single argument"){}
BOOST_DEFAULTED_FUNCTION(~multiple_values() throw(), {})
};
/** Class thrown when there are several occurrences of an
option, but user called a method which cannot return
them all. */
class BOOST_PROGRAM_OPTIONS_DECL BOOST_SYMBOL_VISIBLE multiple_occurrences : public error_with_option_name {
public:
multiple_occurrences()
: error_with_option_name("option '%canonical_option%' cannot be specified more than once"){}
BOOST_DEFAULTED_FUNCTION(~multiple_occurrences() throw(), {})
};
/** Class thrown when a required/mandatory option is missing */
class BOOST_PROGRAM_OPTIONS_DECL BOOST_SYMBOL_VISIBLE required_option : public error_with_option_name {
public:
// option name is constructed by the option_descriptor and never on the fly
required_option(const std::string& option_name)
: error_with_option_name("the option '%canonical_option%' is required but missing", "", option_name)
{
}
BOOST_DEFAULTED_FUNCTION(~required_option() throw(), {})
};
/** Base class of unparsable options,
* when the desired option cannot be identified.
*
*
* It makes no sense to have an option name, when we can't match an option to the
* parameter
*
* Having this a part of the error_with_option_name hierachy makes error handling
* a lot easier, even if the name indicates some sort of conceptual dissonance!
*
* */
class BOOST_PROGRAM_OPTIONS_DECL BOOST_SYMBOL_VISIBLE error_with_no_option_name : public error_with_option_name {
public:
error_with_no_option_name(const std::string& template_,
const std::string& original_token = "")
: error_with_option_name(template_, "", original_token)
{
}
/** Does NOT set option name, because no option name makes sense */
virtual void set_option_name(const std::string&) {}
BOOST_DEFAULTED_FUNCTION(~error_with_no_option_name() throw(), {})
};
/** Class thrown when option name is not recognized. */
class BOOST_PROGRAM_OPTIONS_DECL BOOST_SYMBOL_VISIBLE unknown_option : public error_with_no_option_name {
public:
unknown_option(const std::string& original_token = "")
: error_with_no_option_name("unrecognised option '%canonical_option%'", original_token)
{
}
BOOST_DEFAULTED_FUNCTION(~unknown_option() throw(), {})
};
/** Class thrown when there's ambiguity amoung several possible options. */
class BOOST_PROGRAM_OPTIONS_DECL BOOST_SYMBOL_VISIBLE ambiguous_option : public error_with_no_option_name {
public:
ambiguous_option(const std::vector<std::string>& xalternatives)
: error_with_no_option_name("option '%canonical_option%' is ambiguous"),
m_alternatives(xalternatives)
{}
BOOST_DEFAULTED_FUNCTION(~ambiguous_option() throw(), {})
const std::vector<std::string>& alternatives() const throw() {return m_alternatives;}
protected:
/** Makes all substitutions using the template */
virtual void substitute_placeholders(const std::string& error_template) const;
private:
// TODO: copy ctor might throw
std::vector<std::string> m_alternatives;
};
/** Class thrown when there's syntax error either for command
* line or config file options. See derived children for
* concrete classes. */
class BOOST_PROGRAM_OPTIONS_DECL BOOST_SYMBOL_VISIBLE invalid_syntax : public error_with_option_name {
class BOOST_PROGRAM_OPTIONS_DECL invalid_syntax : public error {
public:
enum kind_t {
long_not_allowed = 30,
@@ -310,57 +34,109 @@ namespace boost { namespace program_options {
extra_parameter,
unrecognized_line
};
invalid_syntax(const std::string& tokens, kind_t kind);
invalid_syntax(kind_t kind,
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)
{
}
BOOST_DEFAULTED_FUNCTION(~invalid_syntax() throw(), {})
kind_t kind() const {return m_kind;}
/** Convenience functions for backwards compatibility */
virtual std::string tokens() const {return get_option_name(); }
// gcc says that throw specification on dtor is loosened
// without this line
~invalid_syntax() throw() {}
kind_t kind() const;
const std::string& tokens() const;
protected:
/** Used to convert kind_t to a related error text */
std::string get_template(kind_t kind);
static std::string error_message(kind_t kind);
private:
// TODO: copy ctor might throw
std::string m_tokens;
kind_t m_kind;
};
class BOOST_PROGRAM_OPTIONS_DECL BOOST_SYMBOL_VISIBLE invalid_config_file_syntax : public invalid_syntax {
/** Class thrown when option name is not recognized. */
class BOOST_PROGRAM_OPTIONS_DECL unknown_option : public error {
public:
invalid_config_file_syntax(const std::string& invalid_line, kind_t kind):
invalid_syntax(kind)
{
m_substitutions["invalid_line"] = invalid_line;
}
unknown_option(const std::string& name)
: error(std::string("unknown option ").append(name)),
m_option_name(name)
{}
BOOST_DEFAULTED_FUNCTION(~invalid_config_file_syntax() throw(), {})
/** Convenience functions for backwards compatibility */
virtual std::string tokens() const {return m_substitutions.find("invalid_line")->second; }
// gcc says that throw specification on dtor is loosened
// without this line
~unknown_option() throw() {}
const std::string& get_option_name() const throw();
private:
std::string m_option_name;
};
/** Class thrown when there are syntax errors in given command line */
class BOOST_PROGRAM_OPTIONS_DECL BOOST_SYMBOL_VISIBLE invalid_command_line_syntax : public invalid_syntax {
/** Class thrown when there's ambiguity amoung several possible options. */
class BOOST_PROGRAM_OPTIONS_DECL ambiguous_option : public error {
public:
invalid_command_line_syntax(kind_t kind,
const std::string& option_name = "",
const std::string& original_token = "",
int option_style = 0):
invalid_syntax(kind, option_name, original_token, option_style) {}
BOOST_DEFAULTED_FUNCTION(~invalid_command_line_syntax() throw(), {})
ambiguous_option(const std::string& name,
const std::vector<std::string>& alternatives)
: error(std::string("ambiguous option ").append(name))
, m_alternatives(alternatives)
, m_option_name(name)
{}
~ambiguous_option() throw() {}
const std::string& get_option_name() const throw();
const std::vector<std::string>& alternatives() const throw();
private:
// TODO: copy ctor might throw
std::vector<std::string> m_alternatives;
std::string m_option_name;
};
/** Class thrown when there are several option values, but
user called a method which cannot return them all. */
class BOOST_PROGRAM_OPTIONS_DECL multiple_values : public error {
public:
multiple_values()
: error("multiple values")
, m_option_name() {}
~multiple_values() throw() {}
void set_option_name(const std::string& option);
const std::string& get_option_name() const throw();
private:
std::string m_option_name; // The name of the option which
// caused the exception.
};
/** Class thrown when there are several occurrences of an
option, but user called a method which cannot return
them all. */
class BOOST_PROGRAM_OPTIONS_DECL multiple_occurrences : public error {
public:
multiple_occurrences()
: error("multiple occurrences")
, m_option_name() {}
~multiple_occurrences() throw() {}
void set_option_name(const std::string& option);
const std::string& get_option_name() const throw();
private:
std::string m_option_name; // The name of the option which
// caused the exception.
};
/** Class thrown when value of option is incorrect. */
class BOOST_PROGRAM_OPTIONS_DECL BOOST_SYMBOL_VISIBLE validation_error : public error_with_option_name {
class BOOST_PROGRAM_OPTIONS_DECL validation_error : public error {
public:
enum kind_t {
multiple_values_not_allowed = 30,
@@ -370,28 +146,33 @@ namespace boost { namespace program_options {
invalid_option
};
public:
validation_error(kind_t kind,
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)
{
}
BOOST_DEFAULTED_FUNCTION(~validation_error() throw(), {})
kind_t kind() const { return m_kind; }
const std::string& option_value = "",
const std::string& option_name = "");
~validation_error() throw() {}
void set_option_name(const std::string& option);
const std::string& get_option_name() const throw();
const char* what() const throw();
protected:
/** Used to convert kind_t to a related error text */
std::string get_template(kind_t kind);
static std::string error_message(kind_t kind);
private:
kind_t m_kind;
std::string m_option_name; // The name of the option which
// caused the exception.
std::string m_option_value; // Optional: value of the option m_options_name
mutable std::string m_message; // For on-demand formatting in 'what'
};
/** Class thrown if there is an invalid option value given */
class BOOST_PROGRAM_OPTIONS_DECL BOOST_SYMBOL_VISIBLE invalid_option_value
/** Class thrown if there is an invalid option value givenn */
class BOOST_PROGRAM_OPTIONS_DECL invalid_option_value
: public validation_error
{
public:
@@ -401,24 +182,55 @@ namespace boost { namespace program_options {
#endif
};
/** Class thrown if there is an invalid bool value given */
class BOOST_PROGRAM_OPTIONS_DECL BOOST_SYMBOL_VISIBLE invalid_bool_value
: public validation_error
{
/** Class thrown when there are too many positional options.
This is a programming error.
*/
class BOOST_PROGRAM_OPTIONS_DECL too_many_positional_options_error : public error {
public:
invalid_bool_value(const std::string& value);
too_many_positional_options_error()
: error("too many positional options")
{}
};
/** Class thrown when there are syntax errors in given command line */
class BOOST_PROGRAM_OPTIONS_DECL invalid_command_line_syntax : public invalid_syntax {
public:
invalid_command_line_syntax(const std::string& tokens, kind_t kind);
};
/** Class thrown when there are programming error related to style */
class BOOST_PROGRAM_OPTIONS_DECL invalid_command_line_style : public error {
public:
invalid_command_line_style(const std::string& msg)
: error(msg)
{}
};
/** Class thrown if config file can not be read */
class BOOST_PROGRAM_OPTIONS_DECL reading_file : public error {
public:
reading_file(const char* filename)
: error(std::string("can not read file ").append(filename))
{}
};
/** Class thrown when a required/mandatory option is missing */
class BOOST_PROGRAM_OPTIONS_DECL required_option : public error {
public:
required_option(const std::string& name)
: error(std::string("missing required option ").append(name))
, m_option_name(name)
{}
~required_option() throw() {}
const std::string& get_option_name() const throw();
private:
std::string m_option_name; // The name of the option which
// caused the exception.
};
}}
#if defined(BOOST_MSVC)
# pragma warning (pop)
#endif
#endif

View File

@@ -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.
@@ -28,11 +28,10 @@ namespace boost { namespace program_options {
, unregistered(false)
, case_insensitive(false)
{}
basic_option(const std::string& xstring_key,
const std::vector< std::string> &xvalue)
: string_key(xstring_key)
, position_key(-1)
, value(xvalue)
basic_option(const std::string& string_key,
const std::vector< std::string> &value)
: string_key(string_key)
, value(value)
, unregistered(false)
, case_insensitive(false)
{}

View File

@@ -22,16 +22,9 @@
#include <set>
#include <map>
#include <stdexcept>
#include <utility>
#include <iosfwd>
#if defined(BOOST_MSVC)
# pragma warning (push)
# pragma warning (disable:4251) // class 'boost::shared_ptr<T>' needs to have dll-interface to be used by clients of class 'boost::program_options::option_description'
#endif
/** Boost namespace */
namespace boost {
/** Namespace for the library. */
@@ -42,7 +35,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 {
@@ -62,8 +55,8 @@ namespace program_options {
Alas, derived->base conversion for auto_ptr does not really work,
see
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2000/n1232.pdf
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#84
http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2000/n1232.pdf
http://std.dkuug.dk/jtc1/sc22/wg21/docs/cwg_defects.html#84
So, we have to use plain old pointers. Besides, users are not
expected to use the constructor directly.
@@ -72,7 +65,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 -- long name.
*/
option_description(const char* name,
const value_semantic* s);
@@ -88,12 +81,12 @@ namespace program_options {
enum match_result { no_match, full_match, approximate_match };
/** Given 'option', specified in the input source,
returns 'true' if 'option' specifies *this.
return 'true' is 'option' specifies *this.
*/
match_result match(const std::string& option, bool approx,
bool long_ignore_case, bool short_ignore_case) const;
/** Returns the key that should identify the option, in
/** Return the key that should identify the option, in
particular in the variables_map class.
The 'option' parameter is the option spelling from the
input source.
@@ -103,20 +96,8 @@ namespace program_options {
*/
const std::string& key(const std::string& option) const;
/** 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.
*/
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;
@@ -126,30 +107,15 @@ namespace program_options {
/// Returns the option name, formatted suitably for usage message.
std::string format_name() const;
/** Returns the parameter name and properties, formatted suitably for
/** Return the parameter name and properties, formatted suitably for
usage message. */
std::string format_parameter() const;
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;
@@ -217,10 +183,6 @@ namespace program_options {
*/
options_description& add(const options_description& desc);
/** Find the maximum width of the option column, including options
in groups. */
unsigned get_option_column_width() const;
public:
/** Returns an object of implementation-defined type suitable for adding
options to options_description. The returned object will
@@ -249,16 +211,11 @@ namespace program_options {
friend BOOST_PROGRAM_OPTIONS_DECL std::ostream& operator<<(std::ostream& os,
const options_description& desc);
/** Outputs 'desc' to the specified stream, calling 'f' to output each
/** Output 'desc' to the specified stream, calling 'f' to output each
option_description element. */
void print(std::ostream& os, unsigned width = 0) const;
void print(std::ostream& os) 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;
@@ -290,12 +247,8 @@ namespace program_options {
/** Class thrown when duplicate option description is found. */
class BOOST_PROGRAM_OPTIONS_DECL duplicate_option_error : public error {
public:
duplicate_option_error(const std::string& xwhat) : error(xwhat) {}
duplicate_option_error(const std::string& what) : error(what) {}
};
}}
#if defined(BOOST_MSVC)
# pragma warning (pop)
#endif
#endif

View File

@@ -17,46 +17,30 @@
#include <vector>
#include <utility>
#if defined(BOOST_MSVC)
# pragma warning (push)
# pragma warning (disable:4251) // class 'std::vector<_Ty>' needs to have dll-interface to be used by clients of class 'boost::program_options::basic_parsed_options<wchar_t>'
#endif
namespace boost { namespace program_options {
class options_description;
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)
: description(xdescription), m_options_prefix(options_prefix) {}
explicit basic_parsed_options(const options_description* description)
: description(description) {}
/** 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.
*/
const options_description* description;
/** Mainly used for the diagnostic messages in exceptions.
* The canonical option prefix for the parser which generated these results,
* depending on the settings for basic_command_line_parser::style() or
* cmdline::style(). In order of precedence of command_line_style enums:
* allow_long
* allow_long_disguise
* allow_dash_for_short
* allow_slash_for_short
*/
int m_options_prefix;
};
/** Specialization of basic_parsed_options which:
@@ -74,18 +58,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;
/** Mainly used for the diagnostic messages in exceptions.
* The canonical option prefix for the parser which generated these results,
* depending on the settings for basic_command_line_parser::style() or
* cmdline::style(). In order of precedence of command_line_style enums:
* allow_long
* allow_long_disguise
* allow_dash_for_short
* allow_slash_for_short
*/
int m_options_prefix;
basic_parsed_options<char> utf8_encoded_options;
};
typedef basic_parsed_options<char> parsed_options;
@@ -101,14 +74,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>
@@ -120,13 +93,9 @@ namespace boost { namespace program_options {
basic_command_line_parser(const std::vector<
std::basic_string<charT> >& args);
/** Creates a command line parser for the specified arguments
list. The parameters should be the same as passed to 'main', meaning:
@param argc Must be non-negative i.e. >= 0
@param argv Argv[argc] must be 0 e.g. nullptr and
if argc is >0 argv[0] up to argv[argc-1] must point to
null terminated strings
list. The parameters should be the same as passed to 'main'.
*/
basic_command_line_parser(int argc, const charT* const argv[]);
basic_command_line_parser(int argc, charT* argv[]);
/** Sets options descriptions to use. */
basic_command_line_parser& options(const options_description& desc);
@@ -150,10 +119,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);
@@ -166,19 +135,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[],
parse_command_line(int argc, charT* 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>
@@ -189,16 +158,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
@@ -208,7 +173,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
@@ -218,34 +183,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.
*/
@@ -260,13 +225,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
@@ -286,14 +251,10 @@ namespace boost { namespace program_options {
split_winmain(const std::wstring& cmdline);
#endif
#endif
}}
#if defined(BOOST_MSVC)
# pragma warning (pop)
#endif
#undef DECL
#include "boost/program_options/detail/parsers.hpp"

View File

@@ -11,11 +11,6 @@
#include <vector>
#include <string>
#if defined(BOOST_MSVC)
# pragma warning (push)
# pragma warning (disable:4251) // class 'std::vector<_Ty>' needs to have dll-interface to be used by clients of class 'boost::program_options::positional_options_description'
#endif
namespace boost { namespace program_options {
/** Describes positional options.
@@ -66,9 +61,5 @@ namespace boost { namespace program_options {
}}
#if defined(BOOST_MSVC)
# pragma warning (pop)
#endif
#endif

View File

@@ -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)
{
@@ -228,13 +227,6 @@ namespace boost { namespace program_options {
return this;
}
/** Specifies the name used to to the value in help message. */
typed_value* value_name(const std::string& name)
{
m_value_name = name;
return this;
}
/** 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, but if
@@ -269,21 +261,13 @@ namespace boost { namespace program_options {
return this;
}
/** Specifies that the value can span multiple tokens.
*/
/** Specifies that the value can span multiple tokens. */
typed_value* multitoken()
{
m_multitoken = true;
return this;
}
/** Specifies that no tokens may be provided as the value of
this option, which means that only presense of the option
is significant. For such option to be useful, either the
'validate' function should be specialized, or the
'implicit_value' method should be also used. In most
cases, you can use the 'bool_switch' function instead of
using this method. */
typed_value* zero_tokens()
{
m_zero_tokens = true;
@@ -314,7 +298,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 +335,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:
@@ -364,7 +346,6 @@ namespace boost { namespace program_options {
// Default value is stored as boost::any and not
// as boost::optional to avoid unnecessary instantiations.
std::string m_value_name;
boost::any m_default_value;
std::string m_default_value_as_text;
boost::any m_implicit_value;

View File

@@ -16,11 +16,6 @@
#include <map>
#include <set>
#if defined(BOOST_MSVC)
# pragma warning (push)
# pragma warning (disable:4251) // 'boost::program_options::variable_value::v' : class 'boost::any' needs to have dll-interface to be used by clients of class 'boost::program_options::variable_value
#endif
namespace boost { namespace program_options {
template<class charT>
@@ -31,35 +26,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& v, bool defaulted)
: v(v), m_defaulted(defaulted)
{}
/** If stored value if of type T, returns that value. Otherwise,
@@ -95,10 +90,10 @@ 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;
friend BOOST_PROGRAM_OPTIONS_DECL class variables_map;
};
/** Implements string->string mapping with convenient value casting
@@ -118,11 +113,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 +133,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.
*/
@@ -153,10 +148,7 @@ namespace boost { namespace program_options {
// Resolve conflict between inherited operators.
const variable_value& operator[](const std::string& name) const
{ return abstract_variables_map::operator[](name); }
// Override to clear some extra fields.
void clear();
void notify();
private:
@@ -164,20 +156,18 @@ 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.
This is useful in creating diagnostic messages when the option is absent. */
std::map<std::string, std::string> m_required;
access to options_description. */
std::set<std::string> m_required;
};
@@ -213,8 +203,4 @@ namespace boost { namespace program_options {
}}
#if defined(BOOST_MSVC)
# pragma warning (pop)
#endif
#endif

View File

@@ -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

View File

@@ -1,16 +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>"
],
"cxxstd": "11"
}

View File

@@ -3,9 +3,7 @@
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROGRAM_OPTIONS_SOURCE
# define BOOST_PROGRAM_OPTIONS_SOURCE
#endif
#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/config.hpp>
#include <boost/config.hpp>
@@ -17,7 +15,7 @@
#include <boost/program_options/positional_options.hpp>
#include <boost/throw_exception.hpp>
#include <boost/bind/bind.hpp>
#include <boost/bind.hpp>
#include <string>
#include <utility>
@@ -31,50 +29,69 @@
#include <iostream>
using namespace boost::placeholders;
namespace boost { namespace program_options {
using namespace std;
using namespace boost::program_options::command_line_style;
invalid_syntax::
invalid_syntax(const string& tokens, kind_t kind)
: error(error_message(kind).append(" in '").append(tokens).append("'"))
, m_tokens(tokens)
, m_kind(kind)
{}
string
invalid_syntax::get_template(kind_t kind)
invalid_syntax::error_message(kind_t kind)
{
// Initially, store the message in 'const char*' variable,
// to avoid conversion to string in all cases.
const char* msg;
switch(kind)
{
case empty_adjacent_parameter:
msg = "the argument for option '%canonical_option%' should follow immediately after the equal sign";
break;
case missing_parameter:
msg = "the required argument for option '%canonical_option%' is missing";
break;
case unrecognized_line:
msg = "the options configuration file contains an invalid line '%invalid_line%'";
break;
// none of the following are currently used:
case long_not_allowed:
msg = "the unabbreviated option '%canonical_option%' is not valid";
msg = "long options are not allowed";
break;
case long_adjacent_not_allowed:
msg = "the unabbreviated option '%canonical_option%' does not take any arguments";
msg = "parameters adjacent to long options not allowed";
break;
case short_adjacent_not_allowed:
msg = "the abbreviated option '%canonical_option%' does not take any arguments";
msg = "parameters adjust to short options are not allowed";
break;
case empty_adjacent_parameter:
msg = "adjacent parameter is empty";
break;
case missing_parameter:
msg = "required parameter is missing";
break;
case extra_parameter:
msg = "option '%canonical_option%' does not take any arguments";
msg = "extra parameter";
break;
case unrecognized_line:
msg = "unrecognized line";
break;
default:
msg = "unknown command line syntax error for '%s'";
msg = "unknown error";
}
return msg;
}
invalid_syntax::kind_t
invalid_syntax::kind() const
{
return m_kind;
}
const string&
invalid_syntax::tokens() const
{
return m_tokens;
}
invalid_command_line_syntax::
invalid_command_line_syntax(const string& tokens, kind_t kind)
: invalid_syntax(tokens, kind)
{}
}}
@@ -107,7 +124,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;
@@ -139,26 +156,15 @@ namespace boost { namespace program_options { namespace detail {
const char* error = 0;
if (allow_some_long &&
!(style & long_allow_adjacent) && !(style & long_allow_next))
error = "boost::program_options misconfiguration: "
"choose one or other of 'command_line_style::long_allow_next' "
"(whitespace separated arguments) or "
"'command_line_style::long_allow_adjacent' ('=' separated arguments) for "
"long options.";
error = "style disallows parameters for long options";
if (!error && (style & allow_short) &&
!(style & short_allow_adjacent) && !(style & short_allow_next))
error = "boost::program_options misconfiguration: "
"choose one or other of 'command_line_style::short_allow_next' "
"(whitespace separated arguments) or "
"'command_line_style::short_allow_adjacent' ('=' separated arguments) for "
"short options.";
error = "style disallows parameters for short options";
if (!error && (style & allow_short) &&
!(style & allow_dash_for_short) && !(style & allow_slash_for_short))
error = "boost::program_options misconfiguration: "
"choose one or other of 'command_line_style::allow_slash_for_short' "
"(slashes) or 'command_line_style::allow_dash_for_short' (dashes) for "
"short options.";
error = "style disallows all characters for short options";
if (error)
boost::throw_exception(invalid_command_line_style(error));
@@ -186,23 +192,6 @@ namespace boost { namespace program_options { namespace detail {
m_positional = &positional;
}
int
cmdline::get_canonical_option_prefix()
{
if (m_style & allow_long)
return allow_long;
if (m_style & allow_long_disguise)
return allow_long_disguise;
if ((m_style & allow_short) && (m_style & allow_dash_for_short))
return allow_dash_for_short;
if ((m_style & allow_short) && (m_style & allow_slash_for_short))
return allow_slash_for_short;
return 0;
}
vector<option>
cmdline::run()
@@ -248,13 +237,12 @@ 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;
for(unsigned i = 0; i < style_parsers.size(); ++i)
{
unsigned current_size = static_cast<unsigned>(args.size());
unsigned current_size = args.size();
vector<option> next = style_parsers[i](args);
// Check that option names
@@ -289,7 +277,7 @@ namespace boost { namespace program_options { namespace detail {
}
/* If an key option is followed by a positional option,
can can consume more tokens (e.g. it's multitoken option),
can can consume more tokens (e.g. it's multitoke option),
give those tokens to it. */
vector<option> result2;
for (unsigned i = 0; i < result.size(); ++i)
@@ -300,21 +288,11 @@ namespace boost { namespace program_options { namespace detail {
if (opt.string_key.empty())
continue;
const option_description* xd;
try
{
xd = m_desc->find_nothrow(opt.string_key,
is_style_active(allow_guessing),
is_style_active(long_case_insensitive),
is_style_active(short_case_insensitive));
}
catch(error_with_option_name& e)
{
// add context and rethrow
e.add_context(opt.string_key, opt.original_tokens[0], get_canonical_option_prefix());
throw;
}
const option_description* xd =
m_desc->find_nothrow(opt.string_key,
is_style_active(allow_guessing),
is_style_active(long_case_insensitive),
is_style_active(short_case_insensitive));
if (!xd)
continue;
@@ -326,7 +304,7 @@ namespace boost { namespace program_options { namespace detail {
// We only allow to grab tokens that are not already
// recognized as key options.
int can_take_more = max_tokens - static_cast<int>(opt.value.size());
int can_take_more = max_tokens - opt.value.size();
unsigned j = i+1;
for (; can_take_more && j < result.size(); --can_take_more, ++j)
{
@@ -405,108 +383,92 @@ namespace boost { namespace program_options { namespace detail {
if (opt.string_key.empty())
return;
//
// Be defensive:
// will have no original token if option created by handle_additional_parser()
std::string original_token_for_exceptions = opt.string_key;
if (opt.original_tokens.size())
original_token_for_exceptions = opt.original_tokens[0];
// First check that the option is valid, and get its description.
const option_description* xd = m_desc->find_nothrow(opt.string_key,
is_style_active(allow_guessing),
is_style_active(long_case_insensitive),
is_style_active(short_case_insensitive));
try
if (!xd)
{
// First check that the option is valid, and get its description.
const option_description* xd = m_desc->find_nothrow(opt.string_key,
is_style_active(allow_guessing),
is_style_active(long_case_insensitive),
is_style_active(short_case_insensitive));
if (m_allow_unregistered) {
opt.unregistered = true;
return;
} else {
boost::throw_exception(unknown_option(opt.string_key));
}
}
const option_description& d = *xd;
if (!xd)
// Canonize the name
opt.string_key = d.key(opt.string_key);
// We check that the min/max number of tokens for the option
// agrees with the number of tokens we have. The 'adjacent_value'
// (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();
unsigned present_tokens = opt.value.size() + other_tokens.size();
if (present_tokens >= min_tokens)
{
if (!opt.value.empty() && max_tokens == 0)
{
if (m_allow_unregistered) {
opt.unregistered = true;
return;
} else {
boost::throw_exception(unknown_option());
}
boost::throw_exception(invalid_command_line_syntax(opt.string_key,
invalid_command_line_syntax::extra_parameter));
}
const option_description& d = *xd;
// Canonize the name
opt.string_key = d.key(opt.string_key);
// We check that the min/max number of tokens for the option
// agrees with the number of tokens we have. The 'adjacent_value'
// (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.
unsigned min_tokens = d.semantic()->min_tokens();
unsigned max_tokens = d.semantic()->max_tokens();
unsigned present_tokens = static_cast<unsigned>(opt.value.size() + other_tokens.size());
if (present_tokens >= min_tokens)
// 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)
{
if (!opt.value.empty() && max_tokens == 0)
{
boost::throw_exception(
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 (opt.value.size() <= min_tokens)
{
min_tokens -= static_cast<unsigned>(opt.value.size());
}
else
{
min_tokens = 0;
}
// Everything's OK, move the values to the result.
for(;!other_tokens.empty() && min_tokens--; )
{
// check if extra parameter looks like a known option
// we use style parsers to check if it is syntactically an option,
// additionally we check if an option_description exists
vector<option> followed_option;
vector<string> next_token(1, other_tokens[0]);
for (unsigned i = 0; followed_option.empty() && i < style_parsers.size(); ++i)
{
followed_option = style_parsers[i](next_token);
}
if (!followed_option.empty())
{
original_token_for_exceptions = other_tokens[0];
const option_description* od = m_desc->find_nothrow(other_tokens[0],
is_style_active(allow_guessing),
is_style_active(long_case_insensitive),
is_style_active(short_case_insensitive));
if (od)
boost::throw_exception(
invalid_command_line_syntax(invalid_command_line_syntax::missing_parameter));
}
opt.value.push_back(other_tokens[0]);
opt.original_tokens.push_back(other_tokens[0]);
other_tokens.erase(other_tokens.begin());
}
min_tokens -= opt.value.size();
}
else
{
boost::throw_exception(
invalid_command_line_syntax(invalid_command_line_syntax::missing_parameter));
min_tokens = 0;
}
}
// use only original token for unknown_option / ambiguous_option since by definition
// they are unrecognised / unparsable
catch(error_with_option_name& e)
{
// add context and rethrow
e.add_context(opt.string_key, original_token_for_exceptions, get_canonical_option_prefix());
throw;
}
// Everything's OK, move the values to the result.
for(;!other_tokens.empty() && min_tokens--; )
{
// check if extra parameter looks like a known option
// we use style parsers to check if it is syntactically an option,
// additionally we check if an option_description exists
vector<option> followed_option;
vector<string> next_token(1, other_tokens[0]);
for (unsigned i = 0; followed_option.empty() && i < style_parsers.size(); ++i)
{
followed_option = style_parsers[i](next_token);
}
if (!followed_option.empty())
{
const option_description* od = m_desc->find_nothrow(other_tokens[0],
is_style_active(allow_guessing),
is_style_active(long_case_insensitive),
is_style_active(short_case_insensitive));
if (od)
boost::throw_exception(invalid_command_line_syntax(opt.string_key,
invalid_command_line_syntax::missing_parameter));
}
opt.value.push_back(other_tokens[0]);
opt.original_tokens.push_back(other_tokens[0]);
other_tokens.erase(other_tokens.begin());
}
}
else
{
boost::throw_exception(invalid_command_line_syntax(opt.string_key,
invalid_command_line_syntax::missing_parameter));
}
}
vector<option>
@@ -524,11 +486,8 @@ namespace boost { namespace program_options { namespace detail {
name = tok.substr(2, p-2);
adjacent = tok.substr(p+1);
if (adjacent.empty())
boost::throw_exception( invalid_command_line_syntax(
invalid_command_line_syntax::empty_adjacent_parameter,
name,
name,
get_canonical_option_prefix()) );
boost::throw_exception( invalid_command_line_syntax(name,
invalid_command_line_syntax::empty_adjacent_parameter) );
}
else
{
@@ -564,20 +523,9 @@ namespace boost { namespace program_options { namespace detail {
// of token is considered to be value, not further grouped
// option.
for(;;) {
const option_description* d;
try
{
d = m_desc->find_nothrow(name, false, false,
is_style_active(short_case_insensitive));
}
catch(error_with_option_name& e)
{
// add context and rethrow
e.add_context(name, name, get_canonical_option_prefix());
throw;
}
const option_description* d
= m_desc->find_nothrow(name, false, false,
is_style_active(short_case_insensitive));
// FIXME: check for 'allow_sticky'.
if (d && (m_style & allow_sticky) &&
@@ -641,24 +589,15 @@ namespace boost { namespace program_options { namespace detail {
((tok[0] == '-' && tok[1] != '-') ||
((m_style & allow_slash_for_short) && tok[0] == '/')))
{
try
if (m_desc->find_nothrow(tok.substr(1, tok.find('=')-1),
is_style_active(allow_guessing),
is_style_active(long_case_insensitive),
is_style_active(short_case_insensitive)))
{
if (m_desc->find_nothrow(tok.substr(1, tok.find('=')-1),
is_style_active(allow_guessing),
is_style_active(long_case_insensitive),
is_style_active(short_case_insensitive)))
{
args[0].insert(0, "-");
if (args[0][1] == '/')
args[0][1] = '-';
return parse_long_option(args);
}
}
catch(error_with_option_name& e)
{
// add context and rethrow
e.add_context(tok, tok, get_canonical_option_prefix());
throw;
args[0].insert(0, "-");
if (args[0][1] == '/')
args[0][1] = '-';
return parse_long_option(args);
}
}
return vector<option>();

View File

@@ -3,9 +3,8 @@
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROGRAM_OPTIONS_SOURCE
# define BOOST_PROGRAM_OPTIONS_SOURCE
#endif
#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/config.hpp>
#include <boost/program_options/detail/config_file.hpp>
@@ -58,9 +57,7 @@ namespace boost { namespace program_options { namespace detail {
bad_prefixes = true;
}
if (bad_prefixes)
boost::throw_exception(error("options '" + string(name) + "' and '" +
*i + "*' will both match the same "
"arguments from the configuration file"));
boost::throw_exception(error("bad prefixes"));
allowed_prefixes.insert(s);
}
}
@@ -120,7 +117,7 @@ namespace boost { namespace program_options { namespace detail {
break;
} else {
boost::throw_exception(invalid_config_file_syntax(s, invalid_syntax::unrecognized_line));
boost::throw_exception(invalid_syntax(s, invalid_syntax::unrecognized_line));
}
}
}

View File

@@ -13,18 +13,15 @@
#include <boost/config.hpp>
#ifndef BOOST_PROGRAM_OPTIONS_SOURCE
# define BOOST_PROGRAM_OPTIONS_SOURCE
#endif
#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/config.hpp>
#include <boost/program_options/detail/convert.hpp>
#include <boost/program_options/detail/utf8_codecvt_facet.hpp>
#include <boost/throw_exception.hpp>
#include <boost/bind/bind.hpp>
#include <boost/bind.hpp>
using namespace std;
using namespace boost::placeholders;
namespace boost { namespace detail {

View File

@@ -4,12 +4,11 @@
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROGRAM_OPTIONS_SOURCE
# define BOOST_PROGRAM_OPTIONS_SOURCE
#endif
#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>
@@ -50,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()
@@ -78,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)
@@ -127,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,
@@ -140,82 +132,29 @@ namespace boost { namespace program_options {
// in the source.
return option;
else
return first_long_name;
}
return m_long_name;
else
return m_short_name;
}
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 (prefix_style == command_line_style::allow_long)
return "--" + *m_long_names.begin();
if (prefix_style == command_line_style::allow_long_disguise)
return "-" + *m_long_names.begin();
}
// sanity check: m_short_name[0] should be '-' or '/'
if (m_short_name.length() == 2)
{
if (prefix_style == command_line_style::allow_slash_for_short)
return string("/") + m_short_name[1];
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();
else
return m_short_name;
}
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,13 +174,10 @@ namespace boost { namespace program_options {
option_description::format_name() const
{
if (!m_short_name.empty())
{
return m_long_names.empty()
? m_short_name
: string(m_short_name).append(" [ --").
append(*m_long_names.begin()).append(" ]");
}
return string("--").append(*m_long_names.begin());
return string(m_short_name).append(" [ --").
append(m_long_name).append(" ]");
else
return string("--").append(m_long_name);
}
std::string
@@ -353,7 +289,7 @@ namespace boost { namespace program_options {
const option_description* d = find_nothrow(name, approx,
long_ignore_case, short_ignore_case);
if (!d)
boost::throw_exception(unknown_option());
boost::throw_exception(unknown_option(name));
return *d;
}
@@ -370,7 +306,6 @@ namespace boost { namespace program_options {
bool short_ignore_case) const
{
shared_ptr<option_description> found;
bool had_full_match = false;
vector<string> approximate_matches;
vector<string> full_matches;
@@ -388,20 +323,19 @@ namespace boost { namespace program_options {
if (r == option_description::full_match)
{
full_matches.push_back(m_options[i]->key(name));
found = m_options[i];
had_full_match = true;
}
else
{
// FIXME: the use of 'key' here might not
// be the best approach.
approximate_matches.push_back(m_options[i]->key(name));
if (!had_full_match)
found = m_options[i];
}
found = m_options[i];
}
if (full_matches.size() > 1)
boost::throw_exception(ambiguous_option(full_matches));
boost::throw_exception(
ambiguous_option(name, full_matches));
// If we have a full match, and an approximate match,
// ignore approximate match instead of reporting error.
@@ -409,7 +343,8 @@ namespace boost { namespace program_options {
// "--all" on the command line should select the first one,
// without ambiguity.
if (full_matches.empty() && approximate_matches.size() > 1)
boost::throw_exception(ambiguous_option(approximate_matches));
boost::throw_exception(
ambiguous_option(name, approximate_matches));
return found.get();
}
@@ -458,7 +393,7 @@ namespace boost { namespace program_options {
if (count(par.begin(), par.end(), '\t') > 1)
{
boost::throw_exception(program_options::error(
"Only one tab per paragraph is allowed in the options description"));
"Only one tab per paragraph is allowed"));
}
// erase tab from string
@@ -505,7 +440,7 @@ namespace boost { namespace program_options {
// Take care to never increment the iterator past
// the end, since MSVC 8.0 (brokenly), assumes that
// doing that, even if no access happens, is a bug.
unsigned remaining = static_cast<unsigned>(std::distance(line_begin, par_end));
unsigned remaining = distance(line_begin, par_end);
string::const_iterator line_end = line_begin +
((remaining < line_length) ? remaining : line_length);
@@ -525,7 +460,7 @@ namespace boost { namespace program_options {
{
// is last_space within the second half ot the
// current line
if (static_cast<unsigned>(std::distance(last_space, line_end)) <
if (static_cast<unsigned>(distance(last_space, line_end)) <
(line_length / 2))
{
line_end = last_space;
@@ -538,8 +473,8 @@ namespace boost { namespace program_options {
if (first_line)
{
indent += static_cast<unsigned>(par_indent);
line_length -= static_cast<unsigned>(par_indent); // there's less to work with now
indent += par_indent;
line_length -= par_indent; // there's less to work with now
first_line = false;
}
@@ -628,7 +563,7 @@ namespace boost { namespace program_options {
os.put(' ');
}
} else {
for(unsigned pad = first_column_width - static_cast<unsigned>(ss.str().size()); pad > 0; --pad)
for(unsigned pad = first_column_width - ss.str().size(); pad > 0; --pad)
{
os.put(' ');
}
@@ -640,9 +575,12 @@ namespace boost { namespace program_options {
}
}
unsigned
options_description::get_option_column_width() const
void
options_description::print(std::ostream& os) const
{
if (!m_caption.empty())
os << m_caption << ":\n";
/* Find the maximum width of the option column */
unsigned width(23);
unsigned i; // vc6 has broken for loop scoping
@@ -653,11 +591,6 @@ namespace boost { namespace program_options {
ss << " " << opt.format_name() << ' ' << opt.format_parameter();
width = (max)(width, static_cast<unsigned>(ss.str().size()));
}
/* Get width of groups as well*/
for (unsigned j = 0; j < groups.size(); ++j)
width = max(width, groups[j]->get_option_column_width());
/* this is the column were description should start, if first
column is longer, we go to a new line */
const unsigned start_of_description_column = m_line_length - m_min_description_length;
@@ -666,20 +599,9 @@ namespace boost { namespace program_options {
/* add an additional space to improve readability */
++width;
return width;
}
void
options_description::print(std::ostream& os, unsigned width) const
{
if (!m_caption.empty())
os << m_caption << ":\n";
if (!width)
width = get_option_column_width();
/* The options formatting style is stolen from Subversion. */
for (unsigned i = 0; i < m_options.size(); ++i)
for (i = 0; i < m_options.size(); ++i)
{
if (belong_to_group[i])
continue;
@@ -692,8 +614,7 @@ namespace boost { namespace program_options {
}
for (unsigned j = 0; j < groups.size(); ++j) {
os << "\n";
groups[j]->print(os, width);
os << "\n" << *groups[j];
}
}

View File

@@ -6,9 +6,7 @@
#include <boost/config.hpp>
#ifndef BOOST_PROGRAM_OPTIONS_SOURCE
# define BOOST_PROGRAM_OPTIONS_SOURCE
#endif
#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/config.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/options_description.hpp>
@@ -18,7 +16,7 @@
#include <boost/program_options/environment_iterator.hpp>
#include <boost/program_options/detail/convert.hpp>
#include <boost/bind/bind.hpp>
#include <boost/bind.hpp>
#include <boost/throw_exception.hpp>
#include <cctype>
@@ -47,10 +45,7 @@
// See: http://article.gmane.org/gmane.comp.lib.boost.devel/103843
// See: http://lists.gnu.org/archive/html/bug-guile/2004-01/msg00013.html
#if defined(__APPLE__) && defined(__DYNAMIC__)
// The proper include for this is crt_externs.h, however it's not
// available on iOS. The right replacement is not known. See
// https://svn.boost.org/trac/boost/ticket/5053
extern "C" { extern char ***_NSGetEnviron(void); }
#include <crt_externs.h>
#define environ (*_NSGetEnviron())
#else
#if defined(__MWERKS__)
@@ -63,7 +58,6 @@ extern char** environ;
#endif
using namespace std;
using namespace boost::placeholders;
namespace boost { namespace program_options {
@@ -91,8 +85,7 @@ namespace boost { namespace program_options {
basic_parsed_options<wchar_t>
::basic_parsed_options(const parsed_options& po)
: description(po.description),
utf8_encoded_options(po),
m_options_prefix(po.m_options_prefix)
utf8_encoded_options(po)
{
for (unsigned i = 0; i < po.options.size(); ++i)
options.push_back(woption_from_option(po.options[i]));
@@ -114,7 +107,7 @@ namespace boost { namespace program_options {
if (d.long_name().empty())
boost::throw_exception(
error("abbreviated option names are not permitted in options configuration files"));
error("long name required for config file"));
allowed_options.insert(d.long_name());
}
@@ -155,16 +148,7 @@ namespace boost { namespace program_options {
{
boost::throw_exception(reading_file(filename));
}
basic_parsed_options<charT> result
= parse_config_file(strm, desc, allow_unregistered);
if (strm.bad())
{
boost::throw_exception(reading_file(filename));
}
return result;
return parse_config_file(strm, desc, allow_unregistered);
}
template
@@ -232,7 +216,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;

View File

@@ -3,9 +3,7 @@
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROGRAM_OPTIONS_SOURCE
# define BOOST_PROGRAM_OPTIONS_SOURCE
#endif
#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/config.hpp>
#include <boost/program_options/positional_options.hpp>
@@ -36,7 +34,7 @@ namespace boost { namespace program_options {
positional_options_description::max_total_count() const
{
return m_trailing.empty() ?
static_cast<unsigned>(m_names.size()) : (std::numeric_limits<unsigned>::max)();
m_names.size() : (std::numeric_limits<unsigned>::max)();
}
const std::string&

View File

@@ -3,9 +3,7 @@
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROGRAM_OPTIONS_SOURCE
# define BOOST_PROGRAM_OPTIONS_SOURCE
#endif
#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/parsers.hpp>
#include <boost/tokenizer.hpp>

View File

@@ -3,9 +3,7 @@
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROGRAM_OPTIONS_SOURCE
# define BOOST_PROGRAM_OPTIONS_SOURCE
#endif
#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/config.hpp>
#define BOOST_UTF8_BEGIN_NAMESPACE \
@@ -14,7 +12,7 @@
#define BOOST_UTF8_END_NAMESPACE }}}
#define BOOST_UTF8_DECL BOOST_PROGRAM_OPTIONS_DECL
#include <boost/detail/utf8_codecvt_facet.ipp>
#include "../../detail/utf8_codecvt_facet.cpp"
#undef BOOST_UTF8_BEGIN_NAMESPACE

View File

@@ -3,14 +3,10 @@
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROGRAM_OPTIONS_SOURCE
# define BOOST_PROGRAM_OPTIONS_SOURCE
#endif
#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/config.hpp>
#include <boost/program_options/value_semantic.hpp>
#include <boost/program_options/detail/convert.hpp>
#include <boost/program_options/detail/cmdline.hpp>
#include <set>
#include <cctype>
@@ -18,22 +14,6 @@ namespace boost { namespace program_options {
using namespace std;
#ifndef BOOST_NO_STD_WSTRING
namespace
{
std::string convert_value(const std::wstring& s)
{
try {
return to_local_8_bit(s);
}
catch(const std::exception&) {
return "<unrepresentable unicode string>";
}
}
}
#endif
void
value_semantic_codecvt_helper<char>::
parse(boost::any& value_store,
@@ -159,7 +139,7 @@ namespace boost { namespace program_options {
else if (s == "off" || s == "no" || s == "0" || s == "false")
v = any(false);
else
boost::throw_exception(invalid_bool_value(s));
boost::throw_exception(validation_error(validation_error::invalid_bool_value, s));
}
// This is blatant copy-paste. However, templating this will cause a problem,
@@ -181,7 +161,7 @@ namespace boost { namespace program_options {
else if (s == L"off" || s == L"no" || s == L"0" || s == L"false")
v = any(false);
else
boost::throw_exception(invalid_bool_value(convert_value(s)));
boost::throw_exception(validation_error(validation_error::invalid_bool_value));
}
#endif
BOOST_PROGRAM_OPTIONS_DECL
@@ -214,212 +194,120 @@ namespace boost { namespace program_options {
invalid_option_value::
invalid_option_value(const std::string& bad_value)
: validation_error(validation_error::invalid_option_value)
{
set_substitute("value", bad_value);
}
: validation_error(validation_error::invalid_option_value, bad_value)
{}
#ifndef BOOST_NO_STD_WSTRING
namespace
{
std::string convert_value(const std::wstring& s)
{
try {
return to_local_8_bit(s);
}
catch(const std::exception&) {
return "<unrepresentable unicode string>";
}
}
}
invalid_option_value::
invalid_option_value(const std::wstring& bad_value)
: validation_error(validation_error::invalid_option_value)
{
set_substitute("value", convert_value(bad_value));
}
: validation_error(validation_error::invalid_option_value, convert_value(bad_value))
{}
#endif
invalid_bool_value::
invalid_bool_value(const std::string& bad_value)
: validation_error(validation_error::invalid_bool_value)
{
set_substitute("value", bad_value);
const std::string&
unknown_option::get_option_name() const throw()
{
return m_option_name;
}
error_with_option_name::error_with_option_name( const std::string& template_,
const std::string& option_name,
const std::string& original_token,
int option_style) :
error(template_),
m_option_style(option_style),
m_error_template(template_)
const std::string&
ambiguous_option::get_option_name() const throw()
{
return m_option_name;
}
const std::vector<std::string>&
ambiguous_option::alternatives() const throw()
{
// parameter | placeholder | value
// --------- | ----------- | -----
set_substitute_default("canonical_option", "option '%canonical_option%'", "option");
set_substitute_default("value", "argument ('%value%')", "argument");
set_substitute_default("prefix", "%prefix%", "");
m_substitutions["option"] = option_name;
m_substitutions["original_token"] = original_token;
return m_alternatives;
}
const char* error_with_option_name::what() const throw()
void
multiple_values::set_option_name(const std::string& option_name)
{
// will substitute tokens each time what is run()
substitute_placeholders(m_error_template);
return m_message.c_str();
m_option_name = option_name;
}
void error_with_option_name::replace_token(const string& from, const string& to) const
const std::string&
multiple_values::get_option_name() const throw()
{
for (;;)
{
std::size_t pos = m_message.find(from.c_str(), 0, from.length());
// not found: all replaced
if (pos == std::string::npos)
return;
m_message.replace(pos, from.length(), to);
}
return m_option_name;
}
void
multiple_occurrences::set_option_name(const std::string& option_name)
{
m_option_name = option_name;
}
string error_with_option_name::get_canonical_option_prefix() const
const std::string&
multiple_occurrences::get_option_name() const throw()
{
switch (m_option_style)
{
case command_line_style::allow_dash_for_short:
return "-";
case command_line_style::allow_slash_for_short:
return "/";
case command_line_style::allow_long_disguise:
return "-";
case command_line_style::allow_long:
return "--";
case 0:
return "";
}
throw std::logic_error("error_with_option_name::m_option_style can only be "
"one of [0, allow_dash_for_short, allow_slash_for_short, "
"allow_long_disguise or allow_long]");
return m_option_name;
}
validation_error::
validation_error(kind_t kind,
const std::string& option_value,
const std::string& option_name)
: error("")
, m_kind(kind)
, m_option_name(option_name)
, m_option_value(option_value)
, m_message(error_message(kind))
{
if (!option_value.empty())
{
m_message.append(std::string("'") + option_value + std::string("'"));
}
}
string error_with_option_name::get_canonical_option_name() const
void
validation_error::set_option_name(const std::string& option_name)
{
if (!m_substitutions.find("option")->second.length())
return m_substitutions.find("original_token")->second;
string original_token = strip_prefixes(m_substitutions.find("original_token")->second);
string option_name = strip_prefixes(m_substitutions.find("option")->second);
// For long options, use option name
if (m_option_style == command_line_style::allow_long ||
m_option_style == command_line_style::allow_long_disguise)
return get_canonical_option_prefix() + option_name;
// For short options use first letter of original_token
if (m_option_style && original_token.length())
return get_canonical_option_prefix() + original_token[0];
// no prefix
return option_name;
m_option_name = option_name;
}
void error_with_option_name::substitute_placeholders(const string& error_template) const
const std::string&
validation_error::get_option_name() const throw()
{
m_message = error_template;
std::map<std::string, std::string> substitutions(m_substitutions);
substitutions["canonical_option"] = get_canonical_option_name();
substitutions["prefix"] = get_canonical_option_prefix();
//
// replace placeholder with defaults if values are missing
//
for (map<string, string_pair>::const_iterator iter = m_substitution_defaults.begin();
iter != m_substitution_defaults.end(); ++iter)
{
// missing parameter: use default
if (substitutions.count(iter->first) == 0 ||
substitutions[iter->first].length() == 0)
replace_token(iter->second.first, iter->second.second);
}
//
// replace placeholder with values
// placeholder are denoted by surrounding '%'
//
for (map<string, string>::iterator iter = substitutions.begin();
iter != substitutions.end(); ++iter)
replace_token('%' + iter->first + '%', iter->second);
return m_option_name;
}
void ambiguous_option::substitute_placeholders(const string& original_error_template) const
{
// For short forms, all alternatives must be identical, by
// definition, to the specified option, so we don't need to
// display alternatives
if (m_option_style == command_line_style::allow_dash_for_short ||
m_option_style == command_line_style::allow_slash_for_short)
{
error_with_option_name::substitute_placeholders(original_error_template);
return;
}
string error_template = original_error_template;
// remove duplicates using std::set
std::set<std::string> alternatives_set (m_alternatives.begin(), m_alternatives.end());
std::vector<std::string> alternatives_vec (alternatives_set.begin(), alternatives_set.end());
error_template += " and matches ";
// Being very cautious: should be > 1 alternative!
if (alternatives_vec.size() > 1)
{
for (unsigned i = 0; i < alternatives_vec.size() - 1; ++i)
error_template += "'%prefix%" + alternatives_vec[i] + "', ";
error_template += "and ";
}
// there is a programming error if multiple options have the same name...
if (m_alternatives.size() > 1 && alternatives_vec.size() == 1)
error_template += "different versions of ";
error_template += "'%prefix%" + alternatives_vec.back() + "'";
// use inherited logic
error_with_option_name::substitute_placeholders(error_template);
}
string
validation_error::get_template(kind_t kind)
std::string
validation_error::error_message(kind_t kind)
{
// Initially, store the message in 'const char*' variable,
// to avoid conversion to std::string in all cases.
const char* msg;
switch(kind)
{
case invalid_bool_value:
msg = "the argument ('%value%') for option '%canonical_option%' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'";
break;
case invalid_option_value:
msg = "the argument ('%value%') for option '%canonical_option%' is invalid";
break;
case multiple_values_not_allowed:
msg = "option '%canonical_option%' only takes a single argument";
msg = "multiple values not allowed";
break;
case at_least_one_value_required:
msg = "option '%canonical_option%' requires at least one argument";
msg = "at least one value required";
break;
case invalid_bool_value:
msg = "invalid bool value";
break;
case invalid_option_value:
msg = "invalid option value";
break;
// currently unused
case invalid_option:
msg = "option '%canonical_option%' is not valid";
msg = "invalid option";
break;
default:
msg = "unknown error";
@@ -427,4 +315,21 @@ namespace boost { namespace program_options {
return msg;
}
const char*
validation_error::what() const throw()
{
if (!m_option_name.empty())
{
m_message = "in option '" + m_option_name + "': "
+ error_message(m_kind);
}
return m_message.c_str();
}
const std::string&
required_option::get_option_name() const throw()
{
return m_option_name;
}
}}

View File

@@ -3,9 +3,8 @@
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROGRAM_OPTIONS_SOURCE
# define BOOST_PROGRAM_OPTIONS_SOURCE
#endif
#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/config.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/options_description.hpp>
@@ -18,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'.
@@ -39,71 +38,69 @@ namespace boost { namespace program_options {
// Declared once, to please Intel in VC++ mode;
unsigned i;
// Declared here so can be used to provide context for exceptions
string option_name;
string original_token;
// First, convert/store all given options
for (i = 0; i < options.options.size(); ++i) {
#ifndef BOOST_NO_EXCEPTIONS
try
#endif
{
const string& name = options.options[i].string_key;
// Skip positional options without name
if (name.empty())
continue;
// First, convert/store all given options
for (i = 0; i < options.options.size(); ++i) {
// 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),
// so just ignore them.
if (options.options[i].unregistered)
continue;
option_name = options.options[i].string_key;
// Skip positional options without name
if (option_name.empty())
continue;
// If option has final value, skip this assignment
if (xm.m_final.count(name))
continue;
// 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),
// so just ignore them.
if (options.options[i].unregistered)
continue;
const option_description& d = desc.find(name, false,
false, false);
// If option has final value, skip this assignment
if (xm.m_final.count(option_name))
continue;
original_token = options.options[i].original_tokens.size() ?
options.options[i].original_tokens[0] : "";
const option_description& d = desc.find(option_name, false,
false, false);
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,
// so that several assignment inside *this* 'store' call
// are allowed.
if (!d.semantic()->is_composing())
new_final.insert(option_name);
variable_value& v = m[name];
if (v.defaulted()) {
// Explicit assignment here erases defaulted value
v = variable_value();
}
try {
d.semantic()->parse(v.value(), options.options[i].value, utf8);
}
}
#ifndef BOOST_NO_EXCEPTIONS
catch(error_with_option_name& e)
{
// add context and rethrow
e.add_context(option_name, original_token, options.m_options_prefix);
throw;
}
catch(validation_error& e)
{
e.set_option_name(name);
throw;
}
catch(multiple_occurrences& e)
{
e.set_option_name(name);
throw;
}
catch(multiple_values& e)
{
e.set_option_name(name);
throw;
}
#endif
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,
// so that several assignment inside *this* 'store' call
// are allowed.
if (!d.semantic()->is_composing())
new_final.insert(name);
}
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)
@@ -112,46 +109,39 @@ 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()) {
// For option names specified in multiple ways, e.g. on the command line,
// config file etc, the following precedence rules apply:
// "--" > ("-" or "/") > ""
// Precedence is set conveniently by a single call to length()
string canonical_name = d.canonical_display_name(options.m_options_prefix);
if (canonical_name.length() > xm.m_required[key].length())
xm.m_required[key] = canonical_name;
xm.m_required.insert(key);
}
}
}
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()
@@ -163,7 +153,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);
@@ -179,7 +169,7 @@ namespace boost { namespace program_options {
}
}
void
void
abstract_variables_map::next(abstract_variables_map* next)
{
m_next = next;
@@ -192,13 +182,6 @@ namespace boost { namespace program_options {
: abstract_variables_map(next)
{}
void variables_map::clear()
{
std::map<std::string, variable_value>::clear();
m_final.clear();
m_required.clear();
}
const variable_value&
variables_map::get(const std::string& name) const
{
@@ -209,41 +192,40 @@ namespace boost { namespace program_options {
else
return i->second;
}
void
variables_map::notify()
{
// This checks if all required options occur
for (map<string, string>::const_iterator r = m_required.begin();
for (set<string>::const_iterator r = m_required.begin();
r != m_required.end();
++r)
{
const string& opt = r->first;
const string& display_opt = r->second;
const string& opt = *r;
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));
boost::throw_exception(required_option(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());
}
}
}
}}

View File

@@ -3,14 +3,10 @@
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROGRAM_OPTIONS_SOURCE
# define BOOST_PROGRAM_OPTIONS_SOURCE
#endif
#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/parsers.hpp>
#include <cctype>
using std::size_t;
#ifdef _WIN32
namespace boost { namespace program_options {
@@ -34,7 +30,6 @@ namespace boost { namespace program_options {
std::string current;
bool inside_quoted = false;
bool empty_quote = false;
int backslash_count = 0;
for(; i != e; ++i) {
@@ -43,7 +38,6 @@ namespace boost { namespace program_options {
// n/2 backslashes and is a quoted block delimiter
if (backslash_count % 2 == 0) {
current.append(backslash_count / 2, '\\');
empty_quote = inside_quoted && current.empty();
inside_quoted = !inside_quoted;
// '"' preceded by odd number (n) of backslashes generates
// (n-1)/2 backslashes and is literal quote.
@@ -65,7 +59,6 @@ namespace boost { namespace program_options {
// Space outside quoted section terminate the current argument
result.push_back(current);
current.resize(0);
empty_quote = false;
for(;i != e && isspace((unsigned char)*i); ++i)
;
--i;
@@ -81,7 +74,7 @@ namespace boost { namespace program_options {
// If we have non-empty 'current' or we're still in quoted
// section (even if 'current' is empty), add the last token.
if (!current.empty() || inside_quoted || empty_quote)
if (!current.empty() || inside_quoted)
result.push_back(current);
}
return result;
@@ -93,7 +86,7 @@ namespace boost { namespace program_options {
{
std::vector<std::wstring> result;
std::vector<std::string> aux = split_winmain(to_internal(cmdline));
for (size_t i = 0, e = aux.size(); i < e; ++i)
for (unsigned i = 0, e = aux.size(); i < e; ++i)
result.push_back(from_utf8(aux[i]));
return result;
}
@@ -101,4 +94,3 @@ namespace boost { namespace program_options {
}}
#endif

View File

@@ -1,27 +0,0 @@
# Copyright 2018-2020 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
include(BoostTest OPTIONAL RESULT_VARIABLE HAVE_BOOST_TEST)
if(NOT HAVE_BOOST_TEST)
return()
endif()
set(BOOST_TEST_LINK_LIBRARIES Boost::program_options)
boost_test(TYPE run SOURCES options_description_test.cpp)
boost_test(TYPE run SOURCES parsers_test.cpp ARGUMENTS ${CMAKE_CURRENT_SOURCE_DIR}/config_test.cfg)
boost_test(TYPE run SOURCES variable_map_test.cpp)
boost_test(TYPE run SOURCES cmdline_test.cpp)
boost_test(TYPE run SOURCES positional_options_test.cpp)
boost_test(TYPE run SOURCES unicode_test.cpp)
boost_test(TYPE run SOURCES winmain.cpp)
boost_test(TYPE run SOURCES exception_test.cpp)
boost_test(TYPE run SOURCES split_test.cpp)
boost_test(TYPE run SOURCES unrecognized_test.cpp)
boost_test(TYPE run SOURCES required_test.cpp ARGUMENTS ${CMAKE_CURRENT_SOURCE_DIR}/required_test.cfg)
boost_test(TYPE run SOURCES exception_txt_test.cpp)
boost_test(TYPE run SOURCES optional_test.cpp)
boost_test(TYPE run SOURCES quick.cpp ARGUMENTS --path=initial LINK_LIBRARIES Boost::core)

View File

@@ -1,4 +1,3 @@
import testing ;
project
: requirements
@@ -33,12 +32,7 @@ test-suite program_options :
[ po-test split_test.cpp ]
[ 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 : options_description_no_rtti_test ]
;
exe test_convert : test_convert.cpp ;
# `quick` target (for CI)
run quick.cpp : --path=initial ;

View File

@@ -1,18 +0,0 @@
# Copyright 2018, 2019 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
cmake_minimum_required(VERSION 3.5...3.16)
project(cmake_install_test LANGUAGES CXX)
find_package(boost_program_options REQUIRED)
find_package(boost_core REQUIRED)
add_executable(quick ../quick.cpp)
target_link_libraries(quick Boost::program_options Boost::core)
enable_testing()
add_test(NAME quick COMMAND quick --path=initial)
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $<CONFIG>)

View File

@@ -1,18 +0,0 @@
# Copyright 2018, 2019 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
cmake_minimum_required(VERSION 3.5...3.16)
project(cmake_subdir_test LANGUAGES CXX)
set(BOOST_INCLUDE_LIBRARIES program_options)
add_subdirectory(../../../.. boostorg/boost)
add_executable(quick ../quick.cpp)
target_link_libraries(quick Boost::program_options Boost::core)
enable_testing()
add_test(NAME quick COMMAND quick --path=initial)
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $<CONFIG>)

View File

@@ -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) {
@@ -377,15 +378,6 @@ void test_guessing()
{0, 0, 0}
};
test_cmdline("opt123 opt56 foo,f=", style, test_cases1);
test_case test_cases2[] = {
{"--fname file --fname2 file2", s_success, "fname: file fname2: file2"},
{"--fnam file --fnam file2", s_ambiguous_option, ""},
{"--fnam file --fname2 file2", s_ambiguous_option, ""},
{"--fname2 file2 --fnam file", s_ambiguous_option, ""},
{0, 0, 0}
};
test_cmdline("fname fname2", style, test_cases2);
}
void test_arguments()
@@ -463,13 +455,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 +467,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 +598,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 +610,6 @@ int main(int /*ac*/, char** /*av*/)
test_additional_parser();
test_style_parser();
test_unregistered();
test_implicit_value();
return 0;
}

View File

@@ -5,5 +5,5 @@ b = true
[m1]
v1 = 1
v2 = 2
v3 = 3

View File

@@ -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()
{
@@ -113,7 +63,7 @@ void test_unknown_option()
catch (unknown_option& e)
{
BOOST_CHECK_EQUAL(e.get_option_name(), "-f");
BOOST_CHECK_EQUAL(string(e.what()), "unrecognised option '-f'");
BOOST_CHECK_EQUAL(string(e.what()), "unknown option -f");
}
}
@@ -144,12 +94,13 @@ void test_multiple_values()
// because: untyped_value always has one value and this is filtered before reach specific
// validation and parsing
//
BOOST_CHECK_EQUAL(e.get_option_name(), "--cfgfile");
BOOST_CHECK_EQUAL(string(e.what()), "option '--cfgfile' only takes a single argument");
BOOST_CHECK_EQUAL(e.get_option_name(), "cfgfile");
BOOST_CHECK_EQUAL(string(e.what()), "in option 'cfgfile': multiple values not allowed");
}
}
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(string(e.what()), "option '--cfgfile' cannot be specified more than once");
BOOST_CHECK_EQUAL(e.get_option_name(), "cfgfile");
BOOST_CHECK_EQUAL(string(e.what()), "multiple occurrences");
}
}
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()
@@ -241,7 +145,7 @@ void test_missing_value()
catch (invalid_command_line_syntax& e)
{
BOOST_CHECK_EQUAL(e.kind(), invalid_syntax::missing_parameter);
BOOST_CHECK_EQUAL(e.tokens(), "--cfgfile");
BOOST_CHECK_EQUAL(e.tokens(), "cfgfile");
}
}
@@ -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;

View File

@@ -1,693 +0,0 @@
// Copyright Leo Goodstadt 2012
// 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/parsers.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/variables_map.hpp>
#include <boost/program_options/cmdline.hpp>
using namespace boost::program_options;
#include <iostream>
#include <sstream>
#include <vector>
#include <cassert>
using namespace std;
#include "minitest.hpp"
//
// like BOOST_CHECK_EQUAL but with more descriptive error message
//
#define CHECK_EQUAL(description, a, b) if (a != b) {std::cerr << "\n\nError:\n<<" << \
description << ">>\n Expected text=\"" << b << "\"\n Actual text =\"" << a << "\"\n\n"; assert(a == b);}
// Uncomment for Debugging, removes asserts so we can see more failures!
//#define BOOST_ERROR(description) std::cerr << description; std::cerr << "\n";
//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
//
// Uncomment to print out the complete set of diagnostic messages for the different test cases
/*
#define CHECK_EQUAL(description, a, b) if (a != b) {std::cerr << "\n\nError: " << \
description << "\n Expecting\n" << b << "\n Found\n" << a << "\n\n"; } \
else {std::cout << description<< "\t" << b << "\n";}
*/
//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
//
// test exception for each specified command line style, e.g. short dash or config file
//
template<typename EXCEPTION>
void test_each_exception_message(const string& test_description, const vector<const char*>& argv, options_description& desc, int style, string exception_msg, istream& is = cin)
{
if (exception_msg.length() == 0)
return;
variables_map vm;
unsigned argc = argv.size();
try {
if (style == -1)
store(parse_config_file(is, desc), vm);
else
store(parse_command_line(argv.size(), &argv[0], desc, style), vm);
notify(vm);
}
catch (EXCEPTION& e)
{
//cerr << "Correct:\n\t" << e.what() << "\n";
CHECK_EQUAL(test_description, e.what(), exception_msg);
return;
}
catch (std::exception& e)
{
// concatenate argv without boost::algorithm::join
string argv_txt;
for (unsigned ii = 0; ii < argc - 1; ++ii)
argv_txt += argv[ii] + string(" ");
if (argc)
argv_txt += argv[argc - 1];
BOOST_ERROR("\n<<" + test_description +
string(">>\n Unexpected exception type!\n Actual text =\"") + e.what() +
"\"\n argv =\"" + argv_txt +
"\"\n Expected text=\"" + exception_msg + "\"\n");
return;
}
BOOST_ERROR(test_description + ": No exception thrown. ");
}
//
// test exception messages for all command line styles (unix/long/short/slash/config file)
//
// try each command line style in turn
const int unix_style = command_line_style::unix_style;
const int short_dash = command_line_style::allow_dash_for_short | command_line_style::allow_short | command_line_style::short_allow_adjacent | command_line_style::allow_sticky;
const int short_slash = command_line_style::allow_slash_for_short | command_line_style::allow_short | command_line_style::short_allow_adjacent;
const int long_dash = command_line_style::allow_long | command_line_style::long_allow_adjacent | command_line_style::allow_guessing;
template<typename EXCEPTION>
void test_exception_message(const vector<vector<const char*> >& argv,
options_description& desc,
const string& error_description,
const char* expected_message_template[5])
{
string expected_message;
// unix
expected_message = expected_message_template[0];
test_each_exception_message<EXCEPTION>(error_description + " -- unix",
argv[0], desc, unix_style, expected_message);
// long dash only
expected_message = expected_message_template[1];
test_each_exception_message<EXCEPTION>(error_description + " -- long_dash",
argv[1], desc, long_dash, expected_message);
// short dash only
expected_message = expected_message_template[2];
test_each_exception_message<EXCEPTION>(error_description + " -- short_dash",
argv[2], desc, short_dash, expected_message);
// short slash only
expected_message = expected_message_template[3];
test_each_exception_message<EXCEPTION>(error_description + " -- short_slash",
argv[3], desc, short_slash, expected_message);
// config file only
expected_message = expected_message_template[4];
if (expected_message.length())
{
istringstream istrm(argv[4][0]);
test_each_exception_message<EXCEPTION>(error_description + " -- config_file",
argv[4], desc, -1, expected_message, istrm);
}
}
#define VEC_STR_PUSH_BACK(vec, c_array) \
vec.push_back(vector<const char*>(c_array, c_array + sizeof(c_array) / sizeof(char*)));
//________________________________________________________________________________________
//
// invalid_option_value
//
//________________________________________________________________________________________
void test_invalid_option_value_exception_msg()
{
options_description desc;
desc.add_options()
("int-option,d", value< int >(), "An option taking an integer")
;
vector<vector<const char*> > argv;
const char* argv0[] = { "program", "-d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv0);
const char* argv1[] = { "program", "--int", "A_STRING"}; VEC_STR_PUSH_BACK(argv, argv1);
const char* argv2[] = { "program", "-d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv2);
const char* argv3[] = { "program", "/d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv3);
const char* argv4[] = { "int-option=A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv4);
const char* expected_msg[5] = {
"the argument ('A_STRING') for option '--int-option' is invalid",
"the argument ('A_STRING') for option '--int-option' is invalid",
"the argument ('A_STRING') for option '-d' is invalid",
"the argument ('A_STRING') for option '/d' is invalid",
"the argument ('A_STRING') for option 'int-option' is invalid",
};
test_exception_message<invalid_option_value>(argv, desc, "invalid_option_value",
expected_msg);
}
//________________________________________________________________________________________
//
// missing_value
//
//________________________________________________________________________________________
void test_missing_value_exception_msg()
{
options_description desc;
desc.add_options()
("cfgfile,e", value<string>(), "the config file")
("output,o", value<string>(), "the output file")
;
vector<vector<const char*> > argv;
const char* argv0[] = { "program", "-e", "-e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv0);
const char* argv1[] = { "program", "--cfgfile"} ; VEC_STR_PUSH_BACK(argv, argv1);
const char* argv2[] = { "program", "-e", "-e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv2);
const char* argv3[] = { "program", "/e", "/e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv3);
const char* argv4[] = { ""} ; VEC_STR_PUSH_BACK(argv, argv4);
const char* expected_msg[5] = {
"the required argument for option '--cfgfile' is missing",
"the required argument for option '--cfgfile' is missing",
"the required argument for option '-e' is missing",
"", // Ignore probable bug in cmdline::finish_option
//"the required argument for option '/e' is missing",
"",
};
test_exception_message<invalid_command_line_syntax>(argv, desc,
"invalid_syntax::missing_parameter",
expected_msg);
}
//________________________________________________________________________________________
//
// ambiguous_option
//
//________________________________________________________________________________________
void test_ambiguous_option_exception_msg()
{
options_description desc;
desc.add_options()
("cfgfile1,c", value<string>(), "the config file")
("cfgfile2,o", value<string>(), "the config file")
("good,g", "good option")
("output,c", value<string>(), "the output file")
("output", value<string>(), "the output file")
;
vector<vector<const char*> > argv;
const char* argv0[] = {"program", "-ggc", "file", "-o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv0);
const char* argv1[] = {"program", "--cfgfile", "file", "--cfgfile", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv1);
const char* argv2[] = {"program", "-ggc", "file", "-o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv2);
const char* argv3[] = {"program", "/c", "file", "/o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv3);
const char* argv4[] = { "output=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4);
const char* expected_msg[5] = {
"option '-c' is ambiguous and matches '--cfgfile1', and '--output'",
"option '--cfgfile' is ambiguous and matches '--cfgfile1', and '--cfgfile2'",
"option '-c' is ambiguous",
"option '/c' is ambiguous",
"option 'output' is ambiguous and matches different versions of 'output'",
};
test_exception_message<ambiguous_option>(argv, desc, "ambiguous_option",
expected_msg);
}
//________________________________________________________________________________________
//
// multiple_occurrences
//
//________________________________________________________________________________________
void test_multiple_occurrences_exception_msg()
{
options_description desc;
desc.add_options()
("cfgfile,c", value<string>(), "the configfile")
;
vector<vector<const char*> > argv;
const char* argv0[] = {"program", "-c", "file", "-c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv0);
const char* argv1[] = {"program", "--cfgfi", "file", "--cfgfi", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv1);
const char* argv2[] = {"program", "-c", "file", "-c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv2);
const char* argv3[] = {"program", "/c", "file", "/c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv3);
const char* argv4[] = { "cfgfile=output.txt\ncfgfile=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4);
const char* expected_msg[5] = {
"option '--cfgfile' cannot be specified more than once",
"option '--cfgfile' cannot be specified more than once",
"option '-c' cannot be specified more than once",
"option '/c' cannot be specified more than once",
"option 'cfgfile' cannot be specified more than once",
};
test_exception_message<multiple_occurrences>(argv, desc, "multiple_occurrences",
expected_msg);
}
//________________________________________________________________________________________
//
// unknown_option
//
//________________________________________________________________________________________
void test_unknown_option_exception_msg()
{
options_description desc;
desc.add_options()
("good,g", "good option")
;
vector<vector<const char*> > argv;
const char* argv0[] = {"program", "-ggc", "file"} ; VEC_STR_PUSH_BACK(argv, argv0);
const char* argv1[] = {"program", "--cfgfile", "file"} ; VEC_STR_PUSH_BACK(argv, argv1);
const char* argv2[] = {"program", "-ggc", "file"} ; VEC_STR_PUSH_BACK(argv, argv2);
const char* argv3[] = {"program", "/c", "file"} ; VEC_STR_PUSH_BACK(argv, argv3);
const char* argv4[] = { "cfgfile=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4);
const char* expected_msg[5] = {
"unrecognised option '-ggc'",
"unrecognised option '--cfgfile'",
"unrecognised option '-ggc'",
"unrecognised option '/c'",
"unrecognised option 'cfgfile'",
};
test_exception_message<unknown_option>(argv, desc, "unknown_option", expected_msg);
}
//________________________________________________________________________________________
//
// validation_error::invalid_bool_value
//
//________________________________________________________________________________________
void test_invalid_bool_value_exception_msg()
{
options_description desc;
desc.add_options()
("bool_option,b", value< bool>(), "bool_option")
;
vector<vector<const char*> > argv;
const char* argv0[] = {"program", "-b", "file"} ; VEC_STR_PUSH_BACK(argv, argv0);
const char* argv1[] = {"program", "--bool_optio", "file"} ; VEC_STR_PUSH_BACK(argv, argv1);
const char* argv2[] = {"program", "-b", "file"} ; VEC_STR_PUSH_BACK(argv, argv2);
const char* argv3[] = {"program", "/b", "file"} ; VEC_STR_PUSH_BACK(argv, argv3);
const char* argv4[] = { "bool_option=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4);
const char* expected_msg[5] = {
"the argument ('file') for option '--bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'",
"the argument ('file') for option '--bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'",
"the argument ('file') for option '-b' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'",
"the argument ('file') for option '/b' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'",
"the argument ('output.txt') for option 'bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'",
};
test_exception_message<validation_error>(argv,
desc,
"validation_error::invalid_bool_value",
expected_msg);
}
//________________________________________________________________________________________
//
// validation_error::multiple_values_not_allowed
//
//________________________________________________________________________________________
//
// Strange exception: sole purpose seems to be catching multitoken() associated with a scalar
// validation_error::multiple_values_not_allowed seems thus to be a programmer error
//
//
void test_multiple_values_not_allowed_exception_msg()
{
options_description desc;
desc.add_options()
("cfgfile,c", value<string>()->multitoken(), "the config file")
("good,g", "good option")
("output,o", value<string>(), "the output file")
;
vector<vector<const char*> > argv;
const char* argv0[] = { "program", "-c", "file", "c", "-o", "fritz", "hugo" } ; VEC_STR_PUSH_BACK(argv, argv0);
const char* argv1[] = { "program", "--cfgfil", "file", "c", "--outpu", "fritz", "hugo" } ; VEC_STR_PUSH_BACK(argv, argv1);
const char* argv2[] = { "program", "-c", "file", "c", "-o", "fritz", "hugo"} ; VEC_STR_PUSH_BACK(argv, argv2);
const char* argv3[] = { "program", "/c", "file", "c", "/o", "fritz", "hugo"} ; VEC_STR_PUSH_BACK(argv, argv3);
const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4);
const char* expected_msg[5] = {
"option '--cfgfile' only takes a single argument",
"option '--cfgfile' only takes a single argument",
"option '-c' only takes a single argument",
"option '/c' only takes a single argument",
"",
};
test_exception_message<validation_error>(argv,
desc,
"validation_error::multiple_values_not_allowed",
expected_msg);
}
//________________________________________________________________________________________
//
// validation_error::at_least_one_value_required
//
//________________________________________________________________________________________
//
// Strange exception: sole purpose seems to be catching zero_tokens() associated with a scalar
// validation_error::multiple_values_not_allowed seems thus to be a programmer error
//
//
void test_at_least_one_value_required_exception_msg()
{
options_description desc;
desc.add_options()
("cfgfile,c", value<int>()->zero_tokens(), "the config file")
("other,o", value<string>(), "other")
;
vector<vector<const char*> > argv;
const char* argv0[] = { "program", "-c" } ; VEC_STR_PUSH_BACK(argv, argv0);
const char* argv1[] = { "program", "--cfg", "--o", "name" } ; VEC_STR_PUSH_BACK(argv, argv1);
const char* argv2[] = { "program", "-c" , "-o" , "name" } ; VEC_STR_PUSH_BACK(argv, argv2);
const char* argv3[] = { "program", "/c" } ; VEC_STR_PUSH_BACK(argv, argv3);
const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4);
const char* expected_msg[5] = {
"option '--cfgfile' requires at least one argument",
"option '--cfgfile' requires at least one argument",
"option '-c' requires at least one argument",
"option '/c' requires at least one argument",
"",
};
test_exception_message<validation_error>(argv,
desc,
"validation_error::at_least_one_value_required",
expected_msg);
}
//________________________________________________________________________________________
//
// required_option
//
//________________________________________________________________________________________
void test_required_option_exception_msg()
{
options_description desc;
desc.add_options()
("cfgfile,c", value<string>()->required(), "the config file")
("good,g", "good option")
("output,o", value<string>()->required(), "the output file")
;
vector<vector<const char*> > argv;
const char* argv0[] = { "program", "-g" } ; VEC_STR_PUSH_BACK(argv, argv0);
const char* argv1[] = { "program", "--g" } ; VEC_STR_PUSH_BACK(argv, argv1);
const char* argv2[] = { "program", "-g"} ; VEC_STR_PUSH_BACK(argv, argv2);
const char* argv3[] = { "program", "/g"} ; VEC_STR_PUSH_BACK(argv, argv3);
const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4);
const char* expected_msg[5] = {
"the option '--cfgfile' is required but missing",
"the option '--cfgfile' is required but missing",
"the option '-c' is required but missing",
"the option '/c' is required but missing",
"the option 'cfgfile' is required but missing",
};
test_exception_message<required_option>(argv,
desc,
"required_option",
expected_msg);
}
/**
* Check if this is the expected exception with the right message is being thrown inside
* func
*/
template <typename EXCEPTION, typename FUNC>
void test_exception(const string& test_name, const string& exception_txt, FUNC func)
{
try {
options_description desc;
variables_map vm;
func(desc, vm);
}
catch (EXCEPTION& e)
{
CHECK_EQUAL(test_name, e.what(), exception_txt);
return;
}
catch (std::exception& e)
{
BOOST_ERROR(string(test_name + ":\nUnexpected exception. ") + e.what() +
"\nExpected text:\n" + exception_txt + "\n\n");
return;
}
BOOST_ERROR(test_name + ": No exception thrown. ");
}
//________________________________________________________________________________________
//
// check_reading_file
//
//________________________________________________________________________________________
void check_reading_file(options_description& desc, variables_map& vm)
{
desc.add_options()
("output,o", value<string>(), "the output file");
const char* file_name = "no_such_file";
store(parse_config_file<char>(file_name, desc, true), vm);
}
//________________________________________________________________________________________
//
// config_file_wildcard
//
//________________________________________________________________________________________
void config_file_wildcard(options_description& desc, variables_map& vm)
{
desc.add_options()
("outpu*", value<string>(), "the output file1")
("outp*", value<string>(), "the output file2")
;
istringstream is("output1=whichone\noutput2=whichone\n");
store(parse_config_file(is, desc), vm);
}
//________________________________________________________________________________________
//
// invalid_syntax::unrecognized_line
//
//________________________________________________________________________________________
void unrecognized_line(options_description& desc, variables_map& vm)
{
istringstream is("funny wierd line\n");
store(parse_config_file(is, desc), vm);
}
//________________________________________________________________________________________
//
// abbreviated_options_in_config_file
//
//________________________________________________________________________________________
void abbreviated_options_in_config_file(options_description& desc, variables_map& vm)
{
desc.add_options()(",o", value<string>(), "the output file");
istringstream is("o=output.txt\n");
store(parse_config_file(is, desc), vm);
}
//________________________________________________________________________________________
//
// too_many_positional_options
//
//________________________________________________________________________________________
void too_many_positional_options(options_description& desc, variables_map& vm)
{
const char* argv[] = {"program", "1", "2", "3"};
positional_options_description positional_args;
positional_args.add("two_positional_arguments", 2);
store(command_line_parser(4, argv).options(desc).positional(positional_args).run(), vm);
}
//________________________________________________________________________________________
//
// invalid_command_line_style
//
//________________________________________________________________________________________
void test_invalid_command_line_style_exception_msg()
{
string test_name = "invalid_command_line_style";
using namespace command_line_style;
options_description desc;
desc.add_options()("output,o", value<string>(), "the output file");
vector<int> invalid_styles;
invalid_styles.push_back(allow_short | short_allow_adjacent);
invalid_styles.push_back(allow_short | allow_dash_for_short);
invalid_styles.push_back(allow_long);
vector<string> invalid_diagnostics;
invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one "
"or other of 'command_line_style::allow_slash_for_short' "
"(slashes) or 'command_line_style::allow_dash_for_short' "
"(dashes) for short options.");
invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one "
"or other of 'command_line_style::short_allow_next' "
"(whitespace separated arguments) or "
"'command_line_style::short_allow_adjacent' ('=' "
"separated arguments) for short options.");
invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one "
"or other of 'command_line_style::long_allow_next' "
"(whitespace separated arguments) or "
"'command_line_style::long_allow_adjacent' ('=' "
"separated arguments) for long options.");
const char* argv[] = {"program"};
variables_map vm;
for (unsigned ii = 0; ii < 3; ++ii)
{
bool exception_thrown = false;
try
{
store(parse_command_line(1, argv, desc, invalid_styles[ii]), vm);
}
catch (invalid_command_line_style& e)
{
string error_msg("arguments are not allowed for unabbreviated option names");
CHECK_EQUAL(test_name, e.what(), invalid_diagnostics[ii]);
exception_thrown = true;
}
catch (std::exception& e)
{
BOOST_ERROR(string(test_name + ":\nUnexpected exception. ") + e.what() +
"\nExpected text:\n" + invalid_diagnostics[ii] + "\n");
exception_thrown = true;
}
if (!exception_thrown)
{
BOOST_ERROR(test_name << ": No exception thrown. ");
}
}
}
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*/)
{
test_ambiguous_option_exception_msg();
test_unknown_option_exception_msg();
test_multiple_occurrences_exception_msg();
test_missing_value_exception_msg();
test_invalid_option_value_exception_msg();
test_invalid_bool_value_exception_msg();
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;
// check_reading_file
test_name = "check_reading_file";
expected_message = "can not read options configuration file 'no_such_file'";
test_exception<reading_file>(test_name, expected_message, check_reading_file);
// config_file_wildcard
test_name = "config_file_wildcard";
expected_message = "options 'outpu*' and 'outp*' will both match the same arguments from the configuration file";
test_exception<error>(test_name, expected_message, config_file_wildcard);
// unrecognized_line
test_name = "unrecognized_line";
expected_message = "the options configuration file contains an invalid line 'funny wierd line'";
test_exception<invalid_syntax>(test_name, expected_message, unrecognized_line);
// abbreviated_options_in_config_file
test_name = "abbreviated_options_in_config_file";
expected_message = "abbreviated option names are not permitted in options configuration files";
test_exception<error>(test_name, expected_message, abbreviated_options_in_config_file);
test_name = "too_many_positional_options";
expected_message = "too many positional options have been specified on the command line";
test_exception<too_many_positional_options_error>(
test_name, expected_message, too_many_positional_options);
test_invalid_command_line_style_exception_msg();
return 0;
}

View File

@@ -1,60 +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>
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
# include <optional>
#endif
#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;
}
template<template<typename> class OptionalType>
void test_optional()
{
OptionalType<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<boost::optional>();
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
test_optional<std::optional>();
#endif
return 0;
}

View File

@@ -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()
@@ -55,17 +53,6 @@ void test_approximation()
BOOST_CHECK_EQUAL(desc.find("all", true).long_name(), "all");
BOOST_CHECK_EQUAL(desc.find("all-ch", true).long_name(), "all-chroots");
options_description desc2;
desc2.add_options()
("help", "display this message")
("config", value<string>(), "config file name")
("config-value", value<string>(), "single config value")
;
BOOST_CHECK_EQUAL(desc2.find("config", true).long_name(), "config");
BOOST_CHECK_EQUAL(desc2.find("config-value", true).long_name(),
"config-value");
// BOOST_CHECK(desc.count_approx("foo") == 1);
// set<string> a = desc.approximations("f");
@@ -74,61 +61,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 +111,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()
{
{
@@ -300,48 +217,16 @@ void test_default_values()
);
}
void test_value_name()
{
options_description desc("Supported options");
desc.add_options()
("include", value<string>()->value_name("directory"), "Search for headers in 'directory'.")
;
stringstream ss;
ss << desc;
BOOST_CHECK_EQUAL(ss.str(),
"Supported options:\n"
" --include directory Search for headers in 'directory'.\n"
);
}
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();
test_default_values();
test_value_name();
return 0;
}

View File

@@ -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*), const_cast<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(BOOST_BORLANDC) && ! defined(BOOST_EMBTC)) || (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();

View File

@@ -21,7 +21,7 @@ void do_it()
f.write("(\"opt%d\", value<int>())\n")
f.write(";\n}\n")
f.close()
os.system(compiler_command + " -c -save-temps -I /home/ghost/Work/Boost/boost-svn program_options_test.cpp")
os.system(compiler_command + " -c -save-temps -I /home/ghost/Work/boost-rc program_options_test.cpp")
nm = os.popen("nm -S program_options_test.o")
for l in nm:
@@ -45,7 +45,7 @@ def run_tests(range, compiler_command):
print "Avarage: ", (last_size-first_size)/(range[-1]-range[0])
if __name__ == '__main__':
for compiler in [ "g++ -Os", "g++ -O3"]:
for compiler in [ "g++-3.3 -Os", "g++-3.3 -O3", "g++-3.4 -Os", "g++-3.4 -O3"]:
print "****", compiler, "****"
run_tests(range(1, 20), compiler)

View File

@@ -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();
}

View File

@@ -23,36 +23,35 @@ 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 +66,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 +79,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 +91,6 @@ int main(int /*argc*/, char* av[])
{
required_throw_test();
simple_required_test(av[1]);
multiname_required_test();
return 0;
}

View File

@@ -3,9 +3,6 @@
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
// This will eventually stop working when <boost/progress.hpp> is removed
#define BOOST_TIMER_ENABLE_DEPRECATED
#include <cstring>
#include <cassert>
#include <string>

View File

@@ -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

View File

@@ -9,12 +9,13 @@
#include <cctype>
#include <iostream>
#include <stdlib.h>
#include <boost/program_options/parsers.hpp>
using namespace std;
#include <boost/program_options/parsers.hpp>
using namespace boost::program_options;
void check_equal(const std::vector<string>& actual, const char **expected, int n)
void check_equal(const std::vector<string>& actual, char **expected, int n)
{
if (actual.size() != n)
{
@@ -38,7 +39,7 @@ void test_winmain()
#define C ,
#define TEST(input, expected) \
const char* BOOST_PP_CAT(e, __LINE__)[] = expected;\
char* BOOST_PP_CAT(e, __LINE__)[] = expected;\
vector<string> BOOST_PP_CAT(v, __LINE__) = split_winmain(input);\
check_equal(BOOST_PP_CAT(v, __LINE__), BOOST_PP_CAT(e, __LINE__),\
sizeof(BOOST_PP_CAT(e, __LINE__))/sizeof(char*));