8000 Fixes parsing of [default: x] in some cases on Win. · lineCode/docopt.cpp@9ca0721 · GitHub
[go: up one dir, main page]

Skip to content
8000

Commit 9ca0721

Browse files
rhorenovGuillaume Fraux
rhorenov
authored and
Guillaume Fraux
committed
Fixes parsing of [default: x] in some cases on Win.
If the option definition spans over multiple lines, then parsing of the [default: x] was not working on Windows - tested on MS Visual Studio 2015. This is due to the differences in regex's multiline property implementation. On some platforms - Linux libstd++ the multiline property is off, on some platforms - msvc2015 the multiline property is on. It cannot be changed programmatically AFAIK. I was not able to come up with a regex expression which would work on Linux and on Windows as well. So I tried to be smart and replace '\n' by '\f' in the string beforehand. The regex was easy and worked on Linux and Windows just fine - up until I tried a longer option definition. Then the msvc2015 regex failed with 'stack' exception. Hence this change. It splits the option definition section by a simple regex which does not use the problematic '$'. modified: docopt.cpp modified: docopt_util.h
1 parent 6f24219 commit 9ca0721

File tree

2 files changed

+43
-31
lines changed

2 files changed

+43
-31
lines changed

docopt.cpp

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -521,31 +521,23 @@ static PatternList parse_argv(Tokens tokens, std::vector<Option>& options, bool
521521
return ret;
522522
}
523523

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

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

536-
for(auto s : parse_section("options:", doc)) {
537-
s.erase(s.begin(), s.begin()+static_cast<std::ptrdiff_t>(s.find(':'))+1); // get rid of "options:"
538-
539-
std::for_each(std::sregex_iterator{ s.begin(), s.end(), pattern },
540-
std::sregex_iterator{},
541-
[&](std::smatch const& m)
542-
{
543-
std::string opt = m[1].str();
544-
536+
for (const auto& opt : regex_split(s, re_delimiter)) {
545537
if (starts_with(opt, "-")) {
546538
defaults.emplace_back(Option::parse(opt));
547539
}
548-
});
540+
}
549541
}
550542

551543
return defaults;

docopt_util.h

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,15 @@
99
#ifndef docopt_docopt_util_h
1010
#define docopt_docopt_util_h
1111

12+
#if DOCTOPT_USE_BOOST_REGEX
13+
#include <boost/regex.hpp>
14+
namespace std {
15+
using boost::regex;
16+
using boost::sregex_token_iterator;
17+
}
18+
#else
19+
#include <regex>
20+
#endif
1221

1322
#pragma mark -
1423
#pragma mark General utility
@@ -21,46 +30,46 @@ namespace {
2130
return std::equal(prefix.begin(), prefix.end(),
2231
str.begin());
2332
}
24-
33+
2534
std::string trim(std::string&& str,
2635
const std::string& whitespace = " \t\n")
2736
{
2837
const auto strEnd = str.find_last_not_of(whitespace);
2938
if (strEnd==std::string::npos)
3039
return {}; // no content
3140
str.erase(strEnd+1);
32-
41+
3342
const auto strBegin = str.find_first_not_of(whitespace);
3443
str.erase(0, strBegin);
35-
44+
3645
return std::move(str);
3746
}
38-
47+
3948
std::vector<std::string> split(std::string const& str, size_t pos = 0)
4049
{
4150
const char* const anySpace = " \t\r\n\v\f";
42-
51+
4352
std::vector<std::string> ret;
4453
while (pos != std::string::npos) {
4554
auto start = str.find_first_not_of(anySpace, pos);
4655
if (start == std::string::npos) break;
47-
56+
4857
auto end = str.find_first_of(anySpace, start);
4958
auto size = end==std::string::npos ? end : end-start;
5059
ret.emplace_back(str.substr(start, size));
51-
60+
5261
pos = end;
5362
}
54-
63+
5564
return ret;
5665
}
57-
66+
5867
std::tuple<std::string, std::string, std::string> partition(std::string str, std::string const& point)
5968
{
6069
std::tuple<std::string, std::string, std::string> ret;
61-
70+
6271
auto i = str.find(point);
63-
72+
6473
if (i == std::string::npos) {
6574
// no match: string goes in 0th spot only
6675
} else {
@@ -69,22 +78,33 @@ namespace {
6978
str.resize(i);
7079
}
7180
std::get<0>(ret) = std::move(str);
72-
81+
7382
return ret;
7483
}
75-
84+
7685
template <typename I>
7786
std::string join(I iter, I end, std::string const& delim) {
7887
if (iter==end)
7988
return {};
80-
89+
8190
std::string ret = *iter;
8291
for(++iter; iter!=end; ++iter) {
8392
ret.append(delim);
8493
ret.append(*iter);
8594
}
8695
return ret;
8796
}
97+
98+
std::vector<std::string> regex_split(std::string const& text, std::regex const& re)
99+
{
100+
std::vector<std::string> ret;
101+
for (auto it = std::sregex_token_iterator(text.begin(), text.end(), re, -1);
102+
it != std::sregex_token_iterator();
103+
++it) {
104+
ret.emplace_back(*it);
105+
}
106+
return ret;
107+
}
88108
}
89109

90110
namespace docopt {

0 commit comments

Comments
 (0)
0