When a {} repeat sequence is invalid or incomplete, and the language is Perl, then backtrack and treat the sequence as a literal, not a repeat operator.

Fixes #8569.

[SVN r84371]
This commit is contained in:
John Maddock
2013-05-19 11:12:14 +00:00
parent 8a16bff57a
commit 66d8b8140a
2 changed files with 64 additions and 29 deletions

View File

@ -1070,27 +1070,47 @@ bool basic_regex_parser<charT, traits>::parse_repeat_range(bool isbasic)
// skip whitespace: // skip whitespace:
while((m_position != m_end) && this->m_traits.isctype(*m_position, this->m_mask_space)) while((m_position != m_end) && this->m_traits.isctype(*m_position, this->m_mask_space))
++m_position; ++m_position;
// fail if at end:
if(this->m_position == this->m_end) if(this->m_position == this->m_end)
{
if(this->flags() & (regbase::main_option_type | regbase::no_perl_ex))
{ {
fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message);
return false; return false;
} }
// Treat the opening '{' as a literal character, rewind to start of error:
--m_position;
while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position;
return parse_literal();
}
// get min: // get min:
v = this->m_traits.toi(m_position, m_end, 10); v = this->m_traits.toi(m_position, m_end, 10);
// skip whitespace: // skip whitespace:
while((m_position != m_end) && this->m_traits.isctype(*m_position, this->m_mask_space))
++m_position;
if(v < 0) if(v < 0)
{ {
fail(regex_constants::error_badbrace, this->m_position - this->m_base); if(this->flags() & (regbase::main_option_type | regbase::no_perl_ex))
return false;
}
else if(this->m_position == this->m_end)
{ {
fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message);
return false; return false;
} }
// Treat the opening '{' as a literal character, rewind to start of error:
--m_position;
while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position;
return parse_literal();
}
while((m_position != m_end) && this->m_traits.isctype(*m_position, this->m_mask_space))
++m_position;
if(this->m_position == this->m_end)
{
if(this->flags() & (regbase::main_option_type | regbase::no_perl_ex))
{
fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message);
return false;
}
// Treat the opening '{' as a literal character, rewind to start of error:
--m_position;
while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position;
return parse_literal();
}
min = v; min = v;
// see if we have a comma: // see if we have a comma:
if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_comma) if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_comma)
@ -1101,10 +1121,17 @@ bool basic_regex_parser<charT, traits>::parse_repeat_range(bool isbasic)
while((m_position != m_end) && this->m_traits.isctype(*m_position, this->m_mask_space)) while((m_position != m_end) && this->m_traits.isctype(*m_position, this->m_mask_space))
++m_position; ++m_position;
if(this->m_position == this->m_end) if(this->m_position == this->m_end)
{
if(this->flags() & (regbase::main_option_type | regbase::no_perl_ex))
{ {
fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message);
return false; return false;
} }
// Treat the opening '{' as a literal character, rewind to start of error:
--m_position;
while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position;
return parse_literal();
}
// get the value if any: // get the value if any:
v = this->m_traits.toi(m_position, m_end, 10); v = this->m_traits.toi(m_position, m_end, 10);
max = (v >= 0) ? (std::size_t)v : (std::numeric_limits<std::size_t>::max)(); max = (v >= 0) ? (std::size_t)v : (std::numeric_limits<std::size_t>::max)();
@ -1119,10 +1146,17 @@ bool basic_regex_parser<charT, traits>::parse_repeat_range(bool isbasic)
++m_position; ++m_position;
// OK now check trailing }: // OK now check trailing }:
if(this->m_position == this->m_end) if(this->m_position == this->m_end)
{
if(this->flags() & (regbase::main_option_type | regbase::no_perl_ex))
{ {
fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message);
return false; return false;
} }
// Treat the opening '{' as a literal character, rewind to start of error:
--m_position;
while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position;
return parse_literal();
}
if(isbasic) if(isbasic)
{ {
if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_escape) if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_escape)
@ -1144,8 +1178,10 @@ bool basic_regex_parser<charT, traits>::parse_repeat_range(bool isbasic)
++m_position; ++m_position;
else else
{ {
fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); // Treat the opening '{' as a literal character, rewind to start of error:
return false; --m_position;
while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position;
return parse_literal();
} }
// //
// finally go and add the repeat, unless error: // finally go and add the repeat, unless error:

View File

@ -179,21 +179,20 @@ void test_simple_repeats2()
{ {
using namespace boost::regex_constants; using namespace boost::regex_constants;
TEST_INVALID_REGEX("a{}", perl); TEST_REGEX_SEARCH("a{}", basic, "a{}", match_default, make_array(0, 3, -2, -2));
TEST_INVALID_REGEX("a{", perl); TEST_REGEX_SEARCH("a{", basic, "a{", match_default, make_array(0, 2, -2, -2));
TEST_INVALID_REGEX("a{1", perl); TEST_REGEX_SEARCH("a{1", basic, "a{1", match_default, make_array(0, 3, -2, -2));
TEST_INVALID_REGEX("a{1,", perl); TEST_REGEX_SEARCH("a{1,", basic, "a{1,", match_default, make_array(0, 4, -2, -2));
TEST_INVALID_REGEX("a{1,2", perl); TEST_REGEX_SEARCH("a{1,2", basic, "a{1,2", match_default, make_array(0, 5, -2, -2));
TEST_INVALID_REGEX("a{ 1 , 2 ", perl); TEST_REGEX_SEARCH("a{ 1 , 2", basic, "a{ 1 , 2", match_default, make_array(0, 8, -2, -2));
TEST_INVALID_REGEX("a{ }", perl); TEST_REGEX_SEARCH("a{ }", basic, "a{ }", match_default, make_array(0, 4, -2, -2));
TEST_INVALID_REGEX("a}", perl); TEST_REGEX_SEARCH("a}", basic, "a}", match_default, make_array(0, 2, -2, -2));
TEST_INVALID_REGEX("{1}", perl); TEST_INVALID_REGEX("{1}", perl);
TEST_INVALID_REGEX("a{b}", perl); TEST_REGEX_SEARCH("a{b}", basic, "a{b}", match_default, make_array(0, 4, -2, -2));
TEST_INVALID_REGEX("a{1b}", perl); TEST_REGEX_SEARCH("a{1b", basic, "a{1b", match_default, make_array(0, 4, -2, -2));
TEST_INVALID_REGEX("a{1,b}", perl); TEST_REGEX_SEARCH("a{1,b}", basic, "a{1,b}", match_default, make_array(0, 6, -2, -2));
TEST_INVALID_REGEX("a{1,2v}", perl); TEST_REGEX_SEARCH("a{1,2v}", basic, "a{1,2v}", match_default, make_array(0, 7, -2, -2));
TEST_INVALID_REGEX("a{2,1}", perl); TEST_INVALID_REGEX("a{2,1}", perl);
// now try operator \\{\\} for POSIX basic regexes // now try operator \\{\\} for POSIX basic regexes
TEST_REGEX_SEARCH("a\\{2\\}", basic, "a", match_default, make_array(-2, -2)); TEST_REGEX_SEARCH("a\\{2\\}", basic, "a", match_default, make_array(-2, -2));
TEST_REGEX_SEARCH("a\\{2\\}", basic|no_intervals, "a{2}", match_default, make_array(0, 4, -2, -2)); TEST_REGEX_SEARCH("a\\{2\\}", basic|no_intervals, "a{2}", match_default, make_array(0, 4, -2, -2));