GithubHelp home page GithubHelp logo

docopt.cpp's Introduction

See docopt-ng

Please see docopt-ng for a compatible, updated fork of the original Python docopt.

This project is no longer maintained.

docopt creates beautiful command-line interfaces

image

image

Video introduction to docopt: PyCon UK 2012: Create *beautiful* command-line interfaces with Python

New in version 0.6.1:

  • Fix issue #85 which caused improper handling of [options] shortcut if it was present several times.

New in version 0.6.0:

  • New argument options_first, disallows interspersing options and arguments. If you supply options_first=True to docopt, it will interpret all arguments as positional arguments after first positional argument.
  • If option with argument could be repeated, its default value will be interpreted as space-separated list. E.g. with [default: ./here ./there] will be interpreted as ['./here', './there'].

Breaking changes:

  • Meaning of [options] shortcut slightly changed. Previously it meant "any known option". Now it means "any option not in usage-pattern". This avoids the situation when an option is allowed to be repeated unintentionally.
  • argv is None by default, not sys.argv[1:]. This allows docopt to always use the latest sys.argv, not sys.argv during import time.

Isn't it awesome how optparse and argparse generate help messages based on your code?!

Hell no! You know what's awesome? It's when the option parser is generated based on the beautiful help message that you write yourself! This way you don't need to write this stupid repeatable parser-code, and instead can write only the help message--the way you want it.

docopt helps you create most beautiful command-line interfaces easily:

"""Naval Fate.

Usage:
  naval_fate.py ship new <name>...
  naval_fate.py ship <name> move <x> <y> [--speed=<kn>]
  naval_fate.py ship shoot <x> <y>
  naval_fate.py mine (set|remove) <x> <y> [--moored | --drifting]
  naval_fate.py (-h | --help)
  naval_fate.py --version

Options:
  -h --help     Show this screen.
  --version     Show version.
  --speed=<kn>  Speed in knots [default: 10].
  --moored      Moored (anchored) mine.
  --drifting    Drifting mine.

"""
from docopt import docopt


if __name__ == '__main__':
    arguments = docopt(__doc__, version='Naval Fate 2.0')
    print(arguments)

Beat that! The option parser is generated based on the docstring above that is passed to docopt function. docopt parses the usage pattern ("Usage: ...") and option descriptions (lines starting with 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.

Also, PEP 257 recommends putting help message in the module docstrings.

Installation

Use pip or easy_install:

pip install docopt==0.6.2

Alternatively, you can just drop docopt.py file into your project--it is self-contained.

docopt is tested with Python 2.7, 3.4, 3.5, and 3.6.

Testing

You can run unit tests using the command:

python setup.py test

API

from docopt import docopt
docopt(doc, argv=None, help=True, version=None, options_first=False)

docopt takes 1 required and 4 optional arguments:

  • doc could be a module docstring (__doc__) or some other string that contains a help message that will be parsed to create the option parser. The simple rules of how to write such a help message are given in next sections. Here is a quick example of such a string:
"""Usage: my_program.py [-hso FILE] [--quiet | --verbose] [INPUT ...]

-h --help    show this
-s --sorted  sorted output
-o FILE      specify output file [default: ./test.txt]
--quiet      print less text
--verbose    print more text

"""
  • argv is an optional argument vector; by default docopt uses the argument vector passed to your program (sys.argv[1:]). Alternatively you can supply a list of strings like ['--verbose', '-o', 'hai.txt'].
  • help, by default True, specifies whether the parser should automatically print the help message (supplied as doc) and terminate, in case -h or --help option is encountered (options should exist in usage pattern, more on that below). If you want to handle -h or --help options manually (as other options), set help=False.
  • version, by default None, is an optional argument that specifies the version of your program. If supplied, then, (assuming --version option is mentioned in usage pattern) when parser encounters the --version option, it will print the supplied version and terminate. version could be any printable object, but most likely a string, e.g. "2.1.0rc1".

    Note, when docopt is set to automatically handle -h, --help and --version options, you still need to mention them in usage pattern for this to work. Also, for your users to know about them.

  • options_first, by default False. If set to True will disallow mixing options and positional argument. I.e. after first positional argument, all arguments will be interpreted as positional even if the look like options. This can be used for strict compatibility with POSIX, or if you want to dispatch your arguments to other programs.

The return value is a simple dictionary with options, arguments and commands as keys, spelled exactly like in your help message. Long versions of options are given priority. For example, if you invoke the top example as:

naval_fate.py ship Guardian move 100 150 --speed=15

the return dictionary will be:

{'--drifting': False,    'mine': False,
 '--help': False,        'move': True,
 '--moored': False,      'new': False,
 '--speed': '15',        'remove': False,
 '--version': False,     'set': False,
 '<name>': ['Guardian'], 'ship': True,
 '<x>': '100',           'shoot': False,
 '<y>': '150'}

Help message format

Help message consists of 2 parts:

  • Usage pattern, e.g.:

    Usage: my_program.py [-hso FILE] [--quiet | --verbose] [INPUT ...]
  • Option descriptions, e.g.:

    -h --help    show this
    -s --sorted  sorted output
    -o FILE      specify output file [default: ./test.txt]
    --quiet      print less text
    --verbose    print more text

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. Minimum example:

"""Usage: my_program.py

"""

The first word after usage: is interpreted as your program's name. You can specify your program's name several times to signify several exclusive patterns:

"""Usage: my_program.py FILE
          my_program.py COUNT FILE

"""

Each pattern can consist of the following elements:

  • <arguments>, ARGUMENTS. Arguments are specified as either upper-case words, e.g. my_program.py CONTENT-PATH or words surrounded by angular brackets: my_program.py <content-path>.
  • --options. Options are words started with dash (-), e.g. --output, -o. You can "stack" several of one-letter options, e.g. -oiv which will be the same as -o -i -v. The options can have arguments, e.g. --input=FILE or -i FILE or even -iFILE. However it is important that you specify option descriptions if you want your option to have an argument, a default value, or specify synonymous short/long versions of the option (see next section on option descriptions).
  • commands are words that do not follow the described above conventions of --options or <arguments> or ARGUMENTS, plus two special commands: dash "-" and double dash "--" (see below).

Use the following constructs to specify patterns:

  • [ ] (brackets) optional elements. e.g.: my_program.py [-hvqo FILE]
  • ( ) (parens) required elements. All elements that are not put in [ ] are also required, e.g.: my_program.py --path=<path> <file>... is the same as my_program.py (--path=<path> <file>...). (Note, "required options" might be not a good idea for your users).
  • | (pipe) mutually exclusive elements. Group them using ( ) if one of the mutually exclusive elements is required: my_program.py (--clockwise | --counter-clockwise) TIME. Group them using [ ] if none of the mutually-exclusive elements are required: my_program.py [--left | --right].
  • ... (ellipsis) one or more elements. To specify that arbitrary number of repeating elements could be accepted, use ellipsis (...), e.g. my_program.py FILE ... means one or more FILE-s are accepted. If you want to accept zero or more elements, use brackets, e.g.: my_program.py [FILE ...]. Ellipsis works as a unary operator on the expression to the left.
  • [options] (case sensitive) shortcut for any options. You can use it if you want to specify that the usage pattern could be provided with any options defined below in the option-descriptions and do not want to enumerate them all in usage-pattern.
  • "[--]". Double dash "--" is used by convention to separate positional arguments that can be mistaken for options. In order to support this convention add "[--]" to your usage patterns.
  • "[-]". Single dash "-" is used by convention to signify that stdin is used instead of a file. To support this add "[-]" to your usage patterns. "-" acts as a normal command.

If your pattern allows to match argument-less option (a flag) several times:

Usage: my_program.py [-v | -vv | -vvv]

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 or positional argument several times, the matched arguments will be collected into a list:

Usage: my_program.py <file> <file> --path=<path>...

I.e. invoked with my_program.py file1 file2 --path=./here --path=./there the returned dict will contain args['<file>'] == ['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.

It is necessary to list option descriptions in order to specify:

  • synonymous short and long options,
  • if an option has an argument,
  • if option's argument has a default value.

The rules are as follows:

  • Every line in doc that starts with - or -- (not counting spaces) is treated as an option description, e.g.:

    Options:
      --verbose   # GOOD
      -o FILE     # GOOD
    Other: --bad  # BAD, line does not start with dash "-"
  • To specify that option has an argument, put a word describing that argument after space (or equals "=" sign) as shown below. Follow either <angular-brackets> 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 to stick to a single style.:

    -o FILE --output=FILE       # without comma, with "=" sign
    -i <file>, --input <file>   # with comma, without "=" sign
  • Use two spaces to separate options with their informal description:

    --verbose More text.   # BAD, will be treated as if verbose option had
                           # an argument "More", so use 2 spaces instead
    -q        Quit.        # GOOD
    -o FILE   Output file. # GOOD
    --stdout  Use stdout.  # GOOD, 2 spaces
  • If you want to set a default value for an option with an argument, put it into the option-description, in form [default: <my-default-value>]:

    --coefficient=K  The K coefficient [default: 2.95]
    --output=FILE    Output file [default: test.txt]
    --directory=DIR  Some directory [default: ./]
  • 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:

    Usage: my_program.py [--repeatable=<arg> --repeatable=<arg>]
                         [--another-repeatable=<arg>]...
                         [--not-repeatable=<arg>]
    
    # will be ['./here', './there']
    --repeatable=<arg>          [default: ./here ./there]
    
    # will be ['./here']
    --another-repeatable=<arg>  [default: ./here]
    
    # will be './here ./there', because it is not repeatable
    --not-repeatable=<arg>      [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.

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), want to interface with existing scripts that don't use docopt, or you're building the next "git", you will need the new options_first parameter (described in API section above). To get you started quickly we implemented a subset of git command-line interface as an example: examples/git

Data validation

docopt does one thing and does it well: it implements your command-line interface. However it does not validate the input data. On the other hand there are libraries like python schema which make validating data a breeze. Take a look at validation_example.py which uses schema to validate data and report an error to the user.

Using docopt with config-files

Often configuration files are used to provide default values which could be overriden by command-line arguments. Since docopt returns a simple dictionary it is very easy to integrate with config-files written in JSON, YAML or INI formats. config_file_example.py provides and example of how to use docopt with JSON or INI config-file.

Development

We would love to hear what you think about docopt on our issues page

Make pull requests, report bugs, suggest ideas and discuss docopt. You can also drop a line directly to <[email protected]>.

Porting docopt to other languages

We think docopt is so good, we want to share it beyond the Python community! All official docopt ports to other languages can be found under the docopt organization page on GitHub.

If your favourite language isn't among then, you can always create a port for it! You are encouraged to use the Python version as a reference implementation. A Language-agnostic test suite is bundled with Python implementation.

Porting discussion is on issues page.

Changelog

docopt follows semantic versioning. The first release with stable API will be 1.0.0 (soon). Until then, you are encouraged to specify explicitly the version in your dependency tools, e.g.:

pip install docopt==0.6.2
  • 0.6.2 Bugfix release.
  • 0.6.1 Bugfix release.
  • 0.6.0 options_first parameter. Breaking changes: Corrected [options] meaning. argv defaults to None.
  • 0.5.0 Repeated options/commands are counted or accumulated into a list.
  • 0.4.2 Bugfix release.
  • 0.4.0 Option descriptions become optional, support for "--" and "-" commands.
  • 0.3.0 Support for (sub)commands like git remote add. Introduce [options] shortcut for any options. Breaking changes: docopt returns dictionary.
  • 0.2.0 Usage pattern matching. Positional arguments parsing based on usage patterns. Breaking changes: docopt returns namespace (for arguments), not list. Usage pattern is formalized.
  • 0.1.0 Initial release. Options-parsing only (based on options description).

docopt.cpp's People

Contributors

acgetchell avatar chrisdembia avatar dermariusz avatar eaaltonen avatar elindsey avatar evgvir avatar gamepad64 avatar ghisvail avatar hoxnox avatar indianakernick avatar jaredgrubb avatar johnsusi avatar liblit avatar luthaf avatar martinhansdk avatar mattpd avatar mrkline avatar nikodemus avatar pemensik avatar rmpowell77 avatar tdegeus avatar theodelrieu avatar toch avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

docopt.cpp's Issues

Parsing fails after 80 characters

Some kind of line wrap issue?

https://github.com/acgetchell/CDT-plusplus/blob/docopt/src/cdt-docopt.cpp parses correctly:

┌─[adam][Hapkido][±][docopt ✓][/CDT-plusplus]
└─▪ ./build.sh
-- The C compiler identification is AppleClang 6.0.0.6000054
-- The CXX compiler identification is AppleClang 6.0.0.6000054
-- Check for working C compiler using: Ninja
-- Check for working C compiler using: Ninja -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler using: Ninja
-- Check for working CXX compiler using: Ninja -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Build type: Release
-- USING CXXFLAGS = ' -O3 -DNDEBUG'
-- USING EXEFLAGS = ' -Wl,-dylib_file,/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib:/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib '
-- Targetting Ninja
-- Using /usr/bin/c++ compiler.
-- DARWIN_VERSION=14
-- Mac Leopard detected
-- Requested component: Core
-- Requested component: MPFR
-- Requested component: GMP
-- Found Eigen3: /usr/local/include/eigen3 (found suitable version "3.2.2", minimum required is "3.1.0")
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/adam/CDT-plusplus/build
[12/12] Linking CXX executable unittests
┌─[adam][Hapkido][±][docopt ✓][
/CDT-plusplus]
└─▪ ./build/cdt-docopt --toroidal -n=5000 -t=256 -k=4
--sphericalfalse
--toroidaltrue
-d"3"
-k"=4"
-n"=5000"
-t"=256"

But adding one more required option does not:

https://gist.github.com/acgetchell/366e321437665d987d1e

Produces:

┌─[adam][Hapkido][±][docopt ✗][~/CDT-plusplus]
└─▪ ./build/cdt-docopt --toroidal -n=5000 -t=256 -k=4 -alpha=5
Causal Dynamical Triangulations in C++ using CGAL.

Copyright (c) 2014 Adam Getchell

A program that generates d-dimensional triangulated spacetimes
with a defined causal structure and evolves them according
to the Metropolis algorithm.

Usage:./cdt (--spherical | --toroidal) -n=SIMPLICES -t=TIMESLICES [-d=DIM] -k=K -alpha ALPHA

Options:
-h --help Show this message
--version Show program version
-n SIMPLICES Approximate number of simplices
-t TIMESLICES Number of timeslices
-d DIM Dimensionality [default: 3]
-k K K constant
-alpha Alpha constant

Handling conversion errors

try { std::cout << args["<x>"].asLong() << std::endl; } catch (std::exception & e) { std::cout << e.what() << std::end; }

If stol fails due to conversion, following message is shown:

stol: no conversion

Can it be more specific? Like:

CMake error on Windows when using docopt in other project

I am building docopt on Windows 10 with VS2015 and CMake 3.6.1 and trying to use it in our project OpenSim. I am using the following steps in PowerShell:

git clone git@github.com:docopt/docopt.cpp.git
cd docopt.cpp
mkdir build
cd build
cmake .. -G"Visual Studio 14 2015 Win64" -DCMAKE_INSTALL_PREFIX="..\install"
cmake --build . --target INSTALL --config RelWithDebInfo

At this point, the directory install contains:

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        8/15/2016  12:13 PM                include
d-----        8/15/2016  12:13 PM                lib

And the directory lib above contains:

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        8/15/2016  12:13 PM                cmake
-a----        8/15/2016  12:13 PM         348672 docopt.dll
-a----        8/15/2016  12:13 PM        3234828 docopt_s.lib

I now create a downstream project:

cd ~
mkdir docopt.cpp_downstream
cd docopt.cpp_downstream

Create a file CMakeLists.txt with following contents:

project(docopt_downstream)
cmake_minimum_required(VERSION 3.2)

find_package(docopt
             REQUIRED)

I then try building the downstream project as follows:

mkdir build
cd build
cmake .. -G"Visual Studio 14 2015 Win64" `
     -DCMAKE_INSTALL_PREFIX="..\install" `
     -Ddocopt_DIR="<full-path>\docopt.cpp\install\lib\cmake\docopt"

I get the following error from CMake:

CMake Error at <full-path>/docopt.cpp/install/lib/cmake/docopt/docopt-targets.cmake:78 (message):
  The imported target "docopt" references the file

     "<full-path>/docopt.cpp/install/lib/docopt.lib"

  but this file does not exist.  Possible reasons include:

  * The file was deleted, renamed, or moved to another location.

  * An install or uninstall procedure did not complete successfully.

  * The installation package was faulty and contained

     "<full-path>/docopt.cpp/install/lib/cmake/docopt/docopt-targets.cmake"

  but not all the files it references.

Call Stack (most recent call first):
  <full-path>/docopt.cpp/install/lib/cmake/docopt/docopt-config.cmake:1 (include)
  CMakeLists.txt:4 (find_package)


-- Configuring incomplete, errors occurred!

So it looks like this is looking for file docopt.lib which is (probably incorrectly) named docopt_s.lib.

Am I doing something wrong or this is a bug ? If it is a bug, I can help fix it if I get some pointers on where to look. Please let me know.

Value.asLong not working as expected

I don't know if I am missing something, but I can not figure out how to get an integer-type value out from an argument.

From the example, you have an option like this:

--speed=<kn>  Speed in knots [default: 10].

Now, if I look at that value after docopt.cpp parsing, I get

"--speed": "10"

You can see that "15" is a string and not an integer.

Calling

args["--speed"].asLong()

results in a runtime exception due to the type being std::string.

Currently, to get around this I'm doing

auto speed = std::stoi(args["--speed"].asString());  // Type of speed will be integer

Is there something that needs to be specified in the USAGE string, or is this a bug?

std::wstring support

Hi,

I'm using this lib in an app to parse input files (between other things), but I'm having issues if the given file contains unicode characters.

Is there any way to use std::wstring instead (or in parallel to) std::strings?

tags for official releases

I can see that docopt has been staying at version 0.6.1 for quite a while now without an official release being made. Is the development currently focusing on the next version, or is it because 0.6.1 is not complete yet? Please consider tagging official releases in the future.

Cheers,
Ghis

combining optional arguments not working

In this example:

>DebugViewConsole.exe -d test.dblog

works

>DebugViewConsole.exe -a false

works, however, the combination:

>DebugViewConsole.exe -d test.dblog -a false
Unexpected argument: -d, test.dblog, -a, false

does not work

static const char USAGE[] =
R"(DebugviewConsole )" VERSION_STR
R"(
    Usage: 
        DebugviewConsole [-i <pattern>, --include <pattern>]... [-e <pattern>, --exclude <pattern>]... 
        DebugviewConsole [-cflsqtpnv] [-d <file>]
        DebugviewConsole (-h | --help)
        DebugviewConsole [-a <value>] 
        DebugviewConsole [-x]
        DebugviewConsole [-u]

    Options:
        -h, --help                          show this screen
        -i <pattern>, --include <pattern>   include filter, may be specified multiple times
        -e <pattern>, --exclude <pattern>   exclude filter, may be specified multiple times
        -c              enable console output
        -d <file>       write to .dblog file
        -v              verbose

    Advanced options:
        -a <value>      auto-newline [default: true]
        -f              aggressively flush buffers, if unsure, do not use
        -x              stop all running debugviewconsole instances
        -u              send a UDP test-message, used only for debugging

    Console options:    (no effect on .dblog file)
        -l              prefix line number
        -s              prefix messages with system time
        -q              prefix message with high-precision (<1us) offset from QueryPerformanceCounter
        -t              tab-separated output
        -p              add PID (process ID)
        -n              add process name
)";

Late error detection

if an option is listed twice that error is only detected if the option is actually specified on the cmdline.

R"(DebugviewConsole )" VERSION_STR
R"(
    Usage: 
        DebugviewConsole [-i <pattern>, --include <pattern>]... [-e <pattern>, --exclude <pattern>]... 
        DebugviewConsole (-h | --help)
        DebugviewConsole [-a value]
        DebugviewConsole [-x]
        DebugviewConsole [-u]
        DebugviewConsole [-cflsqtpn]

    Options:
        -h, --help                          show this screen
        -i <pattern>, --include <pattern>   include filter, may be specified multiple times
        -e <pattern>, --exclude <pattern>   exclude filter, may be specified multiple times
        -c              enable console output
        -d <file>       write to .dblog file

    Console options:    (no effect on .dblog file)
        -d <file>       write to .dblog file
        -l              prefix line number

)";

here:
-d write to .dblog file

is listed twice, but as long as you do not use -d everything just works without error, so you might find this very late during testing.

isLong() does not work as it is expected

Although asLong() returns a valid value for an integral value passed as an argument isLong() at the same time returns false.

It looks like such behaviour is connected with the correction #28: meaning of asLong() was changed but isLong() left unchanged.

In my particular case, there was a check if the passed value is a number (isLong()?): to have a guarantee that there will be no exception from asLong(). However, the check returned false on every occasion.

Hangs until killed

Hello,

Thanks for the port. However, it appears to hang and not work, I had to Control-C. I will preface this by saying that I'm using a developer preview of Yosemite:

┌─[getchell][Hapkido][±][master ✓][/docopt.cpp]
└─▪ sw_vers
ProductName: Mac OS X
ProductVersion: 10.10
BuildVersion: 14A298i
┌─[getchell][Hapkido][±][master ✓][
/docopt.cpp]
└─▪ clang++ --version
Apple LLVM version 6.0 (clang-600.0.34.4) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.0.0
Thread model: posix
┌─[getchell][Hapkido][±][master ✓][/docopt.cpp]
└─▪ clang++ --std=c++11 --stdlib=libc++ -I . docopt.cpp examples/naval_fate.cpp -o naval_fate
In file included from examples/naval_fate.cpp:1:
In file included from ./docopt.h:12:
./docopt_value.h:222:7: warning: inline function
'docopt::hash_combinestd::__1::basic_string' is not defined
[-Wundefined-inline]
void hash_combine(std::size_t& seed, const T& v);
^
./docopt_value.h:234:6: note: used here
hash_combine(seed, str);
^
1 warning generated.
┌─[getchell][Hapkido][±][master ✓][
/docopt.cpp]
└─▪ ll
total 2056
drwxr-xr-x 18 getchell 2129169278 612 Jul 24 22:56 .
drwxr-xr-x+ 49 getchell 2129169278 1666 Jul 24 19:36 ..
drwxr-xr-x 10 getchell 2129169278 340 Jul 24 22:56 .git
-rw-r--r-- 1 getchell 2129169278 192 Jul 24 19:36 .gitignore
-rw-r--r-- 1 getchell 2129169278 1338 Jul 24 19:36 LICENSE-Boost-1.0
-rw-r--r-- 1 getchell 2129169278 1086 Jul 24 19:36 LICENSE-MIT
-rw-r--r-- 1 getchell 2129169278 17090 Jul 24 19:36 README.rst
-rw-r--r-- 1 getchell 2129169278 28470 Jul 24 19:36 docopt.cpp
-rw-r--r-- 1 getchell 2129169278 2661 Jul 24 19:36 docopt.h
-rw-r--r-- 1 getchell 2129169278 8158 Jul 24 19:36 docopt_private.h
-rw-r--r-- 1 getchell 2129169278 2219 Jul 24 19:36 docopt_util.h
-rw-r--r-- 1 getchell 2129169278 6291 Jul 24 19:36 docopt_value.h
drwxr-xr-x 3 getchell 2129169278 102 Jul 24 19:36 examples
-rw-r--r-- 1 getchell 2129169278 212 Jul 24 19:36 main.cpp
-rwxr-xr-x 1 getchell 2129169278 939100 Jul 24 22:56 naval_fate
-rw-r--r-- 1 getchell 2129169278 751 Jul 24 19:36 run_testcase.cpp
-rw-r--r-- 1 getchell 2129169278 1521 Jul 24 19:36 run_tests.py
-rw-r--r-- 1 getchell 2129169278 11970 Jul 24 19:36 testcases.docopt
┌─[getchell][Hapkido][±][master ✓][/docopt.cpp]
└─▪ ./naval_fate --help
^C
┌─[getchell][Hapkido][±][master ✓][
/docopt.cpp]
└─▪ ./naval_fate ship Guardian move 100 150 --speed=15
^C

DocoptLanguageError: unmatched '[' when parsing

I'm trying to understand which part of usage fails could you please help?
It seems to be failing on
[(-s ( OPT1 OPT2)...)] // want -s option to be optional and if it is specified it must go with key-value pairs OPT1 OPT2 but i can't get it working.
Can someone help?
Thanks

image

Won't compile with g++ 4.9 on Linux

Unable to build using g++ 4.9 on Ubuntu 14.04. LMK if I can help sort things out.

ntc490@prompus:~/src/docopt.cpp$ g++ -std=c++0x docopt.cpp run_testcase.cpp -o run_testcase docopt.cpp: In instantiation of ‘struct longOptions(I, I) [with I = __gnu_cxx::__normal_iterator >]::__lambda9’: docopt.cpp:574:70: required from ‘std::vectorstd::basic_string longOptions(I, I) [with I = __gnu_cxx::__normal_iterator >]’ docopt.cpp:611:81: required from here docopt.cpp:574:39: error: ‘const’ qualifiers cannot be applied to ‘const docopt::Option_&’ [](decltype%28*iter%29 const& opt) { return opt->longOption(); }); ^ docopt.cpp:574:36: error: ‘const’ qualifiers cannot be applied to ‘const docopt::Option_&’ [](decltype%28*iter%29 const& opt) { return opt->longOption(); }); ^ docopt.cpp:574: confused by earlier errors, bailing out Preprocessed source stored into /tmp/cctuWJ9W.out file, please attach this to your bugreport. In file included from docopt.h:12:0, from run_testcase.cpp:9: docopt_value.h:222:7: warning: inline function ‘void docopt::hash_combine(std::size_t&, const T&) [with T = std::basic_string; std::size_t = unsigned int]’ used but never defined [enabled by default] void hash_combine(std::size_t& seed, const T& v); ^

Add meson support to docopt

Hello everyone. I am using docopt and I would like to add at least minimal meson support (this is the build system I am using).

I sent PR #78 . Is there anything else that I should do? I just have a Mac OS machine and the file is just minimal: just compiles the library and that's it, because it is the way I am consuming it.

Add documentation on integrating docopt.cpp with a client CMake project

The README is reasonably detailed as far as context and usage his concerned.

However, I believe it could be significantly enhanced by adding a specific section regarding the integration of docopt.cpp within a client CMake project. It should probably cover the following 3 use-cases:

  • directly vendoring the docopt.cpp source code.
  • using ExternalProject to download it as a pre-build command.
  • using find_package if a system copy is installed.

Specifiying short and long option in one line does not work.

The usage message:

    static const char USAGE[] =
      R"(
      Usage:
        test [options]

      Options:
        -h, --help                                Show this screen.
        -v, --version                             Show version.
        -d <device>, --device=<device>            Serial port to use (e.g. "/dev/tty0", "/dev/ttyUSB0" or "COM1").
      )";

The docopt command:

  std::map<std::string, docopt::value> args
  = docopt::docopt ( USAGE,
  { argv + 1, argv + argc },
  true,               // show help if requested
  "0.1.0", false ); // version string

When invoked it works with "-h/--help" as expected. But with all other Options only the long version is accepted, the short versions throw "Unexpected argument:".
If the order of options is changed (e.g. " --version, -v Show version.") then only the short options is accepted.

Do I miss something?

Runtime error: Undefined behavior due to unsigned integer overflow

EDIT: Nevermind, unsigned overflow is not undefined behaviour in the C++ standard. Not sure why ASAN is reporting it.

=== Original Comment: ===
The overflow error:

./docopt_util.h:96:46: runtime error: unsigned integer overflow: 15755298069831242297 + 3304135864781666520 cannot be represented in type 'unsigned long'
./docopt_util.h:96:34: runtime error: unsigned integer overflow: 13828916662110822956 + 17646836532054932864 cannot be represented in type 'unsigned long'

Compiled with clang 3.7 and ASAN:

clang++ docopt.cpp -c -o docopt.o -std=c++11 -Wall -Wextra -pedantic -Wcast-align -Wconversion -Wformat=2 -Wformat-nonliteral -Wlogical-op -Wmissing-format-attribute -Wnon-virtual-dtor -Wsign-conversion -fsanitize=undefined -fsanitize=integer
clang++ docopt-test.cpp docopt.o -std=c++11 -fsanitize=undefined -fsanitize=integer  

The driver program:

#include "docopt.h"

static auto USAGE = R"(
    Usage:
      prog --version

    Options:
      -h --help                 Show this screen.
)";

int main(const int argc, const char *const argv[]) {
    const auto args = docopt::docopt(USAGE,
                                     { argv + 1, argv + argc },
                                     true, "Bake 0.1");
}

Document how to use CMake

I have installed doctopt.cpp as follows:

mkdir /some/tempdir
cd /some/tempdir
cmake /path/to/docopt.cpp
make install

Then I want to use it using CMake, but ${DOCOPT_LIBRARIES} is empty. Here is a simple CMakeLists.txt:

cmake_minimum_required(VERSION 3.1)

# define a project name
project(test)

# define empty list of libraries to link
set(PROJECT_LIBS "")

# set optimization level
set(CMAKE_BUILD_TYPE Release)

# set C++ standard
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# load DOCOPT
find_package(docopt REQUIRED)
include_directories(${DOCOPT_INCLUDE_DIRS})
set(PROJECT_LIBS ${PROJECT_LIBS} ${DOCOPT_LIBRARIES})

# create executable
add_executable(${PROJECT_NAME} main.cpp)

# link libraries
target_link_libraries(${PROJECT_NAME} ${PROJECT_LIBS})

The linker ultimately fails, main.cpp compiles successfully.

defining a short and long option for one function has a aside effect

static const char USAGE[] =
R"(DebugviewConsole )" VERSION_STR
R"(
    Usage: 
        DebugviewConsole [-a] [-i <pattern>, --include <pattern>]... [-e <pattern>, --exclude <pattern>]... 

    Options:
      -h --help             Show this screen.
      -a                    auto-newline (automatically adds newline to messages without a newline, most people want this on)
      -i <pattern>, --include <pattern>     include filter, may be specified multiple times
      -e <pattern>, --exclude <pattern>     exclude filter, may be specified multiple times
)";

This pattern seems to work, but the [-i <pattern>, --include <pattern>]... seems to generate an extra map-entry { ",", Long(0) }

>DebugViewConsole.exe -a -i test -i test2 --include bla
, 0                      // here the first = "," and second is a Long(0)
--exclude  is a list: []
--include  is a list: ["test", "test2", "bla"]
-a true

Consider removing noexcept on `docopt::docopt()`.

Right now, docopt::docopt() is marked as noexcept. However, it can throw exceptions. In particular, it threw a std::regex_error(). Because of the noexcept, this caused the program to terminate. It would have been nice for me to have the chance to give a more meaningful error message when docopt gives that exception. What is the reason for the noexcept?

Issue on linux/clang-3.8.1 and clang-3.9

Here's the error I get building docopt.cpp with clang-3.8.1 or 3.9 on ubuntu-14.04:

FAILED: /usr/bin/clang++-3.9   -DCGAL_EIGEN3_ENABLED -DCGAL_LINKED_WITH_TBB -DCGAL_USE_GMP -DCGAL_USE_MPFR -DNOMINMAX -O3 -DNDEBUG -I../src -I../. -I../../../include -isystem /usr/include/x86_64-linux-gnu -I. -I/usr/local/include -isystem /usr/include/eigen3    -std=gnu++14 -MMD -MT CMakeFiles/cdt.dir/src/docopt/docopt.cpp.o -MF CMakeFiles/cdt.dir/src/docopt/docopt.cpp.o.d -o CMakeFiles/cdt.dir/src/docopt/docopt.cpp.o -c ../src/docopt/docopt.cpp
In file included from ../src/docopt/docopt.cpp:9:
In file included from ../src/docopt/docopt.h:12:
In file included from ../src/docopt/docopt_value.h:12:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/string:52:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/basic_string.h:2815:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/ext/string_conversions.h:43:
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/cstdio:120:11: error: no member named 'gets' in the global namespace
  using ::gets;
        ~~^
1 error generated.

You can see full logs from my Travis-CI builds here:

Clang 3.8.1
https://travis-ci.org/acgetchell/CDT-plusplus/jobs/146769356

Clang 3.9
https://travis-ci.org/acgetchell/CDT-plusplus/jobs/146771517

It works fine with gcc or AppleClang.

Minor GCC build warning

Hi. We have quite strict warnings used in our projects and I just recently run into this:

In file included from ../vendor/docopt/docopt.cpp:11:0:
../vendor/docopt/docopt_private.h: In constructor 'docopt::LeafPattern::LeafPattern(std::string, docopt::value)':
../vendor/docopt/docopt_private.h:84:3: error: declaration of 'name' shadows a member of 'this' [-Werror=shadow]
   : fName(std::move(name)),


In file included from ../vendor/docopt/docopt.cpp:11:0:
../vendor/docopt/docopt_private.h: In constructor 'docopt::BranchPattern::BranchPattern(docopt::PatternList)':
../vendor/docopt/docopt_private.h:127:3: error: declaration of 'children' shadows a member of 'this' [-Werror=shadow]
   : fChildren(std::move(children))

In file included from ../vendor/docopt/docopt.cpp:11:0:
../vendor/docopt/docopt_private.h: In member function 'void docopt::BranchPattern::setChildren(docopt::PatternList)':
../vendor/docopt/docopt_private.h:164:42: error: declaration of 'children' shadows a member of 'this' [-Werror=shadow]
   void setChildren(PatternList children) {


In file included from ../vendor/docopt/docopt.cpp:11:0:
../vendor/docopt/docopt_private.h: In constructor 'docopt::Command::Command(std::string, docopt::value)':
../vendor/docopt/docopt_private.h:213:3: error: declaration of 'name' shadows a member of 'this' [-Werror=shadow]
   : Argument(std::move(name), std::move(v))
   ^

In file included from ../vendor/docopt/docopt.cpp:11:0:
../vendor/docopt/docopt_private.h: In constructor 'docopt::Option::Option(std::string, std::string, int, docopt::value)':
../vendor/docopt/docopt_private.h:230:3: error: declaration of 'longOption' shadows a member of 'this' [-Werror=shadow]
   : LeafPattern(longOption.empty() ? shortOption : longOption,
   ^

In file included from ../vendor/docopt/docopt.cpp:11:0:
../vendor/docopt/docopt_private.h: In constructor 'docopt::Option::Option(std::string, std::string, int, docopt::value)':
../vendor/docopt/docopt_private.h:230:3: error: declaration of 'shortOption' shadows a member of 'this' [-Werror=shadow]
   : LeafPattern(longOption_.empty() ? shortOption : longOption_,
   ^

../vendor/docopt/docopt.cpp: In member function 'virtual bool docopt::LeafPattern::match(docopt::PatternList&, std::vector<std::shared_ptr<docopt::LeafPattern> >&) const':
../vendor/docopt/docopt.cpp:118:7: error: declaration of 'match' shadows a member of 'this' [-Werror=shadow]
  auto match = single_match(left);
       ^

pt/CMakeFiles/docopt.dir/docopt.cpp.obj -c ../vendor/docopt/docopt.cpp
../vendor/docopt/docopt.cpp: In constructor 'Tokens::Tokens(std::vector<std::basic_string<char> >, bool)':
../vendor/docopt/docopt.cpp:450:2: error: declaration of 'isParsingArgv' shadows a member of 'this' [-Werror=shadow]
  : fTokens(std::move(tokens)),
  ^

Maybe you could use unique names for the parameter and the member variable? It would enable compiling the source with quite strict warning configuration.

Thanks,
Markus

How do I set up the options to take optional values?

I might not quite understand the documentation correctly but, suppose I want to set a certain quality to a default level if an option is not passed to the application, a different default value if the option is passed with no arguments, and a third value if the option is passed with certain arguments?

Late error detection 2

In this example, -d is forgotten in the Usage section, but it is listed later, in the options section, when you actually try to use the -d option, it complains:

Unexpected argument: -d, test
R"(DebugviewConsole )" VERSION_STR
R"(
    Usage: 
        DebugviewConsole [-i <pattern>, --include <pattern>]... [-e <pattern>, --exclude <pattern>]... 
        DebugviewConsole (-h | --help)
        DebugviewConsole [-a value]
        DebugviewConsole [-x]
        DebugviewConsole [-u]
        DebugviewConsole [-cflsqtpn]

    Options:
        -h, --help                          show this screen
        -i <pattern>, --include <pattern>   include filter, may be specified multiple times
        -e <pattern>, --exclude <pattern>   exclude filter, may be specified multiple times
        -c              enable console output
        -d <file>       write to .dblog file

    Console options:    (no effect on .dblog file)
        -l              prefix line number

)";

Negative numbers are not properly parsed as argument value

Hi, first of all, many thanks for maintaining this library and in particular this port to C++.

I'm starting to write a library for scientific image processing (Electron Microscopy images) and I was considering to use docopt for command line parsing. In the past I have written my own home-made tools, of course much more limited.

I have started playing with docopt and I have found that negatives values are not properly parsed. Maybe it is getting wrong the regex matching since the negative numbers start with a dash as the optional arguments. The same happens also in the original docopt in Python (which I'm also interesting to use). I tried the simple example of the calculator and it is not working as expected. I think this issue is important for any scientific application that needs to deal with negatives values.

Show I post this issues in the other repository as well?

Thanks in advance.

Example runs fine, but tests fail [gcc 5.2.0]

Some outputs are shown as below, full log is here http://pastie.org/10499035
I tried the pull request #13 but it did not work too
Besides that, for some reasons the python test script could not decode some JSON objects
The example naval_fate runs fine without any problem.

Python version: 2.7.10
GCC: 5.2.0

========================================
Usage: prog [options]

Options: -a  All.


::::::::::::::::::::
prog 
--------------------
{  }

 ** JSON does not match expected: {u'-a': False}
========================================
Usage: prog [options]

Options: -p PATH


::::::::::::::::::::
prog -p home/
--------------------

 ** this should have succeeded! exit code = 255
Traceback (most recent call last):
  File "run_tests", line 45, in <module>
    json_out = json.loads(out)
  File "/anaconda/lib/python2.7/json/__init__.py", line 338, in loads
    return _default_decoder.decode(s)
  File "/anaconda/lib/python2.7/json/decoder.py", line 366, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/anaconda/lib/python2.7/json/decoder.py", line 384, in raw_decode
    raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded

Crash inside regex

This is my usage string:

static const char usage[] =
R"( Usage:
  my_app [-s] [-t <num_threads>] [--config <cfg_file>] [--ult | --test] [<client>]
  my_app (-h | --help)

 Options:
  -s                   Display users' stats.
  -t <num_threads>     Limit number of worker threads.
  --config <cfg_file>  Path to configuration file. [default: data/cfg_fimi.yaml]
  --ult                Run tests: unit level.
  --test               Run tests: full test suite.
  -h --help            Show this screen.
)";

It causes infinite recursion and a crash inside regex matcher. I run it on windows 10, visual studio 15 version as snipped below:
image

Remove either of these lines from the options section:

  -t <num_threads>     Limit number of worker threads.
  --config <cfg_file>  Path to configuration file. [default: data/cfg_fimi.yaml]

and then it works fine. It looks like adding too many option lines causes some issue in the regex runtime. I have no idea if this is VS std library problem, something wrong with docopt or I'm doing something wrong with my usage string. Debugging the regex runtime is rather time consuming and after a quick try I didn't come to any conclusion.

Accessor on StringList

Hi,
That would be a nice feature to add a [ ] accessor on docopt::value to be able to access StringList members without casting nah ?

I just tried docopt.cpp

Hi,

thanks for making this.

Just tried it...! Yay

Here are a view observations:

  1. There's no buildsystem coming with docopt.cpp . Maybe you intended that. Anyhow, it would be good if you had some crossplatform way to generate a lib and maybe distributions can include it?!

    map<string, docopt::value> args = docopt::docopt(USAGE, 
                                                  { argv + 1, argv + argc },
                                                  true,               // show help if requested
                                                  "prog 0.0.0.1");  // version string

    if ( args["--foobar"].asBool() == true )
    {
        foobar = 2;
    }

Coming from python having to manually convert that with asBool() is really looking ugly. Ok, coming from python many things look ugly of tedious in C++.
But I think you could create a docopt::map type (i.e. derived from std::map) that would work better and could overwrite that index (pretty sure it's possible in C++) to automatically return the correct type.
If that's not possible, alternative Idea would be to extend the value type to have some basic value checking:

UPDATE:
Ok, I looked at the code now. You did overload the == operator.... but when I tried == true, there were compiler issues. So, maybe there's just a bug and nothing else there.

Undefined reference to docopt::docopt

When attempting to build the example code, I get the following compiler error using both g++ ((Ubuntu 5.4.0-6ubuntu1~16.04.2) 5.4.0 20160609) and clang (3.8.0-2ubuntu4):

CMakeFiles/projector.dir/main.cpp.o: In function `main':
/home/jeremiah/src/peschkaj/projector/main.cpp:32: undefined reference to `docopt::docopt(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, bool, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)'
/home/jeremiah/src/peschkaj/projector/main.cpp:38: undefined reference to `docopt::operator<<(std::ostream&, docopt::value const&)'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
CMakeFiles/projector.dir/build.make:124: recipe for target 'projector' failed
make[2]: *** [projector] Error 1
CMakeFiles/Makefile2:104: recipe for target 'CMakeFiles/projector.dir/all' failed
make[1]: *** [CMakeFiles/projector.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2

This is on Ubuntu 16.04.1

Docopt is not working on a Qt project

Hi,

I tried to create a Qt project (Qt 5.8 + QtCreator 4.2.1) with just docopt and the main class, and it seems that for some reason Qmake does not understand the docopt.cpp as a source file. Therefore, it does not create an object and fails to link. If I enable the inline mode, it works, but I can't use this way in my original code since I am using docopt in several modules. I looked into the Makefile and indeed and it does not create the rule for docopt.cpp. Someone has a clue why this is happening?

The project file example:

TEMPLATE = app
CONFIG += console c++14
CONFIG -= app_bundle
CONFIG -= qt

SOURCES += main.cpp \
    docopt.cpp

HEADERS += \
    docopt.h \
    docopt_private.h \
    docopt_util.h \
    docopt_value.h

The compilation log:

g++ -c -pipe -g -std=gnu++1y -Wall -W -fPIC -DQT_QML_DEBUG -I../docopt2 -I. -I/usr/lib64/qt5/mkspecs/linux-g++ -o main.o ../docopt2/main.cpp

g++ -o test main.o
main.o: In function main': /home/programming/docopt2/main.cpp:18: undefined reference to docopt::docopt(std::string const&, std::vector<std::string, std::allocatorstd::string > const&, bool, std::string const&, bool)'
collect2: error: ld returned 1 exit status

Parser does not correctly identify option description if on new line

Example of what does not work:

Options:
  --path=<path>
            Some description of what is happening with this path

Error:

Docopt usage string could not be parsed
--path must not have an argument

Examples of what does work:

Options:
  --path=<path> 
            Some description of what is happening with this path
  --path=<path> [default: somedefault]
            Some description of what is happening with this path
  --path=<path>  Some description of what is happening with this path

(for the first working example, note the extra space after --path=<path>

System:

OS X El Capitan (10.11)

Auto type and range checking

I gave it a try! Very nice work.

I would like to propose one thing to make this work really unbeatable:

Adding type check and range information section

This could be in USAGE string buffer or could be given in a separate buffer.

Example:

`static const char USAGE[] =
R"(Naval Fate.

Usage:
  naval_fate ship new <name>...
  naval_fate ship <name> move <x> <y> [--speed=<kn>]
  naval_fate ship shoot <x> <y>
  naval_fate set distance <d>
  naval_fate set filename <file>
  naval_fate mine (set|remove) <x> <y> [--moored | --drifting]
  naval_fate (-h | --help)
  naval_fate --version

Restrictions:
    <name> : string ["apple", "grape", "blueberry"] { default: "apple" }
    <file> : string
    <x> : integer {default: 10}
    <y> : integer [-10..-2000] {default: 20}
    <kn> : unsigned integer [10, 20, 30, 40]
    <d> : float

Options:
  -h --help     Show this screen.
  --version     Show version.
  --speed=<kn>  Speed in knots [default: 10].
  --moored      Moored (anchored) mine.
  --drifting    Drifting mine.

)";`

Type and range error messages can be printed automatically for an argument.

This can help to reduce a lot of type-check / value-range error handling lines and can make our code perfectly clean.

Alternatively, restrictions section can be hidden from user and can be given as a second argument to the parser.

static const char RESTRICTIONS[] =
R"(
        <name> : string [ "apple", "grape", "blueberry" ] { default: "apple" }
        <file> : string
        <x> : integer { default: 10 }
        <y> : integer [ -10..-2000 ] { default: 20 }
        <kn> : unsigned integer [ 10, 20, 30, 40 ]
        <d> : float
)";

...
    std::map<std::string, docopt::value> args
        = docopt::docopt(USAGE, RESTRICTIONS,
                         { argv + 1, argv + argc },
                         true,               // show help if requested
                         "Naval Fate 2.0");  // version string
...

I think restrictions section should be optional. This way, it can be backward compatible. Simple and advanced mode.

Any comments?

runtime error with clang sanitizer

The option -fsanitize=integer with Clang 3.7.1 gives several warnings of the type :

docopt_util.h:96:34: runtime error: unsigned integer overflow: 6142509191626859559 + 15635260900501029888 cannot be represented in type 'unsigned long'
SUMMARY: AddressSanitizer: undefined-behavior

Compiling with Intel compiler failed

I'm trying to compile docopt.cpp using the Intel compiler, in particular

$ icpc --version
icpc (ICC) 17.0.2 20170213
Copyright (C) 1985-2017 Intel Corporation.  All rights reserved.

The compilation is unsuccessful. First, at compile time I can the following warnings:

In file included from /.../docopt.cpp/docopt.cpp(10):
/.../docopt.cpp/docopt_util.h(22): warning #161: unrecognized #pragma
  #pragma mark -
          ^

In file included from /.../docopt.cpp/docopt.cpp(10):
/.../docopt.cpp/docopt_util.h(23): warning #161: unrecognized #pragma
  #pragma mark General utility
          ^

In file included from /.../docopt.cpp/docopt.cpp(11):
/.../docopt.cpp/docopt_private.h(325): warning #161: unrecognized #pragma
  #pragma mark -
          ^

In file included from /.../docopt.cpp/docopt.cpp(11):
/.../docopt.cpp/docopt_private.h(326): warning #161: unrecognized #pragma
  #pragma mark inline implementations
          ^

/.../docopt.cpp/docopt.cpp(57): warning #161: unrecognized #pragma
  #pragma mark -
          ^

/.../docopt.cpp/docopt.cpp(58): warning #161: unrecognized #pragma
  #pragma mark Parsing stuff
          ^

Then at linking I get the following errors

CMakeFiles/....dir/docopt.cpp/docopt.cpp.o: In function `_INTERNAL_68__..._docopt_cpp_docopt_cpp_0dbe0bd8::parse_section(std::string const&, std::string const&)':
docopt.cpp:(.text+0x5d82): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::regex_iterator(__gnu_cxx::__normal_iterator<char const*, std::string>, __gnu_cxx::__normal_iterator<char const*, std::string>, std::basic_regex<char, std::regex_traits<char> > const&, std::bitset<11ul>)'
docopt.cpp:(.text+0x5d8c): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::regex_iterator()'
docopt.cpp:(.text+0x5d9b): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::operator!=(std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> > const&)'
docopt.cpp:(.text+0x5dad): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::operator*()'
docopt.cpp:(.text+0x6252): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::operator++()'
docopt.cpp:(.text+0x6261): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::operator!=(std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> > const&)'
CMakeFiles/....dir/docopt.cpp/docopt.cpp.o: In function `_INTERNAL_68__..._docopt_cpp_docopt_cpp_0dbe0bd8::parse_pattern(std::string const&, std::vector<docopt::Option, std::allocator<docopt::Option> >&)':
docopt.cpp:(.text+0x6896): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::regex_iterator(__gnu_cxx::__normal_iterator<char const*, std::string>, __gnu_cxx::__normal_iterator<char const*, std::string>, std::basic_regex<char, std::regex_traits<char> > const&, std::bitset<11ul>)'
docopt.cpp:(.text+0x68a3): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::regex_iterator()'
docopt.cpp:(.text+0x68c7): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::operator!=(std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> > const&)'
docopt.cpp:(.text+0x68d8): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::operator*()'
docopt.cpp:(.text+0x68f5): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::operator++()'
docopt.cpp:(.text+0x690a): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::operator!=(std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> > const&)'
CMakeFiles/....dir/docopt.cpp/docopt.cpp.o: In function `Tokens::from_pattern(std::string const&)::{lambda(std::match_results<__gnu_cxx::__normal_iterator<char const*, std::string>, std::allocator<std::sub_match<__gnu_cxx::__normal_iterator<char const*, std::string> > > > const&)#1}::operator()(std::match_results<__gnu_cxx::__normal_iterator<char const*, std::string>, std::allocator<std::sub_match<__gnu_cxx::__normal_iterator<char const*, std::string> > > > const&) const':
docopt.cpp:(.text+0x73b6): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::regex_iterator(__gnu_cxx::__normal_iterator<char const*, std::string>, __gnu_cxx::__normal_iterator<char const*, std::string>, std::basic_regex<char, std::regex_traits<char> > const&, std::bitset<11ul>)'
docopt.cpp:(.text+0x73c0): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::regex_iterator()'
docopt.cpp:(.text+0x73d3): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::operator!=(std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> > const&)'
docopt.cpp:(.text+0x73e5): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::operator*()'
docopt.cpp:(.text+0x750e): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::operator++()'
docopt.cpp:(.text+0x751d): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::operator!=(std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> > const&)'
CMakeFiles/....dir/docopt.cpp/docopt.cpp.o: In function `parse_defaults(std::string const&)':
docopt.cpp:(.text+0x9b64): undefined reference to `std::regex_token_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::regex_token_iterator(__gnu_cxx::__normal_iterator<char const*, std::string>, __gnu_cxx::__normal_iterator<char const*, std::string>, std::basic_regex<char, std::regex_traits<char> > const&, int, std::bitset<11ul>)'
docopt.cpp:(.text+0x9b71): undefined reference to `std::regex_token_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::regex_token_iterator()'
docopt.cpp:(.text+0x9b86): undefined reference to `std::regex_token_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::operator!=(std::regex_token_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> > const&)'
docopt.cpp:(.text+0x9bb7): undefined reference to `std::regex_token_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::operator*()'
docopt.cpp:(.text+0x9c7c): undefined reference to `std::regex_token_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::operator++()'
CMakeFiles/....dir/docopt.cpp/docopt.cpp.o: In function `docopt::Option::parse(std::string const&)':
docopt.cpp:(.text._ZN6docopt6Option5parseERKSs[_ZN6docopt6Option5parseERKSs]+0x13a): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::regex_iterator(__gnu_cxx::__normal_iterator<char const*, std::string>, __gnu_cxx::__normal_iterator<char const*, std::string>, std::basic_regex<char, std::regex_traits<char> > const&, std::bitset<11ul>)'
docopt.cpp:(.text._ZN6docopt6Option5parseERKSs[_ZN6docopt6Option5parseERKSs]+0x147): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::regex_iterator()'
docopt.cpp:(.text._ZN6docopt6Option5parseERKSs[_ZN6docopt6Option5parseERKSs]+0x15c): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::operator!=(std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> > const&)'
docopt.cpp:(.text._ZN6docopt6Option5parseERKSs[_ZN6docopt6Option5parseERKSs]+0x171): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::operator*()'
docopt.cpp:(.text._ZN6docopt6Option5parseERKSs[_ZN6docopt6Option5parseERKSs]+0x584): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::operator++()'
docopt.cpp:(.text._ZN6docopt6Option5parseERKSs[_ZN6docopt6Option5parseERKSs]+0x599): undefined reference to `std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> >::operator!=(std::regex_iterator<__gnu_cxx::__normal_iterator<char const*, std::string>, char, std::regex_traits<char> > const&)'

Give the gnu_cxx in the names, I'm not surprised that icpc cannot find them. But I do not know how to proceed?

The error is persistent when compiling with boost. Here is the CMakeLists.txt that I have used:

cmake_minimum_required(VERSION 2.8.12)

project(naval_fate)

set(CMAKE_CXX_STANDARD 14)
add_definitions(-DOCTOPT_USE_BOOST_REGEX)

find_program(INTEL_COMPILER icc)

find_package(Boost)
include_directories(${Boost_INCLUDE_DIRS})

add_executable(${PROJECT_NAME} naval_fate.cpp docopt.cpp)

target_link_libraries(${PROJECT_NAME} LINK_PUBLIC ${Boost_LIBRARIES} )

Use template classe for extraction of values ?

The interface would be nicer if we could do

auto out = args["--output"].as<std::string>();
auto num = args["--num"].as<size_t>();

instead of

auto out = args["--output"].asString();
auto num = args["--num"].asLong();

I do not know if this is possible of not.

Put license text into source files

It's easier for applications to include your source files, when the license text is on top of every .h and .cpp file, because every future "user/developer" of the file will immediatly see what the license is. All you're seeing right now is the copyright, which even might scare a view people of. Of course there are the license files and the problem is you're using two licenses.

I would suggest putting the MIT license in every source file, which is short, and to also put one ore two lines mentioning the alternative Boost license underneath the MIT license.

Why is this important? I quote the howto on the GPL for this (because they have good lawyers):

"Whichever license you plan to use, the process involves adding two elements to each source file of your program: a copyright notice (such as “Copyright 1999 Terry Jones”), and a statement of copying permission, saying that the program is distributed under the terms of the GNU General Public License (or the Lesser GPL)."

http://www.gnu.org/licenses/gpl-howto.en.html

Missing float/double values

I start to use this great lib but I am missing ways to use float/double numbers in the input. Apparently it is simple to do that modifying union Variant and other methods from struct value. Is there some reason for this not be implemented? If not, I will implement and submit a patch.

`WIN32` definition for creating DLLs on Windows is somewhat misleading

The PR that added WIN32 dllimport/dllexport stuff inadvertently seems to have broken static linking with docopt_s if you have WIN32 defined.

The problem seems to be with symbols being tagged with dllexport/dllimport due to the WIN32 flag being defined.

The problem is exhibited on my setup:
using CMake with -G"Visual Studio 14 2015 Win64" -TLLVM-vs2014 arguments (so clang 3.9.0 toolset and using msbuild/visual studio to build)

I am unsure if the same problem is exhibited when building with cl.

I think a good resolution is maybe changing the WIN32 flag to be named something a little more obvious like WIN32_DLL or something and providing some documentation regarding it in the CMakeLists.txt and Readme.rst file.

If you want I could write up a quick blurb and do some more testing to verify whether this happens when using cl or not and submit a PR Just let me know!

Error message not helpfull

phooey.exe -h
Docopt usage string could not be parsed
Mismatched '['

message has no linenr, nor any text/tokens of line offending line.
I will add the reproduction scenario as soon as I figure out what line it is, by binary search elimination.

Cannot distinguish default value from value given by a user

Given this usage text

Usage:
mycli [options]
mycli ADDRESS VALUE

Options:
-h, --help                   Show this screen.
-v, --version                Show version.
--always_set=[<n>]       This set to its default [default: 10].

arg.first.compare ( "--always_set" ) will always be true and arg.second.asLong() will be 10, even if the option --always_set has not been passed.

What I would like to achieve instead is:

mycli -> arg.first.compare ( "--always_set" ) is false
mycli --always_set=2 -> arg.first.compare ( "--always_set" ) is true and arg.second.asLong() is 2
mycli --always_set -> arg.first.compare ( "--always_set" ) is true and arg.second.asLong() is 10. Actually this gives an error, although I (tried to) set the value of --always_set optional using the angular brackets.

Is there a way to achieve what I want?

Regex expressions cause stack overflows in MSVC 2015

First of all, let me thank you for this awesome library!

The standard <regex> implementation for Visual C++ seems to have a rather severe design issue that seems to cause stack overflows for complicated expressions (I suspect the lookaheads you use, but I'm not really sure about that). A couple of google searches revealed that this seems to be a known issue. Some people seem to have been able to avoid the problem by increasing their stack size, but that didn't help in my case (I've added an example program below that reproduces the problem; the nested method calls in std::_Matcher are really quite insane).

I've already written a patch for parse_section that resolves my original problem, but I still get a similar error in parse_defaults with the demo program below. Also, I unfortunately don't have any git-tools at my disposal right now, so I can't start a pull request for this.
For now, I'll post my version of parse_section in the comments and see if I can come up with a similar "fix" for the other expressions.

Here's my test program to reproduce the problem:

#include <docopt.h>
#include <iostream>
#include <string>

void printArguments(const std::map<std::string, docopt::value> &args)
{
    std::cout << "Arguments:\n\n";
    for (auto &entry : args)
    {
        const std::string &name = entry.first;
        const docopt::value &value = entry.second;

        std::cout << name << ": \n";

        if (value.isString())
            std::cout << "       (string)   " << value.asString() << "\n\n";
        else if (value.isLong())
            std::cout << "       (long)     " << value.asLong() << "\n\n";
        else if (value.isBool())
            std::cout << "       (bool)     " << value.asBool() << "\n\n";
        else if (value.isStringList())
        {
            const auto &list = value.asStringList();
            std::cout << "       (str_list) [\n";

            for (auto &str : list)
                std::cout << "                        " << str << ",\n";
            std::cout << "                  ]\n\n";
        }
        else if (!value) std::cout << "       (empty)\n\n";
        else std::cout << "       (unknown)\n\n";

    }
    std::cout << std::endl;
}

const auto USAGE =
R"(
Usage:
    foo [options] <ARG1> <ARG2> [--option1=<OPTION1>] [--option2=<OPTION2>]
    foo --command1 <ARG3> <ARG4> <ARG5> <ARG6>  [--option3=<OPTION3> [--option4=<OPTION4>]] [--option5=<OPTION5>]
    foo --command2 <ARG4>
    foo (-v | --version)
    foo (-h | --help)

Options:
    -o <OPTION6>, --option6=<OPTION6>      Some rather long description of option #6 which makes this line longer than it really should be...
)";

void main(int argc, const char** argv)
{
    try
    {
        auto arguments = docopt::docopt(USAGE, { argv + 1,argv + argc }, true, "1.0.0.0", true);
        printArguments(arguments);
    }
    catch (std::exception &e)
    {
        std::cerr << "Encountered exception of type "
            << typeid(e).name() << ": "
            << e.what();
    }
    std::cin.ignore();
}

MS Visual Studio and undesired warning C4068: unknown pragma

When compiling the code with MS Visual Studio 2015 (Version 14.0.25123.00 Update 2) I get several undesired warnings C4068: unknown pragma.

xxx\docopt\docopt_util.h(22): warning C4068: unknown pragma
xxx\docopt\docopt_util.h(23): warning C4068: unknown pragma
xxx\docopt\docopt_private.h(325): warning C4068: unknown pragma
xxx\docopt\docopt_private.h(326): warning C4068: unknown pragma
xxx\docopt\docopt.cpp(57): warning C4068: unknown pragma
xxx\docopt\docopt.cpp(58): warning C4068: unknown pragma

I know, this warnings are uncritical, but usually when compiling I prefer to see 0 warnings 0 errors.
It seems this issue is caused by pragmas which make happy some Apple related compilers like ObjectiveC.
Is it possible to surround these pragmas with something like this?

#ifndef _MSC_VER
#pragma mark -
#pragma mark General utility
#endif

Integer arguments are parsed as strings

Integer arguments are always parsed by docopt::docopt as strings. For example:

// In naval_fate.cpp
int main(int argc, const char** argv)
{
    std::map<std::string, docopt::value> args = docopt::docopt(USAGE, 
                                                  { argv + 1, argv + argc },
                                                  true,               // show help if requested
                                                  "Naval Fate 2.0");  // version string

    for(auto const& arg : args) {
        std::cout << arg.first << ": " << arg.second << std::endl;
    }
    // Test
    if (args["<x>"]) std::cout << args["<x>"].asLong(); // Throws here
    if (args["<y>"]) std::cout << args["<y>"].asLong();

    return 0;
}

throws, giving

terminate called after throwing an instance of 'std::runtime_error'
what(): Illegal cast to long; type is actually string

By the principle of least astonishment, I would think that calling asLong on an integral argument would give me a long with no hassle. But some quick inspection of docopt_value.h and docopt.cpp shows that the value's internal union is fed a string, and toLong throws its hands up instead of attempting some conversion.

Forgive me if I'm missing something obvious (as I haven't dug through the code thoroughly). Is this expected behavior? Of course you can always parse the values yourself with istringstream or sscanf, but doing so is a bit of a pain, especially for a library focused on simplicity and expressiveness.

Building with gcc 4.8

I needed to build docopt using GCC 4.8, because this is default compiler in CentOS 7.

GCC 4.8 C++11 support is good, but all the <regex> functionalities are missing. So I created a fallback to Boost.Regex when building with GCC 4.8, and used C++11 regex in all other cases.

I used the following diff:

diff --git a/docopt.cpp b/docopt.cpp
index 2fd5f42..ce983c5 100644
--- a/docopt.cpp
+++ b/docopt.cpp
@@ -17,9 +17,24 @@
 #include <unordered_map>
 #include <map>
 #include <string>
-#include <regex>
 #include <iostream>
 #include <cassert>
 #include <cstddef>

+#ifdef DOCOPT_USES_BOOST_REGEX
+#include <boost/regex.hpp>
+namespace std {
+   using boost::regex;
+   using boost::sregex_iterator;
+   using boost::smatch;
+   using boost::regex_search;
+   namespace regex_constants {
+       using boost::regex_constants::match_not_null;
+   }
+}
+#else
+#include <regex>
+#endif

If you want to include this in docopt, I can do a PR.

Define validation or possible values for the value of an option

Fiven the following usage string:

Usage:
  vrplayer-openvr [--option VALUE]

Options:
  --option VALUE  Set of options (first|second|third) [default: first]

Is it possible to validate a set of options (see the values in the parenthesis.

Could it be written also as:

  --option VALUE  Set of options [values: first|second|third, default: first]

If not possible, then its a feature request.

Long params don't except space instead of = for an empty opt arg

I believe that the docopt spec allows a long opt to be separated from its param by either an equals or a space. docopt c++ only accepts an equals. I've now realised that this is only for the edge case where the param is an empty string. This is possible using exec* system calls or indeed bash as follows:
myprog --opt ""
I'm not that familiar with the code but I question the if statement docopt.cpp:653

    if (token.empty() || token=="--") {
        std::string error = o->longOption() + " requires an argument";
        throw Tokens::OptionError(std::move(error));
    }

I'm not sure this is needed at all. val should just always be then next token regardless.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.