From de8fd43cc172b0821fe03828a68e151801640137 Mon Sep 17 00:00:00 2001 From: Christopher Dembia Date: Wed, 10 Aug 2016 12:01:24 -0700 Subject: [PATCH 01/31] Support Xcode by not using CMake object libraries. CMake allows specifying an object file as a source file for a library, but Xcode does not allow creating a library whose source files are *only* object files; there needs to be at least one real source file. This commit gets around this issue by not using object library targets with Xcode. --- CMakeLists.txt | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e292d8..f8af81f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,11 +39,20 @@ set(docopt_HEADERS #============================================================================ # Compile targets #============================================================================ -add_library(docopt_o OBJECT ${docopt_SOURCES} ${docopt_HEADERS}) -set_target_properties(docopt_o PROPERTIES POSITION_INDEPENDENT_CODE TRUE) - -add_library(docopt SHARED $) -add_library(docopt_s STATIC $) +if(XCODE) + # Xcode does not support libraries with only object files as sources. + # See https://cmake.org/cmake/help/v3.0/command/add_library.html?highlight=add_library + add_library(docopt SHARED ${docopt_SOURCES} ${docopt_HEADERS}) + add_library(docopt_s STATIC ${docopt_SOURCES} ${docopt_HEADERS}) +else() + # If not using Xcode, we will create an intermediate object target to avoid + # compiling the source code twice. + add_library(docopt_o OBJECT ${docopt_SOURCES} ${docopt_HEADERS}) + set_target_properties(docopt_o PROPERTIES POSITION_INDEPENDENT_CODE TRUE) + + add_library(docopt SHARED $) + add_library(docopt_s STATIC $) +endif() target_include_directories(docopt PUBLIC $ $) target_include_directories(docopt_s PUBLIC $ $) From 33d36b0d6e80f8877d3bd8953630e7aa94562952 Mon Sep 17 00:00:00 2001 From: Ghislain Antony Vaillant Date: Tue, 16 Aug 2016 19:56:31 +0100 Subject: [PATCH 02/31] Fix install directory of CMake package in multiarch environments. --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e292d8..6213207 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,8 +105,8 @@ install(FILES ${docopt_HEADERS} DESTINATION include/docopt) # CMake Package include(CMakePackageConfigHelpers) write_basic_package_version_file("${PROJECT_BINARY_DIR}/docopt-config-version.cmake" COMPATIBILITY SameMajorVersion) -install(FILES docopt-config.cmake ${PROJECT_BINARY_DIR}/docopt-config-version.cmake DESTINATION "lib/cmake/docopt") -install(EXPORT ${export_name} DESTINATION "lib/cmake/docopt") +install(FILES docopt-config.cmake ${PROJECT_BINARY_DIR}/docopt-config-version.cmake DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/docopt") +install(EXPORT ${export_name} DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/docopt") #============================================================================ # CPack From 3475d45fa5236c43480e00911dee1c68958e3176 Mon Sep 17 00:00:00 2001 From: Christopher Lee Dembia Date: Fri, 26 Aug 2016 12:50:00 -0700 Subject: [PATCH 03/31] Export symbols on windows. --- CMakeLists.txt | 3 +++ docopt.h | 23 ++++++++++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d14cc81..4f84d23 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,9 @@ endif() target_include_directories(docopt PUBLIC $ $) target_include_directories(docopt_s PUBLIC $ $) +# To control the exporting of symbols (on Windows). +set_target_properties(docopt PROPERTIES DEFINE_SYMBOL DOCOPT_EXPORTS) + if(NOT MSVC) set_target_properties(docopt PROPERTIES OUTPUT_NAME docopt) set_target_properties(docopt_s PROPERTIES OUTPUT_NAME docopt) diff --git a/docopt.h b/docopt.h index 5a65e10..0acd843 100644 --- a/docopt.h +++ b/docopt.h @@ -16,9 +16,22 @@ #include #ifdef DOCOPT_HEADER_ONLY -#define DOCOPT_INLINE inline + #define DOCOPT_INLINE inline + #define DOCOPTAPI #else -#define DOCOPT_INLINE + #define DOCOPT_INLINE + + // On Windows, export certain symbols so they are available + // to users of docopt.dll (shared library). + #ifdef WIN32 + #ifdef DOCOPT_EXPORTS + #define DOCOPTAPI __declspec(dllexport) + #else + #define DOCOPTAPI __declspec(dllimport) + #endif + #else + #define DOCOPTAPI + #endif #endif namespace docopt { @@ -48,7 +61,7 @@ namespace docopt { /// @throws DocoptExitHelp if 'help' is true and the user has passed the '--help' argument /// @throws DocoptExitVersion if 'version' is true and the user has passed the '--version' argument /// @throws DocoptArgumentError if the user's argv did not match the usage patterns - std::map docopt_parse(std::string const& doc, + std::map DOCOPTAPI docopt_parse(std::string const& doc, std::vector const& argv, bool help = true, bool version = true, @@ -61,7 +74,7 @@ namespace docopt { /// * DocoptExitHelp - print usage string and terminate (with exit code 0) /// * DocoptExitVersion - print version and terminate (with exit code 0) /// * DocoptArgumentError - print error and usage string and terminate (with exit code -1) - std::map docopt(std::string const& doc, + std::map DOCOPTAPI docopt(std::string const& doc, std::vector const& argv, bool help = true, std::string const& version = {}, @@ -69,7 +82,7 @@ namespace docopt { } #ifdef DOCOPT_HEADER_ONLY -#include "docopt.cpp" + #include "docopt.cpp" #endif #endif /* defined(docopt__docopt_h_) */ From f84c6f4e8f44c26a2e6cdf42cb324c53613071c0 Mon Sep 17 00:00:00 2001 From: Christopher Lee Dembia Date: Sun, 16 Oct 2016 19:51:57 -0700 Subject: [PATCH 04/31] Fix EXPORTS macros for building static library on windows. --- CMakeLists.txt | 19 ++++++++++++++++--- docopt.h | 27 +++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d14cc81..2edd48e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,14 +39,18 @@ set(docopt_HEADERS #============================================================================ # Compile targets #============================================================================ -if(XCODE) +if(MSVC OR XCODE) + # MSVC requires __declspec() attributes, which are achieved via the + # DOCOPT_DLL and DOCOPT_EXPORTS macros below. Since those macros are only + # defined when building a shared library, we must build the shared and + # static libraries completely separately. # Xcode does not support libraries with only object files as sources. # See https://cmake.org/cmake/help/v3.0/command/add_library.html?highlight=add_library add_library(docopt SHARED ${docopt_SOURCES} ${docopt_HEADERS}) add_library(docopt_s STATIC ${docopt_SOURCES} ${docopt_HEADERS}) else() - # If not using Xcode, we will create an intermediate object target to avoid - # compiling the source code twice. + # If not using MSVC or Xcode, we will create an intermediate object target + # to avoid compiling the source code twice. add_library(docopt_o OBJECT ${docopt_SOURCES} ${docopt_HEADERS}) set_target_properties(docopt_o PROPERTIES POSITION_INDEPENDENT_CODE TRUE) @@ -57,6 +61,15 @@ endif() target_include_directories(docopt PUBLIC $ $) target_include_directories(docopt_s PUBLIC $ $) +if(MSVC) + # DOCOPT_DLL: Must be specified when building *and* when using the DLL. + # That's what the "PUBLIC" means. + # DOCOPT_EXPORTS: Must use __declspec(dllexport) when building the DLL. + # "PRIVATE" means it's only defined when building the DLL. + target_compile_definitions(docopt PUBLIC DOCOPT_DLL + PRIVATE DOCOPT_EXPORTS) +endif() + if(NOT MSVC) set_target_properties(docopt PROPERTIES OUTPUT_NAME docopt) set_target_properties(docopt_s PROPERTIES OUTPUT_NAME docopt) diff --git a/docopt.h b/docopt.h index 5a65e10..01e423d 100644 --- a/docopt.h +++ b/docopt.h @@ -16,9 +16,28 @@ #include #ifdef DOCOPT_HEADER_ONLY -#define DOCOPT_INLINE inline + #define DOCOPT_INLINE inline + #define DOCOPT_API #else -#define DOCOPT_INLINE + #define DOCOPT_INLINE + + // With Microsoft Visual Studio, export certain symbols so they + // are available to users of docopt.dll (shared library). The DOCOPT_DLL + // macro should be defined if building a DLL (with Visual Studio), + // and by clients using the DLL. The CMakeLists.txt and the + // docopt-config.cmake it generates handle this. + #ifdef DOCOPT_DLL + // Whoever is *building* the DLL should define DOCOPT_EXPORTS. + // The CMakeLists.txt that comes with docopt does this. + // Clients of docopt.dll should NOT define DOCOPT_EXPORTS. + #ifdef DOCOPT_EXPORTS + #define DOCOPT_API __declspec(dllexport) + #else + #define DOCOPT_API __declspec(dllimport) + #endif + #else + #define DOCOPT_API + #endif #endif namespace docopt { @@ -48,7 +67,7 @@ namespace docopt { /// @throws DocoptExitHelp if 'help' is true and the user has passed the '--help' argument /// @throws DocoptExitVersion if 'version' is true and the user has passed the '--version' argument /// @throws DocoptArgumentError if the user's argv did not match the usage patterns - std::map docopt_parse(std::string const& doc, + std::map DOCOPT_API docopt_parse(std::string const& doc, std::vector const& argv, bool help = true, bool version = true, @@ -61,7 +80,7 @@ namespace docopt { /// * DocoptExitHelp - print usage string and terminate (with exit code 0) /// * DocoptExitVersion - print version and terminate (with exit code 0) /// * DocoptArgumentError - print error and usage string and terminate (with exit code -1) - std::map docopt(std::string const& doc, + std::map DOCOPT_API docopt(std::string const& doc, std::vector const& argv, bool help = true, std::string const& version = {}, From b88d09be8d8550c64b24b8f7d7fb5919a1ac0a81 Mon Sep 17 00:00:00 2001 From: Christopher Lee Dembia Date: Sun, 16 Oct 2016 19:56:59 -0700 Subject: [PATCH 05/31] Replace spaces with tab. --- docopt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docopt.h b/docopt.h index 18f9db1..4c40741 100644 --- a/docopt.h +++ b/docopt.h @@ -67,7 +67,7 @@ namespace docopt { /// @throws DocoptExitHelp if 'help' is true and the user has passed the '--help' argument /// @throws DocoptExitVersion if 'version' is true and the user has passed the '--version' argument /// @throws DocoptArgumentError if the user's argv did not match the usage patterns - std::map DOCOPT_API docopt_parse(std::string const& doc, + std::map DOCOPT_API docopt_parse(std::string const& doc, std::vector const& argv, bool help = true, bool version = true, From b6d34862c959b16dcd824186a0ba64d48555bbfb Mon Sep 17 00:00:00 2001 From: Christopher Lee Dembia Date: Sun, 16 Oct 2016 20:01:28 -0700 Subject: [PATCH 06/31] Tabs -> spaces in CMakeLists --- CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2edd48e..ee01e7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,10 +40,10 @@ set(docopt_HEADERS # Compile targets #============================================================================ if(MSVC OR XCODE) - # MSVC requires __declspec() attributes, which are achieved via the - # DOCOPT_DLL and DOCOPT_EXPORTS macros below. Since those macros are only - # defined when building a shared library, we must build the shared and - # static libraries completely separately. + # MSVC requires __declspec() attributes, which are achieved via the + # DOCOPT_DLL and DOCOPT_EXPORTS macros below. Since those macros are only + # defined when building a shared library, we must build the shared and + # static libraries completely separately. # Xcode does not support libraries with only object files as sources. # See https://cmake.org/cmake/help/v3.0/command/add_library.html?highlight=add_library add_library(docopt SHARED ${docopt_SOURCES} ${docopt_HEADERS}) From 18110222dc9cb57ec880ce24fbbd7291b2d1046e Mon Sep 17 00:00:00 2001 From: Jared Grubb Date: Fri, 2 Dec 2016 11:12:44 -0800 Subject: [PATCH 07/31] Release notes: add note about this 0.6.2 tag --- README.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index b7e871e..fc01274 100644 --- a/README.rst +++ b/README.rst @@ -441,4 +441,5 @@ Changelog **docopt** follows `semantic versioning `_. The first release with stable API will be 1.0.0 (soon). -- 0.6.1 The initial C++ port of docopt.py +- 0.6.2 Bugfix release (still based on docopt 0.6.1) +- 0.6.1 The initial C++ port of docopt.py (based on docopt 0.6.1) From daaad2927cac7a42cc34862b58034263ac920c07 Mon Sep 17 00:00:00 2001 From: Mariusz Wojcik Date: Sat, 31 Dec 2016 20:45:55 +0100 Subject: [PATCH 08/31] Add support for pkgconfig --- CMakeLists.txt | 3 +++ docopt.pc.in | 9 +++++++++ 2 files changed, 12 insertions(+) create mode 100644 docopt.pc.in diff --git a/CMakeLists.txt b/CMakeLists.txt index ee01e7c..70df5ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -130,6 +130,9 @@ write_basic_package_version_file("${PROJECT_BINARY_DIR}/docopt-config-version.cm install(FILES docopt-config.cmake ${PROJECT_BINARY_DIR}/docopt-config-version.cmake DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/docopt") install(EXPORT ${export_name} DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/docopt") +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/docopt.pc.in ${CMAKE_CURRENT_BINARY_DIR}/docopt.pc @ONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/docopt.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + #============================================================================ # CPack #============================================================================ diff --git a/docopt.pc.in b/docopt.pc.in new file mode 100644 index 0000000..0ac4ffd --- /dev/null +++ b/docopt.pc.in @@ -0,0 +1,9 @@ +libdir=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@ +includedir=@CMAKE_INSTALL_PREFIX@/include/docopt + +Name: docopt.cpp +Description: C++11 port of docopt +Version: @PROJECT_VERSION@ +Requires: +Libs: -L${libdir} -ldocopt +Cflags: -I${includedir} From b586bbeb393d2cc78e7cf560302c4c6391e866ae Mon Sep 17 00:00:00 2001 From: Ghislain Antony Vaillant Date: Thu, 2 Mar 2017 12:34:56 +0000 Subject: [PATCH 09/31] Fixup project version The current release is tagged `v0.6.2` but the project version was still at `0.6.1` --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ee01e7c..d806cd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.1) -project(docopt.cpp VERSION 0.6.1) +project(docopt.cpp VERSION 0.6.2) include(GNUInstallDirs) From 56a3ae39b59c48b2112072f427f8ecad014ca9e6 Mon Sep 17 00:00:00 2001 From: Nikodemus Siivola Date: Fri, 13 Apr 2018 11:59:50 +0300 Subject: [PATCH 10/31] hide #pragma mark's away from the compiler --- CMakeLists.txt | 5 ----- docopt.cpp | 2 ++ docopt_private.h | 2 ++ docopt_util.h | 2 ++ 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d806cd8..1aba5ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,11 +20,6 @@ if(NOT CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD LESS 11) set(CMAKE_CXX_STANDARD 11) endif() -# Suppression of "unknown pragma" warning on GCC -if(CMAKE_COMPILER_IS_GNUCXX) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-pragmas") # Code uses #pragma mark -endif() - #============================================================================ # Sources & headers #============================================================================ diff --git a/docopt.cpp b/docopt.cpp index e875d2f..937845d 100644 --- a/docopt.cpp +++ b/docopt.cpp @@ -54,8 +54,10 @@ std::ostream& docopt::operator<<(std::ostream& os, value const& val) return os; } +#if 0 #pragma mark - #pragma mark Parsing stuff +#endif class Tokens { public: diff --git a/docopt_private.h b/docopt_private.h index 77bf2bd..931986b 100644 --- a/docopt_private.h +++ b/docopt_private.h @@ -322,8 +322,10 @@ namespace docopt { bool match(PatternList& left, std::vector>& collected) const override; }; +#if 0 #pragma mark - #pragma mark inline implementations +#endif inline std::vector Pattern::leaves() { diff --git a/docopt_util.h b/docopt_util.h index c9a2647..b504609 100644 --- a/docopt_util.h +++ b/docopt_util.h @@ -19,8 +19,10 @@ namespace std { #include #endif +#if 0 #pragma mark - #pragma mark General utility +#endif namespace { bool starts_with(std::string const& str, std::string const& prefix) From 72a8e3e01effe22ac0f4e29c14153743172efcb5 Mon Sep 17 00:00:00 2001 From: Cheney-Wang Date: Wed, 31 Oct 2018 19:21:26 -0700 Subject: [PATCH 11/31] Add missing include to use std::runtime_error --- docopt_value.h | 1 + 1 file changed, 1 insertion(+) diff --git a/docopt_value.h b/docopt_value.h index a923219..829ee55 100644 --- a/docopt_value.h +++ b/docopt_value.h @@ -9,6 +9,7 @@ #ifndef docopt__value_h_ #define docopt__value_h_ +#include #include #include #include // std::hash From 6244119b0b0334411a7ca4e1f97b9cc3a61ab9ac Mon Sep 17 00:00:00 2001 From: Tom de Geus Date: Thu, 21 Nov 2019 15:04:43 +0100 Subject: [PATCH 12/31] Updating readme: added Conda and CMake instructions; various spelling updates --- README.rst | 74 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 20 deletions(-) diff --git a/README.rst b/README.rst index fc01274..5fe8b4f 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,13 @@ ``docopt.cpp``: A C++11 Port ============================ + +Contents +-------- + +.. contents:: + :local: + :depth: 3 + docopt creates *beautiful* command-line interfaces -------------------------------------------------- @@ -58,13 +66,40 @@ and instead can write only the help message--*the way you want it*. Beat that! The option parser is generated based on the docstring above that is passed to ``docopt::docopt`` function. ``docopt`` parses the usage pattern (``"Usage: ..."``) and option descriptions (lines starting -with dash "``-``") and ensures that the program invocation matches the +with a dash "``-``") and ensures that the program invocation matches the usage pattern; it parses options, arguments and commands based on that. The basic idea is that *a good help message has all necessary information in it to make a parser*. +Getting and using +----------------- + +To get *docopt.cpp*, the simplest is to use `Conda `_:: + + conda install -c conda-forge docopt.cpp + +Alternatively manual installation is done using (unix):: + + git clone + cmake . + make install + +To link *docopt.cpp*, the simplest is to use CMake. The general structure of your +``CMakeLists.txt`` would be as follows:: + + cmake_minimum_required(VERSION 3.1) + + project(example) + + find_package(docopt COMPONENTS CXX REQUIRED) + include_directories(${DOCOPT_INCLUDE_DIRS}) + + add_executable(${PROJECT_NAME} ...) + + target_link_libraries(${PROJECT_NAME} docopt) + C++11 port details ---------------------------------------------------- +------------------ This is a port of the ``docopt.py`` module (https://github.com/docopt/docopt), and we have tried to maintain full feature parity (and code structure) as the @@ -80,7 +115,7 @@ to work with docopt: 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 +docopt, and link your code with the appropriated Boost libraries. A relatively 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. @@ -101,7 +136,7 @@ The differences from the Python port are: some of the regex's had to be restructured and additional loops used. API ---------------------------------------------------- +--- .. code:: c++ @@ -182,16 +217,15 @@ If any parsing error (in either the usage, or due to incorrect user inputs) is encountered, the program will exit with exit code -1. Note that there is another function that does not exit on error, and instead will -propogate an exception that you can catch and process as you like. See the docopt.h file +propagate an exception that you can catch and process as you like. See the docopt.h file for information on the exceptions and usage: .. code:: c++ docopt::docopt_parse(doc, argv, help /* =true */, version /* =true */, options_first /* =false) - Help message format ---------------------------------------------------- +------------------- Help message consists of 2 parts: @@ -210,7 +244,7 @@ Help message consists of 2 parts: Their format is described below; other text is ignored. Usage pattern format ----------------------------------------------------------------------- +-------------------- **Usage pattern** is a substring of ``doc`` that starts with ``usage:`` (case *insensitive*) and ends with a *visibly* empty line. @@ -263,7 +297,7 @@ Use the following constructs to specify patterns: - **|** (pipe) **mutually exclusive** elements. Group them using **( )** if one of the mutually exclusive elements is required: ``my_program (--clockwise | --counter-clockwise) TIME``. Group - them using **[ ]** if none of the mutually-exclusive elements are + them using **[ ]** if none of the mutually exclusive elements are required: ``my_program [--left | --right]``. - **...** (ellipsis) **one or more** elements. To specify that arbitrary number of repeating elements could be accepted, use @@ -291,7 +325,7 @@ then number of occurrences of the option will be counted. I.e. ``args['-v']`` will be ``2`` if program was invoked as ``my_program -vv``. Same works for commands. -If your usage patterns allows to match same-named option with argument +If your usage pattern allows to match same-named option with argument or positional argument several times, the matched arguments will be collected into a list:: @@ -301,9 +335,8 @@ I.e. invoked with ``my_program file1 file2 --path=./here --path=./there`` the returned dict will contain ``args[''] == ['file1', 'file2']`` and ``args['--path'] == ['./here', './there']``. - Option descriptions format ----------------------------------------------------------------------- +-------------------------- **Option descriptions** consist of a list of options that you put below your usage patterns. @@ -328,7 +361,7 @@ The rules are as follows: argument after space (or equals "``=``" sign) as shown below. Follow either or UPPER-CASE convention for options' arguments. You can use comma if you want to separate options. In - the example below, both lines are valid, however you are recommended + the example below, both lines are valid. However you are recommended to stick to a single style.:: -o FILE --output=FILE # without comma, with "=" sign @@ -352,7 +385,7 @@ The rules are as follows: - If the option is not repeatable, the value inside ``[default: ...]`` will be interpreted as string. If it *is* repeatable, it will be - splited into a list on whitespace:: + split into a list on whitespace:: Usage: my_program [--repeatable= --repeatable=] [--another-repeatable=]... @@ -368,18 +401,18 @@ The rules are as follows: --not-repeatable= [default: ./here ./there] Examples ----------------------------------------------------------------------- +-------- We have an extensive list of `examples `_ which cover 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 interesting applications and ideas at that page. Check out the sister project for more information! Subparsers, multi-level help and *huge* applications (like git) ----------------------------------------------------------------------- +--------------------------------------------------------------- If you want to split your usage-pattern into several, implement multi-level help (with separate help-screen for each subcommand), @@ -391,7 +424,8 @@ we implemented a subset of git command-line interface as an example: `_ Compiling the example / Running the tests ----------------------------------------------------------------------- +----------------------------------------- + The original Python module includes some language-agnostic unit tests, and these can be run with this port as well. @@ -425,7 +459,7 @@ You can also compile the example shown at the start (included as example.cpp):: shoot: false Development ---------------------------------------------------- +----------- Comments and suggestions are *very* welcome! If you find issues, please file them and help improve our code! @@ -436,7 +470,7 @@ we might want to first negotiate these changes into the Python code first. However, bring it up! Let's hear it! Changelog ---------------------------------------------------- +--------- **docopt** follows `semantic versioning `_. The first release with stable API will be 1.0.0 (soon). From 7e487686590f8309e6e086859a838d39b99af4ac Mon Sep 17 00:00:00 2001 From: Jared Grubb Date: Thu, 28 Nov 2019 13:06:35 -0800 Subject: [PATCH 13/31] OSX: update the Xcode versions --- .travis.yml | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index d3e842c..65d57cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,22 +35,28 @@ matrix: packages: ["clang-3.7", "cmake-data", "cmake"] - os: osx - osx_image: xcode6.4 + osx_image: xcode9.4 env: - - COMPILER=clang++ V='Apple LLVM 6.4' - - COMPILER=clang++ V='Apple LLVM 6.4' WITH_CPP14=true + - COMPILER=clang++ V='Apple LLVM 9.1' + - COMPILER=clang++ V='Apple LLVM 9.1' WITH_CPP14=true - os: osx - osx_image: xcode7 + osx_image: xcode10.3 env: - - COMPILER=clang++ V='Apple LLVM 7.0' - - COMPILER=clang++ V='Apple LLVM 7.0' WITH_CPP14=true + - COMPILER=clang++ V='Apple LLVM 10.0' + - COMPILER=clang++ V='Apple LLVM 10.0' WITH_CPP14=true + - os: osx + osx_image: xcode11.2 + env: + - COMPILER=clang++ V='Apple LLVM 11.0' + - COMPILER=clang++ V='Apple LLVM 11.0' WITH_CPP14=true before_install: - - | - if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then - brew rm --force cmake && brew install cmake - fi + # - | + # if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then + # brew update + # brew rm --force cmake && brew install cmake + # fi - CMAKE_CXX_FLAGS+=" -Wall" From 69682578d4dbb59b297a15ea537f2b1b8735c7bc Mon Sep 17 00:00:00 2001 From: Eero Aaltonen Date: Thu, 20 Jun 2019 16:21:20 +0300 Subject: [PATCH 14/31] Set library VERSION and SOVERSION With soversion and version specified, `install` target will install the library with the specified version and also create the proper symlink. --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 23da468..feff32e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,6 +50,10 @@ else() set_target_properties(docopt_o PROPERTIES POSITION_INDEPENDENT_CODE TRUE) add_library(docopt SHARED $) + set_target_properties(docopt PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} + ) add_library(docopt_s STATIC $) endif() From d915352f05c2de4a2b027f335fe0dc97cce81c0e Mon Sep 17 00:00:00 2001 From: Jared Grubb Date: Thu, 28 Nov 2019 19:35:23 -0800 Subject: [PATCH 15/31] OSX: remove the commented out parts --- .travis.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 65d57cd..42541e3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,12 +52,6 @@ matrix: - COMPILER=clang++ V='Apple LLVM 11.0' WITH_CPP14=true before_install: - # - | - # if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then - # brew update - # brew rm --force cmake && brew install cmake - # fi - - CMAKE_CXX_FLAGS+=" -Wall" - if [[ "${WITH_CPP14}" == "true" ]]; then CMAKE_OPTIONS+=" -DCMAKE_CXX_STANDARD=14"; fi From 1cb3c4af8173a7415e1bb20aef94675eb5f59ae3 Mon Sep 17 00:00:00 2001 From: Jared Grubb Date: Thu, 28 Nov 2019 09:23:55 -0800 Subject: [PATCH 16/31] Travis CI: fix libboost package issue --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 42541e3..93fd5e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ matrix: addons: apt: sources: ['ubuntu-toolchain-r-test', 'george-edison55-precise-backports', 'boost-latest'] - packages: ["g++-4.8", "cmake-data", "cmake", "libboost-regex1.55-dev"] + packages: ["g++-4.8", "cmake-data", "cmake", "libboost-regex-dev"] - os: linux env: From a3e66b9dd9891b939b7ab334fe923206515eda1a Mon Sep 17 00:00:00 2001 From: Jared Grubb Date: Thu, 28 Nov 2019 10:03:13 -0800 Subject: [PATCH 17/31] Travis: fix the GCC+boost::regex builds by updating the compiler versions The old Travis file had gcc-4.8 + boost::regex. But I think the default Ubuntu install (and the pre-packaged libboost_regex.so) was compiled against libstdc++-5 which had a major ABI break with std::string, which caused an ABI problem when gcc-4.8 was linking aginst that library. Easiest thing is to stop testing gcc-4.8 Also updated the clang and gcc versions to try newer ones. --- .travis.yml | 57 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index 93fd5e2..90e7c68 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,18 +5,32 @@ matrix: include: - os: linux env: - - COMPILER=g++-5 STDLIB=libc++ + - COMPILER=g++-7 addons: apt: - sources: ['ubuntu-toolchain-r-test', 'george-edison55-precise-backports'] - packages: ["g++-5", "cmake-data", "cmake"] + sources: ['ubuntu-toolchain-r-test'] + packages: ["g++-7", "cmake-data", "cmake"] - os: linux env: - - COMPILER=g++-4.8 USE_BOOST_REGEX=ON + - COMPILER=g++-8 addons: apt: - sources: ['ubuntu-toolchain-r-test', 'george-edison55-precise-backports', 'boost-latest'] - packages: ["g++-4.8", "cmake-data", "cmake", "libboost-regex-dev"] + sources: ['ubuntu-toolchain-r-test'] + packages: ["g++-8", "cmake-data", "cmake"] + - os: linux + env: + - COMPILER=g++-9 + addons: + apt: + sources: ['ubuntu-toolchain-r-test'] + packages: ["g++-9", "cmake-data", "cmake"] + - os: linux + env: + - COMPILER=g++-9 USE_BOOST_REGEX=ON + addons: + apt: + sources: ['ubuntu-toolchain-r-test'] + packages: ["g++-9", "cmake-data", "cmake", "libboost-regex-dev"] - os: linux env: @@ -28,11 +42,11 @@ matrix: - os: linux env: - - COMPILER=clang++-3.7 STDLIB=libc++ + - COMPILER=clang++-8 STDLIB=libc++ addons: apt: - sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.7', 'george-edison55-precise-backports'] - packages: ["clang-3.7", "cmake-data", "cmake"] + sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-8'] + packages: ["clang-8", "cmake-data", "cmake"] - os: osx osx_image: xcode9.4 @@ -50,19 +64,32 @@ matrix: env: - COMPILER=clang++ V='Apple LLVM 11.0' - COMPILER=clang++ V='Apple LLVM 11.0' WITH_CPP14=true + - os: osx + osx_image: xcode11.2 + env: + - COMPILER=clang++ V='Apple LLVM 11.0' + - COMPILER=clang++ V='Apple LLVM 11.0' WITH_CPP17=true before_install: - CMAKE_CXX_FLAGS+=" -Wall" - - - if [[ "${WITH_CPP14}" == "true" ]]; then CMAKE_OPTIONS+=" -DCMAKE_CXX_STANDARD=14"; fi + - | + if [[ "${WITH_CPP14}" == "true" ]]; then + CMAKE_OPTIONS+=" -DCMAKE_CXX_STANDARD=14" + fi + - | + if [[ "${WITH_CPP17}" == "true" ]]; then + CMAKE_OPTIONS+=" -DCMAKE_CXX_STANDARD=17" + 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" + CMAKE_OPTIONS+=" -DBoost_REGEX_LIBRARY_DEBUG=/usr/lib/x86_64-linux-gnu/libboost_regex.so" + CMAKE_OPTIONS+=" -DBoost_REGEX_LIBRARY_RELEASE=/usr/lib/x86_64-linux-gnu/libboost_regex.so" + fi + - | + if [[ "${STDLIB}" == "libc++" ]]; then + CMAKE_CXX_FLAGS+=" -stdlib=libc++" fi - - if [[ "${STDLIB}" == "libc++" ]]; then CMAKE_CXX_FLAGS+=" -stdlib=libc++"; fi - - ${COMPILER} --version before_script: From 1ae5cd6ee6328399863dc657d0b2f7b32e8472dd Mon Sep 17 00:00:00 2001 From: Petr Mensik Date: Mon, 2 Mar 2020 19:31:10 +0100 Subject: [PATCH 18/31] Include definition for std::runtime_error Build fails with GCC 10.0. Make sure runtime_error definition is included in headers that contain construction of std::runtime_error. --- docopt.h | 1 + docopt_value.h | 1 + 2 files changed, 2 insertions(+) diff --git a/docopt.h b/docopt.h index 4c40741..3269c98 100644 --- a/docopt.h +++ b/docopt.h @@ -14,6 +14,7 @@ #include #include #include +#include #ifdef DOCOPT_HEADER_ONLY #define DOCOPT_INLINE inline diff --git a/docopt_value.h b/docopt_value.h index 829ee55..be4f767 100644 --- a/docopt_value.h +++ b/docopt_value.h @@ -14,6 +14,7 @@ #include #include // std::hash #include +#include namespace docopt { From 11912fc8e943cfc3310034ed4cac4c736eb92602 Mon Sep 17 00:00:00 2001 From: Eli Lindsey Date: Tue, 7 Apr 2020 12:22:49 -0400 Subject: [PATCH 19/31] remove redundant include stdexcept docopt_value.h includes stdexcept twice --- docopt_value.h | 1 - 1 file changed, 1 deletion(-) diff --git a/docopt_value.h b/docopt_value.h index be4f767..2003a7a 100644 --- a/docopt_value.h +++ b/docopt_value.h @@ -9,7 +9,6 @@ #ifndef docopt__value_h_ #define docopt__value_h_ -#include #include #include #include // std::hash From 2b40eaab3173ab70435a628b8761dbbfc3bc26e2 Mon Sep 17 00:00:00 2001 From: Kerndog73 Date: Fri, 13 Dec 2019 15:41:12 +1030 Subject: [PATCH 20/31] Add kind() --- docopt_value.h | 129 +++++++++++++++++++++++++------------------------ 1 file changed, 65 insertions(+), 64 deletions(-) diff --git a/docopt_value.h b/docopt_value.h index 2003a7a..9757f30 100644 --- a/docopt_value.h +++ b/docopt_value.h @@ -17,6 +17,14 @@ namespace docopt { + enum class Kind { + Empty, + Bool, + Long, + String, + StringList + }; + /// A generic type to hold the various types that can be produced by docopt. /// /// This type can be one of: {bool, long, string, vector}, or empty. @@ -36,15 +44,17 @@ namespace docopt { value(value&&) noexcept; value& operator=(value const&); value& operator=(value&&) noexcept; + + Kind kind() const { return mKind; } // Test if this object has any contents at all - explicit operator bool() const { return kind != Kind::Empty; } + explicit operator bool() const { return mKind != Kind::Empty; } // Test the type contained by this value object - bool isBool() const { return kind==Kind::Bool; } - bool isString() const { return kind==Kind::String; } - bool isLong() const { return kind==Kind::Long; } - bool isStringList() const { return kind==Kind::StringList; } + bool isBool() const { return mKind==Kind::Bool; } + bool isString() const { return mKind==Kind::String; } + bool isLong() const { return mKind==Kind::Long; } + bool isStringList() const { return mKind==Kind::StringList; } // Throws std::invalid_argument if the type does not match bool asBool() const; @@ -59,14 +69,6 @@ namespace docopt { friend bool operator!=(value const&, value const&); private: - enum class Kind { - Empty, - Bool, - Long, - String, - StringList - }; - union Variant { Variant() {} ~Variant() { /* do nothing; will be destroyed by ~value */ } @@ -89,19 +91,18 @@ namespace docopt { } void throwIfNotKind(Kind expected) const { - if (kind == expected) + if (mKind == expected) return; std::string error = "Illegal cast to "; error += kindAsString(expected); error += "; type is actually "; - error += kindAsString(kind); + error += kindAsString(mKind); throw std::runtime_error(std::move(error)); } - private: - Kind kind = Kind::Empty; - Variant variant {}; + Kind mKind = Kind::Empty; + Variant mVariant {}; }; /// Write out the contents to the ostream @@ -120,51 +121,51 @@ namespace std { namespace docopt { inline value::value(bool v) - : kind(Kind::Bool) + : mKind(Kind::Bool) { - variant.boolValue = v; + mVariant.boolValue = v; } inline value::value(long v) - : kind(Kind::Long) + : mKind(Kind::Long) { - variant.longValue = v; + mVariant.longValue = v; } inline value::value(std::string v) - : kind(Kind::String) + : mKind(Kind::String) { - new (&variant.strValue) std::string(std::move(v)); + new (&mVariant.strValue) std::string(std::move(v)); } inline value::value(std::vector v) - : kind(Kind::StringList) + : mKind(Kind::StringList) { - new (&variant.strList) std::vector(std::move(v)); + new (&mVariant.strList) std::vector(std::move(v)); } inline value::value(value const& other) - : kind(other.kind) + : mKind(other.mKind) { - switch (kind) { + switch (mKind) { case Kind::String: - new (&variant.strValue) std::string(other.variant.strValue); + new (&mVariant.strValue) std::string(other.mVariant.strValue); break; case Kind::StringList: - new (&variant.strList) std::vector(other.variant.strList); + new (&mVariant.strList) std::vector(other.mVariant.strList); break; case Kind::Bool: - variant.boolValue = other.variant.boolValue; + mVariant.boolValue = other.mVariant.boolValue; break; case Kind::Long: - variant.longValue = other.variant.longValue; + mVariant.longValue = other.mVariant.longValue; break; case Kind::Empty: @@ -175,23 +176,23 @@ namespace docopt { inline value::value(value&& other) noexcept - : kind(other.kind) + : mKind(other.mKind) { - switch (kind) { + switch (mKind) { case Kind::String: - new (&variant.strValue) std::string(std::move(other.variant.strValue)); + new (&mVariant.strValue) std::string(std::move(other.mVariant.strValue)); break; case Kind::StringList: - new (&variant.strList) std::vector(std::move(other.variant.strList)); + new (&mVariant.strList) std::vector(std::move(other.mVariant.strList)); break; case Kind::Bool: - variant.boolValue = other.variant.boolValue; + mVariant.boolValue = other.mVariant.boolValue; break; case Kind::Long: - variant.longValue = other.variant.longValue; + mVariant.longValue = other.mVariant.longValue; break; case Kind::Empty: @@ -203,13 +204,13 @@ namespace docopt { inline value::~value() { - switch (kind) { + switch (mKind) { case Kind::String: - variant.strValue.~basic_string(); + mVariant.strValue.~basic_string(); break; case Kind::StringList: - variant.strList.~vector(); + mVariant.strList.~vector(); break; case Kind::Empty: @@ -243,23 +244,23 @@ namespace docopt { inline size_t value::hash() const noexcept { - switch (kind) { + switch (mKind) { case Kind::String: - return std::hash()(variant.strValue); + return std::hash()(mVariant.strValue); case Kind::StringList: { - size_t seed = std::hash()(variant.strList.size()); - for(auto const& str : variant.strList) { + size_t seed = std::hash()(mVariant.strList.size()); + for(auto const& str : mVariant.strList) { hash_combine(seed, str); } return seed; } case Kind::Bool: - return std::hash()(variant.boolValue); + return std::hash()(mVariant.boolValue); case Kind::Long: - return std::hash()(variant.longValue); + return std::hash()(mVariant.longValue); case Kind::Empty: default: @@ -271,15 +272,15 @@ namespace docopt { bool value::asBool() const { throwIfNotKind(Kind::Bool); - return variant.boolValue; + return mVariant.boolValue; } inline long value::asLong() const { // Attempt to convert a string to a long - if (kind == Kind::String) { - const std::string& str = variant.strValue; + if (mKind == Kind::String) { + const std::string& str = mVariant.strValue; std::size_t pos; const long ret = stol(str, &pos); // Throws if it can't convert if (pos != str.length()) { @@ -289,43 +290,43 @@ namespace docopt { return ret; } throwIfNotKind(Kind::Long); - return variant.longValue; + return mVariant.longValue; } inline std::string const& value::asString() const { throwIfNotKind(Kind::String); - return variant.strValue; + return mVariant.strValue; } inline std::vector const& value::asStringList() const { throwIfNotKind(Kind::StringList); - return variant.strList; + return mVariant.strList; } inline bool operator==(value const& v1, value const& v2) { - if (v1.kind != v2.kind) + if (v1.mKind != v2.mKind) return false; - switch (v1.kind) { - case value::Kind::String: - return v1.variant.strValue==v2.variant.strValue; + switch (v1.mKind) { + case Kind::String: + return v1.mVariant.strValue==v2.mVariant.strValue; - case value::Kind::StringList: - return v1.variant.strList==v2.variant.strList; + case Kind::StringList: + return v1.mVariant.strList==v2.mVariant.strList; - case value::Kind::Bool: - return v1.variant.boolValue==v2.variant.boolValue; + case Kind::Bool: + return v1.mVariant.boolValue==v2.mVariant.boolValue; - case value::Kind::Long: - return v1.variant.longValue==v2.variant.longValue; + case Kind::Long: + return v1.mVariant.longValue==v2.mVariant.longValue; - case value::Kind::Empty: + case Kind::Empty: default: return true; } From 2f8a31100c9a5baf3442b83e0078c57eb3cf0713 Mon Sep 17 00:00:00 2001 From: Kerndog73 Date: Fri, 13 Dec 2019 15:41:46 +1030 Subject: [PATCH 21/31] No it isn't! --- docopt_value.h | 1 - 1 file changed, 1 deletion(-) diff --git a/docopt_value.h b/docopt_value.h index 9757f30..760c721 100644 --- a/docopt_value.h +++ b/docopt_value.h @@ -64,7 +64,6 @@ namespace docopt { size_t hash() const noexcept; - // equality is based on hash-equality friend bool operator==(value const&, value const&); friend bool operator!=(value const&, value const&); From 6879488fbbcdd502fe7d512d8b4466ef71dc30c7 Mon Sep 17 00:00:00 2001 From: Kerndog73 Date: Fri, 13 Dec 2019 15:47:03 +1030 Subject: [PATCH 22/31] Use tabs instead of spaces Not a fan of tabs. hehe --- docopt_value.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docopt_value.h b/docopt_value.h index 760c721..de5c1f9 100644 --- a/docopt_value.h +++ b/docopt_value.h @@ -17,13 +17,13 @@ namespace docopt { - enum class Kind { - Empty, - Bool, - Long, - String, - StringList - }; + enum class Kind { + Empty, + Bool, + Long, + String, + StringList + }; /// A generic type to hold the various types that can be produced by docopt. /// @@ -45,7 +45,7 @@ namespace docopt { value& operator=(value const&); value& operator=(value&&) noexcept; - Kind kind() const { return mKind; } + Kind kind() const { return mKind; } // Test if this object has any contents at all explicit operator bool() const { return mKind != Kind::Empty; } From c8a63d5fa606091e5c8044bb7c2b1db3f51f100d Mon Sep 17 00:00:00 2001 From: Kerndog73 Date: Fri, 14 Feb 2020 12:30:01 +1030 Subject: [PATCH 23/31] Use trailing underscore --- docopt_value.h | 102 ++++++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/docopt_value.h b/docopt_value.h index de5c1f9..ff88625 100644 --- a/docopt_value.h +++ b/docopt_value.h @@ -45,16 +45,16 @@ namespace docopt { value& operator=(value const&); value& operator=(value&&) noexcept; - Kind kind() const { return mKind; } + Kind kind() const { return kind_; } // Test if this object has any contents at all - explicit operator bool() const { return mKind != Kind::Empty; } + explicit operator bool() const { return kind_ != Kind::Empty; } // Test the type contained by this value object - bool isBool() const { return mKind==Kind::Bool; } - bool isString() const { return mKind==Kind::String; } - bool isLong() const { return mKind==Kind::Long; } - bool isStringList() const { return mKind==Kind::StringList; } + bool isBool() const { return kind_==Kind::Bool; } + bool isString() const { return kind_==Kind::String; } + bool isLong() const { return kind_==Kind::Long; } + bool isStringList() const { return kind_==Kind::StringList; } // Throws std::invalid_argument if the type does not match bool asBool() const; @@ -90,18 +90,18 @@ namespace docopt { } void throwIfNotKind(Kind expected) const { - if (mKind == expected) + if (kind_ == expected) return; std::string error = "Illegal cast to "; error += kindAsString(expected); error += "; type is actually "; - error += kindAsString(mKind); + error += kindAsString(kind_); throw std::runtime_error(std::move(error)); } - Kind mKind = Kind::Empty; - Variant mVariant {}; + Kind kind_ = Kind::Empty; + Variant variant_ {}; }; /// Write out the contents to the ostream @@ -120,51 +120,51 @@ namespace std { namespace docopt { inline value::value(bool v) - : mKind(Kind::Bool) + : kind_(Kind::Bool) { - mVariant.boolValue = v; + variant_.boolValue = v; } inline value::value(long v) - : mKind(Kind::Long) + : kind_(Kind::Long) { - mVariant.longValue = v; + variant_.longValue = v; } inline value::value(std::string v) - : mKind(Kind::String) + : kind_(Kind::String) { - new (&mVariant.strValue) std::string(std::move(v)); + new (&variant_.strValue) std::string(std::move(v)); } inline value::value(std::vector v) - : mKind(Kind::StringList) + : kind_(Kind::StringList) { - new (&mVariant.strList) std::vector(std::move(v)); + new (&variant_.strList) std::vector(std::move(v)); } inline value::value(value const& other) - : mKind(other.mKind) + : kind_(other.kind_) { - switch (mKind) { + switch (kind_) { case Kind::String: - new (&mVariant.strValue) std::string(other.mVariant.strValue); + new (&variant_.strValue) std::string(other.variant_.strValue); break; case Kind::StringList: - new (&mVariant.strList) std::vector(other.mVariant.strList); + new (&variant_.strList) std::vector(other.variant_.strList); break; case Kind::Bool: - mVariant.boolValue = other.mVariant.boolValue; + variant_.boolValue = other.variant_.boolValue; break; case Kind::Long: - mVariant.longValue = other.mVariant.longValue; + variant_.longValue = other.variant_.longValue; break; case Kind::Empty: @@ -175,23 +175,23 @@ namespace docopt { inline value::value(value&& other) noexcept - : mKind(other.mKind) + : kind_(other.kind_) { - switch (mKind) { + switch (kind_) { case Kind::String: - new (&mVariant.strValue) std::string(std::move(other.mVariant.strValue)); + new (&variant_.strValue) std::string(std::move(other.variant_.strValue)); break; case Kind::StringList: - new (&mVariant.strList) std::vector(std::move(other.mVariant.strList)); + new (&variant_.strList) std::vector(std::move(other.variant_.strList)); break; case Kind::Bool: - mVariant.boolValue = other.mVariant.boolValue; + variant_.boolValue = other.variant_.boolValue; break; case Kind::Long: - mVariant.longValue = other.mVariant.longValue; + variant_.longValue = other.variant_.longValue; break; case Kind::Empty: @@ -203,13 +203,13 @@ namespace docopt { inline value::~value() { - switch (mKind) { + switch (kind_) { case Kind::String: - mVariant.strValue.~basic_string(); + variant_.strValue.~basic_string(); break; case Kind::StringList: - mVariant.strList.~vector(); + variant_.strList.~vector(); break; case Kind::Empty: @@ -243,23 +243,23 @@ namespace docopt { inline size_t value::hash() const noexcept { - switch (mKind) { + switch (kind_) { case Kind::String: - return std::hash()(mVariant.strValue); + return std::hash()(variant_.strValue); case Kind::StringList: { - size_t seed = std::hash()(mVariant.strList.size()); - for(auto const& str : mVariant.strList) { + size_t seed = std::hash()(variant_.strList.size()); + for(auto const& str : variant_.strList) { hash_combine(seed, str); } return seed; } case Kind::Bool: - return std::hash()(mVariant.boolValue); + return std::hash()(variant_.boolValue); case Kind::Long: - return std::hash()(mVariant.longValue); + return std::hash()(variant_.longValue); case Kind::Empty: default: @@ -271,15 +271,15 @@ namespace docopt { bool value::asBool() const { throwIfNotKind(Kind::Bool); - return mVariant.boolValue; + return variant_.boolValue; } inline long value::asLong() const { // Attempt to convert a string to a long - if (mKind == Kind::String) { - const std::string& str = mVariant.strValue; + if (kind_ == Kind::String) { + const std::string& str = variant_.strValue; std::size_t pos; const long ret = stol(str, &pos); // Throws if it can't convert if (pos != str.length()) { @@ -289,41 +289,41 @@ namespace docopt { return ret; } throwIfNotKind(Kind::Long); - return mVariant.longValue; + return variant_.longValue; } inline std::string const& value::asString() const { throwIfNotKind(Kind::String); - return mVariant.strValue; + return variant_.strValue; } inline std::vector const& value::asStringList() const { throwIfNotKind(Kind::StringList); - return mVariant.strList; + return variant_.strList; } inline bool operator==(value const& v1, value const& v2) { - if (v1.mKind != v2.mKind) + if (v1.kind_ != v2.kind_) return false; - switch (v1.mKind) { + switch (v1.kind_) { case Kind::String: - return v1.mVariant.strValue==v2.mVariant.strValue; + return v1.variant_.strValue==v2.variant_.strValue; case Kind::StringList: - return v1.mVariant.strList==v2.mVariant.strList; + return v1.variant_.strList==v2.variant_.strList; case Kind::Bool: - return v1.mVariant.boolValue==v2.mVariant.boolValue; + return v1.variant_.boolValue==v2.variant_.boolValue; case Kind::Long: - return v1.mVariant.longValue==v2.mVariant.longValue; + return v1.variant_.longValue==v2.variant_.longValue; case Kind::Empty: default: From 0718ad71b860fa80003df8e4d6191fd1ae0228a5 Mon Sep 17 00:00:00 2001 From: Kerndog73 Date: Fri, 29 Nov 2019 15:49:32 +1030 Subject: [PATCH 24/31] Add options type-alias --- docopt.cpp | 6 +++--- docopt.h | 7 +++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/docopt.cpp b/docopt.cpp index 937845d..5481667 100644 --- a/docopt.cpp +++ b/docopt.cpp @@ -609,7 +609,7 @@ static std::pair> create_pattern_tree(std::string } DOCOPT_INLINE -std::map +docopt::options docopt::docopt_parse(std::string const& doc, std::vector const& argv, bool help, @@ -636,7 +636,7 @@ docopt::docopt_parse(std::string const& doc, std::vector> collected; bool matched = pattern.fix().match(argv_patterns, collected); if (matched && argv_patterns.empty()) { - std::map ret; + options ret; // (a.name, a.value) for a in (pattern.flat() + collected) for (auto* p : pattern.leaves()) { @@ -659,7 +659,7 @@ docopt::docopt_parse(std::string const& doc, } DOCOPT_INLINE -std::map +docopt::options docopt::docopt(std::string const& doc, std::vector const& argv, bool help, diff --git a/docopt.h b/docopt.h index 3269c98..6258d32 100644 --- a/docopt.h +++ b/docopt.h @@ -54,6 +54,9 @@ namespace docopt { // Arguments contained '--version' and parsing was aborted early struct DocoptExitVersion : std::runtime_error { DocoptExitVersion() : std::runtime_error("Docopt --version argument encountered") {} }; + + /// A map of options set by the user + using options = std::map; /// Parse user options from the given option string. /// @@ -68,7 +71,7 @@ namespace docopt { /// @throws DocoptExitHelp if 'help' is true and the user has passed the '--help' argument /// @throws DocoptExitVersion if 'version' is true and the user has passed the '--version' argument /// @throws DocoptArgumentError if the user's argv did not match the usage patterns - std::map DOCOPT_API docopt_parse(std::string const& doc, + options DOCOPT_API docopt_parse(std::string const& doc, std::vector const& argv, bool help = true, bool version = true, @@ -81,7 +84,7 @@ namespace docopt { /// * DocoptExitHelp - print usage string and terminate (with exit code 0) /// * DocoptExitVersion - print version and terminate (with exit code 0) /// * DocoptArgumentError - print error and usage string and terminate (with exit code -1) - std::map DOCOPT_API docopt(std::string const& doc, + options DOCOPT_API docopt(std::string const& doc, std::vector const& argv, bool help = true, std::string const& version = {}, From f2618abc1feee4b140bc742f5982be1e818d7e32 Mon Sep 17 00:00:00 2001 From: Kerndog73 Date: Fri, 29 Nov 2019 15:56:54 +1030 Subject: [PATCH 25/31] Maybe you should try compiling before committing next time --- docopt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docopt.cpp b/docopt.cpp index 5481667..e460bd1 100644 --- a/docopt.cpp +++ b/docopt.cpp @@ -636,7 +636,7 @@ docopt::docopt_parse(std::string const& doc, std::vector> collected; bool matched = pattern.fix().match(argv_patterns, collected); if (matched && argv_patterns.empty()) { - options ret; + docopt::options ret; // (a.name, a.value) for a in (pattern.flat() + collected) for (auto* p : pattern.leaves()) { From 42ebcec9dc2c99a1b3a4542787572045763ad196 Mon Sep 17 00:00:00 2001 From: Kerndog73 Date: Sat, 30 Nov 2019 09:12:35 +1030 Subject: [PATCH 26/31] Uppercase --- docopt.cpp | 6 +++--- docopt.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docopt.cpp b/docopt.cpp index e460bd1..c2c2008 100644 --- a/docopt.cpp +++ b/docopt.cpp @@ -609,7 +609,7 @@ static std::pair> create_pattern_tree(std::string } DOCOPT_INLINE -docopt::options +docopt::Options docopt::docopt_parse(std::string const& doc, std::vector const& argv, bool help, @@ -636,7 +636,7 @@ docopt::docopt_parse(std::string const& doc, std::vector> collected; bool matched = pattern.fix().match(argv_patterns, collected); if (matched && argv_patterns.empty()) { - docopt::options ret; + docopt::Options ret; // (a.name, a.value) for a in (pattern.flat() + collected) for (auto* p : pattern.leaves()) { @@ -659,7 +659,7 @@ docopt::docopt_parse(std::string const& doc, } DOCOPT_INLINE -docopt::options +docopt::Options docopt::docopt(std::string const& doc, std::vector const& argv, bool help, diff --git a/docopt.h b/docopt.h index 6258d32..c5ce97e 100644 --- a/docopt.h +++ b/docopt.h @@ -56,7 +56,7 @@ namespace docopt { struct DocoptExitVersion : std::runtime_error { DocoptExitVersion() : std::runtime_error("Docopt --version argument encountered") {} }; /// A map of options set by the user - using options = std::map; + using Options = std::map; /// Parse user options from the given option string. /// @@ -71,7 +71,7 @@ namespace docopt { /// @throws DocoptExitHelp if 'help' is true and the user has passed the '--help' argument /// @throws DocoptExitVersion if 'version' is true and the user has passed the '--version' argument /// @throws DocoptArgumentError if the user's argv did not match the usage patterns - options DOCOPT_API docopt_parse(std::string const& doc, + Options DOCOPT_API docopt_parse(std::string const& doc, std::vector const& argv, bool help = true, bool version = true, @@ -84,7 +84,7 @@ namespace docopt { /// * DocoptExitHelp - print usage string and terminate (with exit code 0) /// * DocoptExitVersion - print version and terminate (with exit code 0) /// * DocoptArgumentError - print error and usage string and terminate (with exit code -1) - options DOCOPT_API docopt(std::string const& doc, + Options DOCOPT_API docopt(std::string const& doc, std::vector const& argv, bool help = true, std::string const& version = {}, From 6f5de76970be94a6f1e4556d1716593100e285d2 Mon Sep 17 00:00:00 2001 From: Martin Hans Date: Tue, 16 Jun 2020 15:15:26 -0700 Subject: [PATCH 27/31] Add missing static keyword GCC complains about a missing declaration for this function when compiled with `-Werror=missing-declarations`. Adding a static keyword here fixes that. --- docopt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docopt.cpp b/docopt.cpp index c2c2008..c6ee9b9 100644 --- a/docopt.cpp +++ b/docopt.cpp @@ -523,7 +523,7 @@ static PatternList parse_argv(Tokens tokens, std::vector