Skip to content

Commit

Permalink
Merge pull request #43 from Luthaf/master
Browse files Browse the repository at this point in the history
Support GCC 4.8, using Boost.Regex
  • Loading branch information
jaredgrubb authored Jul 24, 2016
2 parents c15f292 + 8f926b6 commit 52e3064
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 107 deletions.
27 changes: 20 additions & 7 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,24 @@ matrix:
apt:
sources: ['ubuntu-toolchain-r-test', 'george-edison55-precise-backports']
packages: ["g++-5", "cmake-data", "cmake"]
- os: linux
env:
- COMPILER=g++-4.8 USE_BOOST_REGEX=ON
addons:
apt:
sources: ['ubuntu-toolchain-r-test', 'george-edison55-precise-backports', 'boost-latest']
packages: ["g++-4.8", "cmake-data", "cmake", "libboost-regex1.55-dev"]

- os: linux
env:
env:
- COMPILER=clang++-3.6 STDLIB=libc++
addons:
apt:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.6', 'george-edison55-precise-backports']
packages: ["clang-3.6", "cmake-data", "cmake"]

- os: linux
env:
env:
- COMPILER=clang++-3.7 STDLIB=libc++
addons:
apt:
Expand All @@ -29,35 +36,41 @@ matrix:

- os: osx
osx_image: xcode6.4
env:
env:
- COMPILER=clang++ V='Apple LLVM 6.4'
- COMPILER=clang++ V='Apple LLVM 6.4' WITH_CPP14=true

- os: osx
osx_image: xcode7
env:
env:
- COMPILER=clang++ V='Apple LLVM 7.0'
- COMPILER=clang++ V='Apple LLVM 7.0' WITH_CPP14=true

before_install:
- |
if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
brew install cmake
brew rm --force cmake && brew install cmake
fi
- CMAKE_CXX_FLAGS+=" -Wall"

- if [[ "${WITH_CPP14}" == "true" ]]; then CMAKE_OPTIONS+=" -DCMAKE_CXX_STANDARD=14"; fi
- |
if [[ "${USE_BOOST_REGEX}" == "ON" ]]; then
CMAKE_OPTIONS+=" -DUSE_BOOST_REGEX=ON"
CMAKE_OPTIONS+=" -DBoost_REGEX_LIBRARY_DEBUG=/usr/lib/x86_64-linux-gnu/libboost_regex.so.1.55.0"
CMAKE_OPTIONS+=" -DBoost_REGEX_LIBRARY_RELEASE=/usr/lib/x86_64-linux-gnu/libboost_regex.so.1.55.0"
fi
- if [[ "${STDLIB}" == "libc++" ]]; then CMAKE_CXX_FLAGS+=" -stdlib=libc++"; fi

- sh ${COMPILER} --version || true
- ${COMPILER} --version

before_script:
- rm -rf build/
- mkdir build
- cd build
- cmake -DCMAKE_CXX_COMPILER=${COMPILER} -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} -DWITH_TESTS=1 -DWITH_EXAMPLE=1 ${CMAKE_OPTIONS} ..

script:
script:
- cmake --build .
- python run_tests
14 changes: 14 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ include(GNUInstallDirs)
#============================================================================
option(WITH_TESTS "Build tests." OFF)
option(WITH_EXAMPLE "Build example." OFF)
option(USE_BOOST_REGEX "Replace std::regex with Boost.Regex" OFF)

#============================================================================
# Internal compiler options
Expand Down Expand Up @@ -52,6 +53,19 @@ if(NOT MSVC)
set_target_properties(docopt_s PROPERTIES OUTPUT_NAME docopt)
endif()

if(USE_BOOST_REGEX)
add_definitions("-DDOCTOPT_USE_BOOST_REGEX")
# This is needed on Linux, where linking a static library into docopt.so
# fails because boost static libs are not compiled with -fPIC
set(Boost_USE_STATIC_LIBS OFF)
find_package(Boost 1.53 REQUIRED COMPONENTS regex)
include_directories(${Boost_INCLUDE_DIRS})
target_link_libraries(docopt ${Boost_LIBRARIES})
if(WITH_STATIC)
target_link_libraries(docopt_s ${Boost_LIBRARIES})
endif()
endif()

#============================================================================
# Examples
#============================================================================
Expand Down
28 changes: 15 additions & 13 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ and instead can write only the help message--*the way you want it*.

int main(int argc, const char** argv)
{
std::map<std::string, docopt::value> args
= docopt::docopt(USAGE,
std::map<std::string, docopt::value> args
= docopt::docopt(USAGE,
{ argv + 1, argv + argc },
true, // show help if requested
"Naval Fate 2.0"); // version string
Expand Down Expand Up @@ -78,7 +78,10 @@ to work with docopt:
- GCC 4.9
- Visual C++ 2015 RC

Note that GCC-4.8 will not work due to its missing the ``regex`` module.
GCC-4.8 can work, but the std::regex module needs to be replaced with ``Boost.Regex``.
In that case, you will need to define ``DOCTOPT_USE_BOOST_REGEX`` when compiling
docopt, and link your code with the appropriated Boost libraries. A relativley
recent version of Boost is needed: 1.55 works, but 1.46 does not for example.

This port is licensed under the MIT license, just like the original module.
However, we are also dual-licensing this code under the Boost License, version 1.0,
Expand All @@ -92,8 +95,8 @@ The differences from the Python port are:
* a ``docopt::value`` type to hold the various value types that can be parsed.
We considered using boost::variant, but it seems better to have no external
dependencies (beyond a good STL).
* because C++ is statically-typed and Python is not, we had to make some
changes to the interfaces of the internal parse tree types.
* because C++ is statically-typed and Python is not, we had to make some
changes to the interfaces of the internal parse tree types.
* because ``std::regex`` does not have an equivalent to Python's regex.split,
some of the regex's had to be restructured and additional loops used.

Expand Down Expand Up @@ -126,7 +129,7 @@ API
- ``argv`` is a vector of strings representing the args passed. Although
main usually takes a ``(int argc, const char** argv)`` pair, you can
pass the value ``{argv+1, argv+argc}`` to generate the vector automatically.
(Note we skip the argv[0] argument!) Alternatively you can supply a list of
(Note we skip the argv[0] argument!) Alternatively you can supply a list of
strings like ``{ "--verbose", "-o", "hai.txt" }``.

- ``help``, by default ``true``, specifies whether the parser should
Expand Down Expand Up @@ -155,8 +158,8 @@ API
compatibility with POSIX, or if you want to dispatch your arguments
to other programs.

The **return** value is a ``map<string, docopt::value>`` with options,
arguments and commands as keys, spelled exactly like in your help message.
The **return** value is a ``map<string, docopt::value>`` with options,
arguments and commands as keys, spelled exactly like in your help message.
Long versions of options are given priority. For example, if you invoke the
top example as::

Expand Down Expand Up @@ -372,7 +375,7 @@ We have an extensive list of `examples
every aspect of functionality of **docopt**. Try them out, read the
source if in doubt.

There are also very intersting applications and ideas at that page.
There are also very intersting applications and ideas at that page.
Check out the sister project for more information!

Subparsers, multi-level help and *huge* applications (like git)
Expand All @@ -397,7 +400,7 @@ a C++ test case runner (run_testcase.cpp)::

$ clang++ --std=c++11 --stdlib=libc++ docopt.cpp run_testcase.cpp -o run_testcase
$ python run_tests.py
PASS (175)
PASS (175)

You can also compile the example shown at the start (included as example.cpp)::

Expand All @@ -424,10 +427,10 @@ You can also compile the example shown at the start (included as example.cpp)::
Development
---------------------------------------------------

Comments and suggestions are *very* welcome! If you find issues, please
Comments and suggestions are *very* welcome! If you find issues, please
file them and help improve our code!

Please note, however, that we have tried to stay true to the original
Please note, however, that we have tried to stay true to the original
Python code. If you have any major patches, structural changes, or new features,
we might want to first negotiate these changes into the Python code first.
However, bring it up! Let's hear it!
Expand All @@ -439,4 +442,3 @@ Changelog
first release with stable API will be 1.0.0 (soon).

- 0.6.1 The initial C++ port of docopt.py

27 changes: 9 additions & 18 deletions docopt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#include <unordered_map>
#include <map>
#include <string>
#include <regex>
#include <iostream>
#include <cassert>
#include <cstddef>
Expand Down Expand Up @@ -522,31 +521,23 @@ static PatternList parse_argv(Tokens tokens, std::vector<Option>& options, bool
return ret;
}

static std::vector<Option> parse_defaults(std::string const& doc) {
// This pattern is a bit more complex than the python docopt one due to lack of
// re.split. Effectively, it grabs any line with leading whitespace and then a
// hyphen; it stops grabbing when it hits another line that also looks like that.
static std::regex const pattern {
std::vector<Option> parse_defaults(std::string const& doc) {
// This pattern is a delimiter by which we split the options.
// The delimiter is a new line followed by a whitespace(s) followed by one or two hyphens.
static std::regex const re_delimiter{
"(?:^|\\n)[ \\t]*" // a new line with leading whitespace
"(-(.|\\n)*?)" // a hyphen, and then grab everything it can...
"(?=\\n[ \\t]*-|$)" // .. until it hits another new line with space and a hyphen
"(?=-{1,2})" // [split happens here] (positive lookahead) ... and followed by one or two hyphes
};

std::vector<Option> defaults;
for (auto s : parse_section("options:", doc)) {
s.erase(s.begin(), s.begin() + s.find(':') + 1); // get rid of "options:"

for(auto s : parse_section("options:", doc)) {
s.erase(s.begin(), s.begin()+static_cast<std::ptrdiff_t>(s.find(':'))+1); // get rid of "options:"

std::for_each(std::sregex_iterator{ s.begin(), s.end(), pattern },
std::sregex_iterator{},
[&](std::smatch const& m)
{
std::string opt = m[1].str();

for (const auto& opt : regex_split(s, re_delimiter)) {
if (starts_with(opt, "-")) {
defaults.emplace_back(Option::parse(opt));
}
});
}
}

return defaults;
Expand Down
Loading

0 comments on commit 52e3064

Please sign in to comment.