├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── LICENSE-Boost-1.0 ├── LICENSE-MIT ├── README.rst ├── docopt-config.cmake ├── docopt.cpp ├── docopt.h ├── docopt.pc.in ├── docopt_private.h ├── docopt_util.h ├── docopt_value.h ├── examples └── naval_fate.cpp ├── main.cpp ├── run_testcase.cpp ├── run_tests.py └── testcases.docopt /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | 6 | # Compiled Dynamic libraries 7 | *.so 8 | *.dylib 9 | *.dll 10 | 11 | # Compiled Static libraries 12 | *.lai 13 | *.la 14 | *.a 15 | 16 | # Compiled examples, as per docs 17 | example 18 | naval_fate 19 | run_testcase 20 | run_testcase.exe 21 | 22 | # CMake temporary files 23 | CMakeCache.txt 24 | CMakeFiles 25 | CPackConfig.cmake 26 | CPackSourceConfig.cmake 27 | Makefile 28 | cmake_install.cmake 29 | docopt-config-version.cmake 30 | 31 | # Files configured by CMake 32 | run_tests 33 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | sudo: false # Use the new container infrastructure 3 | 4 | matrix: 5 | include: 6 | - os: linux 7 | env: 8 | - COMPILER=g++-7 9 | addons: 10 | apt: 11 | sources: ['ubuntu-toolchain-r-test'] 12 | packages: ["g++-7", "cmake-data", "cmake"] 13 | - os: linux 14 | env: 15 | - COMPILER=g++-8 16 | addons: 17 | apt: 18 | sources: ['ubuntu-toolchain-r-test'] 19 | packages: ["g++-8", "cmake-data", "cmake"] 20 | - os: linux 21 | env: 22 | - COMPILER=g++-9 23 | addons: 24 | apt: 25 | sources: ['ubuntu-toolchain-r-test'] 26 | packages: ["g++-9", "cmake-data", "cmake"] 27 | - os: linux 28 | env: 29 | - COMPILER=g++-9 USE_BOOST_REGEX=ON 30 | addons: 31 | apt: 32 | sources: ['ubuntu-toolchain-r-test'] 33 | packages: ["g++-9", "cmake-data", "cmake", "libboost-regex-dev"] 34 | 35 | - os: linux 36 | env: 37 | - COMPILER=clang++-3.6 STDLIB=libc++ 38 | addons: 39 | apt: 40 | sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.6', 'george-edison55-precise-backports'] 41 | packages: ["clang-3.6", "cmake-data", "cmake"] 42 | 43 | - os: linux 44 | env: 45 | - COMPILER=clang++-8 STDLIB=libc++ 46 | addons: 47 | apt: 48 | sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-8'] 49 | packages: ["clang-8", "cmake-data", "cmake"] 50 | 51 | - os: osx 52 | osx_image: xcode9.4 53 | env: 54 | - COMPILER=clang++ V='Apple LLVM 9.1' 55 | - COMPILER=clang++ V='Apple LLVM 9.1' WITH_CPP14=true 56 | 57 | - os: osx 58 | osx_image: xcode10.3 59 | env: 60 | - COMPILER=clang++ V='Apple LLVM 10.0' 61 | - COMPILER=clang++ V='Apple LLVM 10.0' WITH_CPP14=true 62 | - os: osx 63 | osx_image: xcode11.2 64 | env: 65 | - COMPILER=clang++ V='Apple LLVM 11.0' 66 | - COMPILER=clang++ V='Apple LLVM 11.0' WITH_CPP14=true 67 | - os: osx 68 | osx_image: xcode11.2 69 | env: 70 | - COMPILER=clang++ V='Apple LLVM 11.0' 71 | - COMPILER=clang++ V='Apple LLVM 11.0' WITH_CPP17=true 72 | 73 | before_install: 74 | - CMAKE_CXX_FLAGS+=" -Wall" 75 | - | 76 | if [[ "${WITH_CPP14}" == "true" ]]; then 77 | CMAKE_OPTIONS+=" -DCMAKE_CXX_STANDARD=14" 78 | fi 79 | - | 80 | if [[ "${WITH_CPP17}" == "true" ]]; then 81 | CMAKE_OPTIONS+=" -DCMAKE_CXX_STANDARD=17" 82 | fi 83 | - | 84 | if [[ "${USE_BOOST_REGEX}" == "ON" ]]; then 85 | CMAKE_OPTIONS+=" -DUSE_BOOST_REGEX=ON" 86 | CMAKE_OPTIONS+=" -DBoost_REGEX_LIBRARY_DEBUG=/usr/lib/x86_64-linux-gnu/libboost_regex.so" 87 | CMAKE_OPTIONS+=" -DBoost_REGEX_LIBRARY_RELEASE=/usr/lib/x86_64-linux-gnu/libboost_regex.so" 88 | fi 89 | - | 90 | if [[ "${STDLIB}" == "libc++" ]]; then 91 | CMAKE_CXX_FLAGS+=" -stdlib=libc++" 92 | fi 93 | - ${COMPILER} --version 94 | 95 | before_script: 96 | - rm -rf build/ 97 | - mkdir build 98 | - cd build 99 | - cmake -DCMAKE_CXX_COMPILER=${COMPILER} -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} -DWITH_TESTS=1 -DWITH_EXAMPLE=1 ${CMAKE_OPTIONS} .. 100 | 101 | script: 102 | - cmake --build . 103 | - python run_tests 104 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(docopt.cpp VERSION 0.6.2) 3 | 4 | include(GNUInstallDirs) 5 | 6 | #============================================================================ 7 | # Settable options 8 | #============================================================================ 9 | option(WITH_TESTS "Build tests." OFF) 10 | option(WITH_EXAMPLE "Build example." OFF) 11 | option(USE_BOOST_REGEX "Replace std::regex with Boost.Regex" OFF) 12 | 13 | #============================================================================ 14 | # Internal compiler options 15 | #============================================================================ 16 | # C++ standard 17 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 18 | set(CMAKE_CXX_EXTENSIONS OFF) 19 | if(NOT CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD LESS 11) 20 | set(CMAKE_CXX_STANDARD 11) 21 | endif() 22 | 23 | #============================================================================ 24 | # Sources & headers 25 | #============================================================================ 26 | set(docopt_SOURCES docopt.cpp) 27 | set(docopt_HEADERS 28 | docopt.h 29 | docopt_private.h 30 | docopt_util.h 31 | docopt_value.h 32 | ) 33 | 34 | #============================================================================ 35 | # Compile targets 36 | #============================================================================ 37 | add_library(docopt ${docopt_SOURCES} ${docopt_HEADERS}) 38 | set_target_properties(docopt PROPERTIES 39 | VERSION ${PROJECT_VERSION} 40 | SOVERSION ${PROJECT_VERSION_MAJOR} 41 | ) 42 | 43 | target_include_directories(docopt PUBLIC $ $) 44 | 45 | if(MSVC AND BUILD_SHARED_LIBS) 46 | # DOCOPT_DLL: Must be specified when building *and* when using the DLL. 47 | # That's what the "PUBLIC" means. 48 | # DOCOPT_EXPORTS: Must use __declspec(dllexport) when building the DLL. 49 | # "PRIVATE" means it's only defined when building the DLL. 50 | target_compile_definitions(docopt PUBLIC DOCOPT_DLL 51 | PRIVATE DOCOPT_EXPORTS) 52 | endif() 53 | 54 | if(USE_BOOST_REGEX) 55 | add_definitions("-DDOCTOPT_USE_BOOST_REGEX") 56 | # This is needed on Linux, where linking a static library into docopt.so 57 | # fails because boost static libs are not compiled with -fPIC 58 | set(Boost_USE_STATIC_LIBS OFF) 59 | find_package(Boost 1.53 REQUIRED COMPONENTS regex) 60 | include_directories(${Boost_INCLUDE_DIRS}) 61 | target_link_libraries(docopt ${Boost_LIBRARIES}) 62 | endif() 63 | 64 | #============================================================================ 65 | # Examples 66 | #============================================================================ 67 | if(WITH_EXAMPLE) 68 | add_executable(docopt_example examples/naval_fate.cpp) 69 | target_link_libraries(docopt_example docopt) 70 | endif() 71 | 72 | #============================================================================ 73 | # Tests 74 | #============================================================================ 75 | if(WITH_TESTS) 76 | set(TESTPROG "${CMAKE_CURRENT_BINARY_DIR}/run_testcase") 77 | set(TESTCASES "${PROJECT_SOURCE_DIR}/testcases.docopt") 78 | add_executable(run_testcase run_testcase.cpp) 79 | target_link_libraries(run_testcase docopt) 80 | configure_file( 81 | "${PROJECT_SOURCE_DIR}/run_tests.py" 82 | "${CMAKE_CURRENT_BINARY_DIR}/run_tests" 83 | ESCAPE_QUOTES 84 | ) 85 | add_test("Testcases docopt" ${TESTPROG}) 86 | endif() 87 | 88 | #============================================================================ 89 | # Install 90 | #============================================================================ 91 | set(export_name "docopt-targets") 92 | 93 | # Runtime package 94 | install(TARGETS docopt EXPORT ${export_name} 95 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 96 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 97 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) 98 | 99 | # Development package 100 | install(FILES ${docopt_HEADERS} DESTINATION include/docopt) 101 | 102 | # CMake Package 103 | include(CMakePackageConfigHelpers) 104 | write_basic_package_version_file("${PROJECT_BINARY_DIR}/docopt-config-version.cmake" COMPATIBILITY SameMajorVersion) 105 | install(FILES docopt-config.cmake ${PROJECT_BINARY_DIR}/docopt-config-version.cmake DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/docopt") 106 | install(EXPORT ${export_name} DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/docopt") 107 | 108 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/docopt.pc.in ${CMAKE_CURRENT_BINARY_DIR}/docopt.pc @ONLY) 109 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/docopt.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) 110 | 111 | #============================================================================ 112 | # CPack 113 | #============================================================================ 114 | set(CPACK_PACKAGE_NAME "docopt") 115 | set(CPACK_DEBIAN_PACKAGE_DEPENDS "") 116 | set(CPACK_RPM_PACKAGE_REQUIRES "") 117 | set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Beautiful command line interfaces") 118 | set(CPACK_PACKAGE_VENDOR "Jared Grubb") 119 | set(CPACK_PACKAGE_CONTACT ${CPACK_PACKAGE_VENDOR}) 120 | set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/README.rst") 121 | set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE-MIT") 122 | set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}) 123 | set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR}) 124 | set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH}) 125 | set(CPACK_DEBIAN_PACKAGE_SECTION "Development") 126 | set(CPACK_RPM_PACKAGE_GROUP "Development/Libraries") 127 | set(CPACK_RPM_PACKAGE_LICENSE "MIT") 128 | set(CPACK_STRIP_FILES TRUE) 129 | include(CPack) 130 | -------------------------------------------------------------------------------- /LICENSE-Boost-1.0: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Vladimir Keleshev, 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software 6 | without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to 9 | whom the Software is furnished to do so, subject to the 10 | following conditions: 11 | 12 | The above copyright notice and this permission notice shall 13 | be included in all copies or substantial portions of the 14 | Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 22 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ``docopt.cpp``: A C++11 Port 2 | ============================ 3 | 4 | Contents 5 | -------- 6 | 7 | .. contents:: 8 | :local: 9 | :depth: 3 10 | 11 | docopt creates *beautiful* command-line interfaces 12 | -------------------------------------------------- 13 | 14 | Isn't it awesome how ``getopt`` (and ``boost::program_options`` for you fancy 15 | folk!) generate help messages based on your code?! These timeless functions 16 | have been around for decades and have proven we don't need anything better, right? 17 | 18 | *Hell no!* You know what's awesome? It's when the option parser *is* 19 | generated based on the beautiful help message that you write yourself! 20 | This way you don't need to write this stupid repeatable parser-code, 21 | and instead can write only the help message--*the way you want it*. 22 | 23 | **docopt** helps you create most beautiful command-line interfaces 24 | *easily*: 25 | 26 | .. code:: c++ 27 | 28 | #include "docopt.h" 29 | 30 | #include 31 | 32 | static const char USAGE[] = 33 | R"(Naval Fate. 34 | 35 | Usage: 36 | naval_fate ship new ... 37 | naval_fate ship move [--speed=] 38 | naval_fate ship shoot 39 | naval_fate mine (set|remove) [--moored | --drifting] 40 | naval_fate (-h | --help) 41 | naval_fate --version 42 | 43 | Options: 44 | -h --help Show this screen. 45 | --version Show version. 46 | --speed= Speed in knots [default: 10]. 47 | --moored Moored (anchored) mine. 48 | --drifting Drifting mine. 49 | )"; 50 | 51 | int main(int argc, const char** argv) 52 | { 53 | std::map args 54 | = docopt::docopt(USAGE, 55 | { argv + 1, argv + argc }, 56 | true, // show help if requested 57 | "Naval Fate 2.0"); // version string 58 | 59 | for(auto const& arg : args) { 60 | std::cout << arg.first << arg.second << std::endl; 61 | } 62 | 63 | return 0; 64 | } 65 | 66 | Beat that! The option parser is generated based on the docstring above 67 | that is passed to ``docopt::docopt`` function. ``docopt`` parses the usage 68 | pattern (``"Usage: ..."``) and option descriptions (lines starting 69 | with a dash "``-``") and ensures that the program invocation matches the 70 | usage pattern; it parses options, arguments and commands based on 71 | that. The basic idea is that *a good help message has all necessary 72 | information in it to make a parser*. 73 | 74 | Getting and using 75 | ----------------- 76 | 77 | To get *docopt.cpp*, the simplest is to use `Conda `_:: 78 | 79 | conda install -c conda-forge docopt.cpp 80 | 81 | Alternatively manual installation is done using (unix):: 82 | 83 | git clone 84 | cmake . 85 | make install 86 | 87 | To link *docopt.cpp*, the simplest is to use CMake. The general structure of your 88 | ``CMakeLists.txt`` would be as follows:: 89 | 90 | cmake_minimum_required(VERSION 3.1) 91 | 92 | project(example) 93 | 94 | find_package(docopt COMPONENTS CXX REQUIRED) 95 | include_directories(${DOCOPT_INCLUDE_DIRS}) 96 | 97 | add_executable(${PROJECT_NAME} ...) 98 | 99 | target_link_libraries(${PROJECT_NAME} docopt) 100 | 101 | C++11 port details 102 | ------------------ 103 | 104 | This is a port of the ``docopt.py`` module (https://github.com/docopt/docopt), 105 | and we have tried to maintain full feature parity (and code structure) as the 106 | original. 107 | 108 | This port is written in C++11 and also requires a good C++11 standard library 109 | (in particular, one with ``regex`` support). The following compilers are known 110 | to work with docopt: 111 | 112 | - Clang 3.3 and later 113 | - GCC 4.9 114 | - Visual C++ 2015 RC 115 | 116 | GCC-4.8 can work, but the std::regex module needs to be replaced with ``Boost.Regex``. 117 | In that case, you will need to define ``DOCTOPT_USE_BOOST_REGEX`` when compiling 118 | docopt, and link your code with the appropriated Boost libraries. A relatively 119 | recent version of Boost is needed: 1.55 works, but 1.46 does not for example. 120 | 121 | This port is licensed under the MIT license, just like the original module. 122 | However, we are also dual-licensing this code under the Boost License, version 1.0, 123 | as this is a popular C++ license. The licenses are similar and you are free to 124 | use this code under the terms of either license. 125 | 126 | The differences from the Python port are: 127 | 128 | * the addition of a ``docopt_parse`` function, which does not terminate 129 | the program on error 130 | * a ``docopt::value`` type to hold the various value types that can be parsed. 131 | We considered using boost::variant, but it seems better to have no external 132 | dependencies (beyond a good STL). 133 | * because C++ is statically-typed and Python is not, we had to make some 134 | changes to the interfaces of the internal parse tree types. 135 | * because ``std::regex`` does not have an equivalent to Python's regex.split, 136 | some of the regex's had to be restructured and additional loops used. 137 | 138 | API 139 | --- 140 | 141 | .. code:: c++ 142 | 143 | docopt::docopt(doc, argv, help /* =true */, version /* ="" */, options_first /* =false */) 144 | 145 | ``docopt`` takes 2 required and 3 optional arguments: 146 | 147 | - ``doc`` is a string that contains a **help message** that will be parsed to 148 | create the option parser. The simple rules of how to write such a 149 | help message are given in next sections. Here is a quick example of 150 | such a string (note that this example uses the "raw string literal" feature 151 | that was added to C++11): 152 | 153 | .. code:: c++ 154 | 155 | R"(Usage: my_program [-hso FILE] [--quiet | --verbose] [INPUT ...] 156 | 157 | -h --help show this 158 | -s --sorted sorted output 159 | -o FILE specify output file [default: ./test.txt] 160 | --quiet print less text 161 | --verbose print more text 162 | )" 163 | 164 | - ``argv`` is a vector of strings representing the args passed. Although 165 | main usually takes a ``(int argc, const char** argv)`` pair, you can 166 | pass the value ``{argv+1, argv+argc}`` to generate the vector automatically. 167 | (Note we skip the argv[0] argument!) Alternatively you can supply a list of 168 | strings like ``{ "--verbose", "-o", "hai.txt" }``. 169 | 170 | - ``help``, by default ``true``, specifies whether the parser should 171 | automatically print the help message (supplied as ``doc``) and 172 | terminate, in case ``-h`` or ``--help`` option is encountered 173 | (options should exist in usage pattern, more on that below). If you 174 | want to handle ``-h`` or ``--help`` options manually (as other 175 | options), set ``help=false``. 176 | 177 | - ``version``, by default empty, is an optional argument that 178 | specifies the version of your program. If supplied, then, (assuming 179 | ``--version`` option is mentioned in usage pattern) when parser 180 | encounters the ``--version`` option, it will print the supplied 181 | version and terminate. ``version`` could be any printable object, 182 | but most likely a string, e.g. ``"2.1.0rc1"``. 183 | 184 | Note, when ``docopt`` is set to automatically handle ``-h``, 185 | ``--help`` and ``--version`` options, you still need to mention 186 | them in usage pattern for this to work (also so your users to 187 | know about them!) 188 | 189 | - ``options_first``, by default ``false``. If set to ``true`` will 190 | disallow mixing options and positional argument. I.e. after first 191 | positional argument, all arguments will be interpreted as positional 192 | even if the look like options. This can be used for strict 193 | compatibility with POSIX, or if you want to dispatch your arguments 194 | to other programs. 195 | 196 | The **return** value is a ``map`` with options, 197 | arguments and commands as keys, spelled exactly like in your help message. 198 | Long versions of options are given priority. For example, if you invoke the 199 | top example as:: 200 | 201 | naval_fate ship Guardian move 100 150 --speed=15 202 | 203 | the return dictionary will be: 204 | 205 | .. code:: python 206 | 207 | {"--drifting": false, "mine": false, 208 | "--help": false, "move": true, 209 | "--moored": false, "new": false, 210 | "--speed": "15", "remove": false, 211 | "--version": false, "set": false, 212 | "": ["Guardian"], "ship": true, 213 | "": "100", "shoot": false, 214 | "": "150"} 215 | 216 | If any parsing error (in either the usage, or due to incorrect user inputs) is 217 | encountered, the program will exit with exit code -1. 218 | 219 | Note that there is another function that does not exit on error, and instead will 220 | propagate an exception that you can catch and process as you like. See the docopt.h file 221 | for information on the exceptions and usage: 222 | 223 | .. code:: c++ 224 | 225 | docopt::docopt_parse(doc, argv, help /* =true */, version /* =true */, options_first /* =false) 226 | 227 | Help message format 228 | ------------------- 229 | 230 | Help message consists of 2 parts: 231 | 232 | - Usage pattern, e.g.:: 233 | 234 | Usage: my_program [-hso FILE] [--quiet | --verbose] [INPUT ...] 235 | 236 | - Option descriptions, e.g.:: 237 | 238 | -h --help show this 239 | -s --sorted sorted output 240 | -o FILE specify output file [default: ./test.txt] 241 | --quiet print less text 242 | --verbose print more text 243 | 244 | Their format is described below; other text is ignored. 245 | 246 | Usage pattern format 247 | -------------------- 248 | 249 | **Usage pattern** is a substring of ``doc`` that starts with 250 | ``usage:`` (case *insensitive*) and ends with a *visibly* empty line. 251 | Minimum example: 252 | 253 | .. code:: python 254 | 255 | """Usage: my_program 256 | 257 | """ 258 | 259 | The first word after ``usage:`` is interpreted as your program's name. 260 | You can specify your program's name several times to signify several 261 | exclusive patterns: 262 | 263 | .. code:: python 264 | 265 | """Usage: my_program FILE 266 | my_program COUNT FILE 267 | 268 | """ 269 | 270 | Each pattern can consist of the following elements: 271 | 272 | - ****, **ARGUMENTS**. Arguments are specified as either 273 | upper-case words, e.g. ``my_program CONTENT-PATH`` or words 274 | surrounded by angular brackets: ``my_program ``. 275 | - **--options**. Options are words started with dash (``-``), e.g. 276 | ``--output``, ``-o``. You can "stack" several of one-letter 277 | options, e.g. ``-oiv`` which will be the same as ``-o -i -v``. The 278 | options can have arguments, e.g. ``--input=FILE`` or ``-i FILE`` or 279 | even ``-iFILE``. However it is important that you specify option 280 | descriptions if you want your option to have an argument, a default 281 | value, or specify synonymous short/long versions of the option (see 282 | next section on option descriptions). 283 | - **commands** are words that do *not* follow the described above 284 | conventions of ``--options`` or ```` or ``ARGUMENTS``, 285 | plus two special commands: dash "``-``" and double dash "``--``" 286 | (see below). 287 | 288 | Use the following constructs to specify patterns: 289 | 290 | - **[ ]** (brackets) **optional** elements. e.g.: ``my_program 291 | [-hvqo FILE]`` 292 | - **( )** (parens) **required** elements. All elements that are *not* 293 | put in **[ ]** are also required, e.g.: ``my_program 294 | --path= ...`` is the same as ``my_program 295 | (--path= ...)``. (Note, "required options" might be not 296 | a good idea for your users). 297 | - **|** (pipe) **mutually exclusive** elements. Group them using **( 298 | )** if one of the mutually exclusive elements is required: 299 | ``my_program (--clockwise | --counter-clockwise) TIME``. Group 300 | them using **[ ]** if none of the mutually exclusive elements are 301 | required: ``my_program [--left | --right]``. 302 | - **...** (ellipsis) **one or more** elements. To specify that 303 | arbitrary number of repeating elements could be accepted, use 304 | ellipsis (``...``), e.g. ``my_program FILE ...`` means one or 305 | more ``FILE``-s are accepted. If you want to accept zero or more 306 | elements, use brackets, e.g.: ``my_program [FILE ...]``. Ellipsis 307 | works as a unary operator on the expression to the left. 308 | - **[options]** (case sensitive) shortcut for any options. You can 309 | use it if you want to specify that the usage pattern could be 310 | provided with any options defined below in the option-descriptions 311 | and do not want to enumerate them all in usage-pattern. 312 | - "``[--]``". Double dash "``--``" is used by convention to separate 313 | positional arguments that can be mistaken for options. In order to 314 | support this convention add "``[--]``" to your usage patterns. 315 | - "``[-]``". Single dash "``-``" is used by convention to signify that 316 | ``stdin`` is used instead of a file. To support this add "``[-]``" 317 | to your usage patterns. "``-``" acts as a normal command. 318 | 319 | If your pattern allows to match argument-less option (a flag) several 320 | times:: 321 | 322 | Usage: my_program [-v | -vv | -vvv] 323 | 324 | then number of occurrences of the option will be counted. I.e. 325 | ``args['-v']`` will be ``2`` if program was invoked as ``my_program 326 | -vv``. Same works for commands. 327 | 328 | If your usage pattern allows to match same-named option with argument 329 | or positional argument several times, the matched arguments will be 330 | collected into a list:: 331 | 332 | Usage: my_program --path=... 333 | 334 | I.e. invoked with ``my_program file1 file2 --path=./here 335 | --path=./there`` the returned dict will contain ``args[''] == 336 | ['file1', 'file2']`` and ``args['--path'] == ['./here', './there']``. 337 | 338 | Option descriptions format 339 | -------------------------- 340 | 341 | **Option descriptions** consist of a list of options that you put 342 | below your usage patterns. 343 | 344 | It is necessary to list option descriptions in order to specify: 345 | 346 | - synonymous short and long options, 347 | - if an option has an argument, 348 | - if option's argument has a default value. 349 | 350 | The rules are as follows: 351 | 352 | - Every line in ``doc`` that starts with ``-`` or ``--`` (not counting 353 | spaces) is treated as an option description, e.g.:: 354 | 355 | Options: 356 | --verbose # GOOD 357 | -o FILE # GOOD 358 | Other: --bad # BAD, line does not start with dash "-" 359 | 360 | - To specify that option has an argument, put a word describing that 361 | argument after space (or equals "``=``" sign) as shown below. Follow 362 | either or UPPER-CASE convention for options' 363 | arguments. You can use comma if you want to separate options. In 364 | the example below, both lines are valid. However you are recommended 365 | to stick to a single style.:: 366 | 367 | -o FILE --output=FILE # without comma, with "=" sign 368 | -i , --input # with comma, without "=" sing 369 | 370 | - Use two spaces to separate options with their informal description:: 371 | 372 | --verbose More text. # BAD, will be treated as if verbose option had 373 | # an argument "More", so use 2 spaces instead 374 | -q Quit. # GOOD 375 | -o FILE Output file. # GOOD 376 | --stdout Use stdout. # GOOD, 2 spaces 377 | 378 | - If you want to set a default value for an option with an argument, 379 | put it into the option-description, in form ``[default: 380 | ]``:: 381 | 382 | --coefficient=K The K coefficient [default: 2.95] 383 | --output=FILE Output file [default: test.txt] 384 | --directory=DIR Some directory [default: ./] 385 | 386 | - If the option is not repeatable, the value inside ``[default: ...]`` 387 | will be interpreted as string. If it *is* repeatable, it will be 388 | split into a list on whitespace:: 389 | 390 | Usage: my_program [--repeatable= --repeatable=] 391 | [--another-repeatable=]... 392 | [--not-repeatable=] 393 | 394 | # will be ['./here', './there'] 395 | --repeatable= [default: ./here ./there] 396 | 397 | # will be ['./here'] 398 | --another-repeatable= [default: ./here] 399 | 400 | # will be './here ./there', because it is not repeatable 401 | --not-repeatable= [default: ./here ./there] 402 | 403 | Examples 404 | -------- 405 | 406 | We have an extensive list of `examples 407 | `_ which cover 408 | every aspect of functionality of **docopt**. Try them out, read the 409 | source if in doubt. 410 | 411 | There are also very interesting applications and ideas at that page. 412 | Check out the sister project for more information! 413 | 414 | Subparsers, multi-level help and *huge* applications (like git) 415 | --------------------------------------------------------------- 416 | 417 | If you want to split your usage-pattern into several, implement 418 | multi-level help (with separate help-screen for each subcommand), 419 | want to interface with existing scripts that don't use **docopt**, or 420 | you're building the next "git", you will need the new ``options_first`` 421 | parameter (described in API section above). To get you started quickly 422 | we implemented a subset of git command-line interface as an example: 423 | `examples/git 424 | `_ 425 | 426 | Compiling the example / Running the tests 427 | ----------------------------------------- 428 | 429 | The original Python module includes some language-agnostic unit tests, 430 | and these can be run with this port as well. 431 | 432 | The tests are a Python driver that uses the testcases.docopt file to then invoke 433 | a C++ test case runner (run_testcase.cpp):: 434 | 435 | $ clang++ --std=c++11 --stdlib=libc++ docopt.cpp run_testcase.cpp -o run_testcase 436 | $ python run_tests.py 437 | PASS (175) 438 | 439 | You can also compile the example shown at the start (included as example.cpp):: 440 | 441 | $ clang++ --std=c++11 --stdlib=libc++ -I . docopt.cpp examples/naval_fate.cpp -o naval_fate 442 | $ ./naval_fate --help 443 | [ ... ] 444 | $ ./naval_fate ship Guardian move 100 150 --speed=15 445 | --drifting: false 446 | --help: false 447 | --moored: false 448 | --speed: "15" 449 | --version: false 450 | : ["Guardian"] 451 | : "100" 452 | : "150" 453 | mine: false 454 | move: true 455 | new: false 456 | remove: false 457 | set: false 458 | ship: true 459 | shoot: false 460 | 461 | Development 462 | ----------- 463 | 464 | Comments and suggestions are *very* welcome! If you find issues, please 465 | file them and help improve our code! 466 | 467 | Please note, however, that we have tried to stay true to the original 468 | Python code. If you have any major patches, structural changes, or new features, 469 | we might want to first negotiate these changes into the Python code first. 470 | However, bring it up! Let's hear it! 471 | 472 | Changelog 473 | --------- 474 | 475 | **docopt** follows `semantic versioning `_. The 476 | first release with stable API will be 1.0.0 (soon). 477 | 478 | - 0.6.2 Bugfix release (still based on docopt 0.6.1) 479 | - 0.6.1 The initial C++ port of docopt.py (based on docopt 0.6.1) 480 | -------------------------------------------------------------------------------- /docopt-config.cmake: -------------------------------------------------------------------------------- 1 | include("${CMAKE_CURRENT_LIST_DIR}/docopt-targets.cmake") 2 | -------------------------------------------------------------------------------- /docopt.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // docopt.cpp 3 | // docopt 4 | // 5 | // Created by Jared Grubb on 2013-11-03. 6 | // Copyright (c) 2013 Jared Grubb. All rights reserved. 7 | // 8 | 9 | #include "docopt.h" 10 | #include "docopt_util.h" 11 | #include "docopt_private.h" 12 | 13 | #include "docopt_value.h" 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | using namespace docopt; 25 | 26 | DOCOPT_INLINE 27 | std::ostream& docopt::operator<<(std::ostream& os, value const& val) 28 | { 29 | if (val.isBool()) { 30 | bool b = val.asBool(); 31 | os << (b ? "true" : "false"); 32 | } else if (val.isLong()) { 33 | long v = val.asLong(); 34 | os << v; 35 | } else if (val.isString()) { 36 | std::string const& str = val.asString(); 37 | os << '"' << str << '"'; 38 | } else if (val.isStringList()) { 39 | auto const& list = val.asStringList(); 40 | os << "["; 41 | bool first = true; 42 | for(auto const& el : list) { 43 | if (first) { 44 | first = false; 45 | } else { 46 | os << ", "; 47 | } 48 | os << '"' << el << '"'; 49 | } 50 | os << "]"; 51 | } else { 52 | os << "null"; 53 | } 54 | return os; 55 | } 56 | 57 | #if 0 58 | #pragma mark - 59 | #pragma mark Parsing stuff 60 | #endif 61 | 62 | class Tokens { 63 | public: 64 | Tokens(std::vector tokens, bool isParsingArgv = true) 65 | : fTokens(std::move(tokens)), 66 | fIsParsingArgv(isParsingArgv) 67 | {} 68 | 69 | explicit operator bool() const { 70 | return fIndex < fTokens.size(); 71 | } 72 | 73 | static Tokens from_pattern(std::string const& source) { 74 | static const std::regex re_separators { 75 | "(?:\\s*)" // any spaces (non-matching subgroup) 76 | "(" 77 | "[\\[\\]\\(\\)\\|]" // one character of brackets or parens or pipe character 78 | "|" 79 | "\\.\\.\\." // elipsis 80 | ")" }; 81 | 82 | static const std::regex re_strings { 83 | "(?:\\s*)" // any spaces (non-matching subgroup) 84 | "(" 85 | "\\S*<.*?>" // strings, but make sure to keep "< >" strings together 86 | "|" 87 | "[^<>\\s]+" // string without <> 88 | ")" }; 89 | 90 | // We do two stages of regex matching. The '[]()' and '...' are strong delimeters 91 | // and need to be split out anywhere they occur (even at the end of a token). We 92 | // first split on those, and then parse the stuff between them to find the string 93 | // tokens. This is a little harder than the python version, since they have regex.split 94 | // and we dont have anything like that. 95 | 96 | std::vector tokens; 97 | std::for_each(std::sregex_iterator{ source.begin(), source.end(), re_separators }, 98 | std::sregex_iterator{}, 99 | [&](std::smatch const& match) 100 | { 101 | // handle anything before the separator (this is the "stuff" between the delimeters) 102 | if (match.prefix().matched) { 103 | std::for_each(std::sregex_iterator{match.prefix().first, match.prefix().second, re_strings}, 104 | std::sregex_iterator{}, 105 | [&](std::smatch const& m) 106 | { 107 | tokens.push_back(m[1].str()); 108 | }); 109 | } 110 | 111 | // handle the delimter token itself 112 | if (match[1].matched) { 113 | tokens.push_back(match[1].str()); 114 | } 115 | }); 116 | 117 | return Tokens(tokens, false); 118 | } 119 | 120 | std::string const& current() const { 121 | if (*this) 122 | return fTokens[fIndex]; 123 | 124 | static std::string const empty; 125 | return empty; 126 | } 127 | 128 | std::string the_rest() const { 129 | if (!*this) 130 | return {}; 131 | return join(fTokens.begin()+static_cast(fIndex), 132 | fTokens.end(), 133 | " "); 134 | } 135 | 136 | std::string pop() { 137 | return std::move(fTokens.at(fIndex++)); 138 | } 139 | 140 | bool isParsingArgv() const { return fIsParsingArgv; } 141 | 142 | struct OptionError : std::runtime_error { using runtime_error::runtime_error; }; 143 | 144 | private: 145 | std::vector fTokens; 146 | size_t fIndex = 0; 147 | bool fIsParsingArgv; 148 | }; 149 | 150 | // Get all instances of 'T' from the pattern 151 | template 152 | std::vector flat_filter(Pattern& pattern) { 153 | std::vector flattened = pattern.flat([](Pattern const* p) -> bool { 154 | return dynamic_cast(p) != nullptr; 155 | }); 156 | 157 | // now, we're guaranteed to have T*'s, so just use static_cast 158 | std::vector ret; 159 | std::transform(flattened.begin(), flattened.end(), std::back_inserter(ret), [](Pattern* p) { 160 | return static_cast(p); 161 | }); 162 | return ret; 163 | } 164 | 165 | static std::vector parse_section(std::string const& name, std::string const& source) { 166 | // ECMAScript regex only has "?=" for a non-matching lookahead. In order to make sure we always have 167 | // a newline to anchor our matching, we have to avoid matching the final newline of each grouping. 168 | // Therefore, our regex is adjusted from the docopt Python one to use ?= to match the newlines before 169 | // the following lines, rather than after. 170 | std::regex const re_section_pattern { 171 | "(?:^|\\n)" // anchored at a linebreak (or start of string) 172 | "(" 173 | "[^\\n]*" + name + "[^\\n]*(?=\\n?)" // a line that contains the name 174 | "(?:\\n[ \\t].*?(?=\\n|$))*" // followed by any number of lines that are indented 175 | ")", 176 | std::regex::icase 177 | }; 178 | 179 | std::vector ret; 180 | std::for_each(std::sregex_iterator(source.begin(), source.end(), re_section_pattern), 181 | std::sregex_iterator(), 182 | [&](std::smatch const& match) 183 | { 184 | ret.push_back(trim(match[1].str())); 185 | }); 186 | 187 | return ret; 188 | } 189 | 190 | static bool is_argument_spec(std::string const& token) { 191 | if (token.empty()) 192 | return false; 193 | 194 | if (token[0]=='<' && token[token.size()-1]=='>') 195 | return true; 196 | 197 | if (std::all_of(token.begin(), token.end(), &::isupper)) 198 | return true; 199 | 200 | return false; 201 | } 202 | 203 | template 204 | std::vector longOptions(I iter, I end) { 205 | std::vector ret; 206 | std::transform(iter, end, 207 | std::back_inserter(ret), 208 | [](typename I::reference opt) { return opt->longOption(); }); 209 | return ret; 210 | } 211 | 212 | static PatternList parse_long(Tokens& tokens, std::vector