1) Disabled recursive implementation for VC8: stack overflows can't be reliably detected unless the whole program is compiled with asynchronous exceptions.

2) Changed std::copy calls on VC8 to avoid "dangerous code" warnings.
3) Moved backreference and octal escape code into line with POSIX-extended requirements.
4) Changed match_results leftmost-longest rules to stop unnecessary std::distance computations (an optimisation for non-random access iterators).
5) Changed C lib calls to use "safe" versions of string API's where available.
6) Added many new POSIX-extended leftmost-longest tests, to verify the above.


[SVN r27880]
This commit is contained in:
John Maddock
2005-03-30 11:38:51 +00:00
parent ca144bb2b3
commit de28eb9b18
17 changed files with 361 additions and 106 deletions

View File

@ -319,7 +319,7 @@ BOOST_REGEX_DECL void BOOST_REGEX_CALL reset_stack_guard_page();
****************************************************************************/
#if !defined(BOOST_REGEX_RECURSIVE) && !defined(BOOST_REGEX_NON_RECURSIVE)
# if defined(BOOST_REGEX_HAS_MS_STACK_GUARD) && !defined(_STLP_DEBUG) && !defined(__STL_DEBUG)
# if defined(BOOST_REGEX_HAS_MS_STACK_GUARD) && !defined(_STLP_DEBUG) && !defined(__STL_DEBUG) && !(defined(BOOST_MSVC) && (BOOST_MSVC >= 1400))
# define BOOST_REGEX_RECURSIVE
# else
# define BOOST_REGEX_NON_RECURSIVE

View File

@ -728,7 +728,7 @@ OutputIterator do_regex_replace(OutputIterator out,
if(i == j)
{
if(!(flags & regex_constants::format_no_copy))
out = std::copy(in.first, in.second, out);
out = re_detail::copy(in.first, in.second, out);
}
else
{
@ -736,7 +736,7 @@ OutputIterator do_regex_replace(OutputIterator out,
while(i != j)
{
if(!(flags & regex_constants::format_no_copy))
out = std::copy(i->prefix().first, i->prefix().second, out);
out = re_detail::copy(i->prefix().first, i->prefix().second, out);
out = ::boost::re_detail::regex_format_imp(out, *i, &*f.begin(), &*f.end(), flags, e.get_traits());
last_m = (*i)[0].second;
if(flags & regex_constants::format_first_only)
@ -744,7 +744,7 @@ OutputIterator do_regex_replace(OutputIterator out,
++i;
}
if(!(flags & regex_constants::format_no_copy))
out = std::copy(last_m, in.second, out);
out = re_detail::copy(last_m, in.second, out);
}
return out;
}

View File

@ -435,10 +435,10 @@ re_syntax_base* basic_regex_creator<charT, traits>::append_set(
return 0;
}
charT* p = static_cast<charT*>(this->m_pdata->m_data.extend(sizeof(charT) * (s1.size() + s2.size() + 2) ) );
std::copy(s1.begin(), s1.end(), p);
re_detail::copy(s1.begin(), s1.end(), p);
p[s1.size()] = charT(0);
p += s1.size() + 1;
std::copy(s2.begin(), s2.end(), p);
re_detail::copy(s2.begin(), s2.end(), p);
p[s2.size()] = charT(0);
}
//
@ -459,7 +459,7 @@ re_syntax_base* basic_regex_creator<charT, traits>::append_set(
if(s.empty())
return 0; // invalid or unsupported equivalence class
charT* p = static_cast<charT*>(this->m_pdata->m_data.extend(sizeof(charT) * (s.size()+1) ) );
std::copy(s.begin(), s.end(), p);
re_detail::copy(s.begin(), s.end(), p);
p[s.size()] = charT(0);
++first;
}
@ -620,7 +620,7 @@ void basic_regex_creator<charT, traits>::finalize(const charT* p1, const charT*
m_pdata->m_expression_len = len;
charT* ps = static_cast<charT*>(m_pdata->m_data.extend(sizeof(charT) * (1 + (p2 - p1))));
m_pdata->m_expression = ps;
std::copy(p1, p2, ps);
re_detail::copy(p1, p2, ps);
ps[p2 - p1] = 0;
// fill in our other data...
// successful parsing implies a zero status:

View File

@ -1422,7 +1422,15 @@ charT basic_regex_parser<charT, traits>::unescape_character()
// an octal escape sequence, the first character must be a zero
// followed by up to 3 octal digits:
std::ptrdiff_t len = (std::min)(::boost::re_detail::distance(m_position, m_end), static_cast<std::ptrdiff_t>(4));
int val = this->m_traits.toi(m_position, m_position + len, 8);
const charT* bp = m_position;
int val = this->m_traits.toi(bp, bp + 1, 8);
if(val != 0)
{
// Oops not an octal escape after all:
fail(regex_constants::error_escape, m_position - m_base);
return result;
}
val = this->m_traits.toi(m_position, m_position + len, 8);
if(val < 0)
{
fail(regex_constants::error_escape, m_position - m_base);
@ -1477,19 +1485,20 @@ template <class charT, class traits>
bool basic_regex_parser<charT, traits>::parse_backref()
{
BOOST_ASSERT(m_position != m_end);
int i = this->m_traits.toi(m_position, m_position + 1, 10);
if((i > 0) && (this->m_backrefs & (1u << (i-1))))
{
re_brace* pb = static_cast<re_brace*>(this->append_state(syntax_element_backref, sizeof(re_brace)));
pb->index = i;
}
else if(i == 0)
const charT* pc = m_position;
int i = this->m_traits.toi(pc, pc + 1, 10);
if((i == 0) || (((this->flags() & regbase::main_option_type) == regbase::perl_syntax_group) && (this->flags() & regbase::no_bk_refs)))
{
// not a backref at all but an octal escape sequence:
--m_position;
charT c = unescape_character();
this->append_literal(c);
}
else if((i > 0) && (this->m_backrefs & (1u << (i-1))))
{
m_position = pc;
re_brace* pb = static_cast<re_brace*>(this->append_state(syntax_element_backref, sizeof(re_brace)));
pb->index = i;
}
else
{
fail(regex_constants::error_backref, m_position - m_end);

View File

@ -300,29 +300,73 @@ void BOOST_REGEX_CALL match_results<BidiIterator, Allocator>::maybe_assign(const
const_iterator p1, p2;
p1 = begin();
p2 = m.begin();
BidiIterator base = (*this)[-1].first;
std::size_t len1 = 0;
std::size_t len2 = 0;
std::size_t base1 = 0;
std::size_t base2 = 0;
//
// Distances are measured from the start of *this* match, unless this isn't
// a valid match in which case we use the start of the whole sequence. Note that
// no subsequent match-candidate can ever be to the left of the first match found.
// This ensures that when we are using bidirectional iterators, that distances
// measured are as short as possible, and therefore as efficient as possible
// to compute. Finally note that we don't use the "matched" data member to test
// whether a sub-expression is a valid match, because partial matches set this
// to false for sub-expression 0.
//
BidiIterator end = this->suffix().second;
BidiIterator base = (p1->first == end) ? this->prefix().first : (*this)[0].first;
difference_type len1 = 0;
difference_type len2 = 0;
difference_type base1 = 0;
difference_type base2 = 0;
std::size_t i;
for(i = 0; i < size(); ++i)
for(i = 0; i < size(); ++i, ++p1, ++p2)
{
//
// leftmost takes priority over longest:
// Leftmost takes priority over longest; handle special cases
// where distances need not be computed first (an optimisation
// for bidirectional iterators: ensure that we don't accidently
// compute the length of the whole sequence, as this can be really
// expensive).
//
if(p1->first == end)
{
if(p2->first != end)
{
// p2 must be better than p1, and no need to calculate
// actual distances:
base1 = 1;
base2 = 0;
break;
}
else
{
// *p1 and *p2 are either unmatched or match end-of sequence,
// either way no need to calculate distances:
if((p1->matched == false) && (p2->matched == true))
break;
if((p1->matched == true) && (p2->matched == false))
return;
continue;
}
}
else if(p2->first == end)
{
// p1 better than p2, and no need to calculate distances:
return;
}
base1 = ::boost::re_detail::distance(base, p1->first);
base2 = ::boost::re_detail::distance(base, p2->first);
BOOST_ASSERT(base1 >= 0);
BOOST_ASSERT(base2 >= 0);
if(base1 < base2) return;
if(base2 < base1) break;
len1 = ::boost::re_detail::distance((BidiIterator)p1->first, (BidiIterator)p1->second);
len2 = ::boost::re_detail::distance((BidiIterator)p2->first, (BidiIterator)p2->second);
BOOST_ASSERT(len1 >= 0);
BOOST_ASSERT(len2 >= 0);
if((len1 != len2) || ((p1->matched == false) && (p2->matched == true)))
break;
if((p1->matched == true) && (p2->matched == false))
return;
++p1;
++p2;
}
if(i == size())
return;

View File

@ -524,6 +524,9 @@ void basic_regex_formatter<OutputIterator, Results, traits>::put(const sub_match
template <class S>
class string_out_iterator
#ifndef BOOST_NO_STD_ITERATOR
: public std::iterator<std::output_iterator_tag, typename S::value_type>
#endif
{
S* out;
public:
@ -537,11 +540,13 @@ public:
return *this;
}
#ifdef BOOST_NO_STD_ITERATOR
typedef std::ptrdiff_t difference_type;
typedef typename S::value_type value_type;
typedef value_type* pointer;
typedef value_type& reference;
typedef std::output_iterator_tag iterator_category;
#endif
};
template <class OutputIterator, class Iterator, class Alloc, class charT, class traits>
@ -554,7 +559,7 @@ OutputIterator regex_format_imp(OutputIterator out,
{
if(flags & regex_constants::format_literal)
{
return std::copy(p1, p2, out);
return re_detail::copy(p1, p2, out);
}
re_detail::basic_regex_formatter<

View File

@ -41,7 +41,7 @@ OutputIterator regex_replace(OutputIterator out,
if(i == j)
{
if(!(flags & regex_constants::format_no_copy))
out = std::copy(first, last, out);
out = re_detail::copy(first, last, out);
}
else
{
@ -49,7 +49,7 @@ OutputIterator regex_replace(OutputIterator out,
while(i != j)
{
if(!(flags & regex_constants::format_no_copy))
out = std::copy(i->prefix().first, i->prefix().second, out);
out = re_detail::copy(i->prefix().first, i->prefix().second, out);
out = i->format(out, fmt, flags, e);
last_m = (*i)[0].second;
if(flags & regex_constants::format_first_only)
@ -57,7 +57,7 @@ OutputIterator regex_replace(OutputIterator out,
++i;
}
if(!(flags & regex_constants::format_no_copy))
out = std::copy(last_m, last, out);
out = re_detail::copy(last_m, last, out);
}
return out;
}

View File

@ -1,6 +1,6 @@
/*
*
* Copyright (c) 1998-2004
* Copyright (c) 1998-2005
* John Maddock
*
* Use, modification and distribution are subject to the
@ -43,6 +43,12 @@
# include <locale>
#endif
#if defined(BOOST_NO_STDC_NAMESPACE)
namespace std{
using ::sprintf; using ::strcpy; using ::strcat; using ::strlen;
}
#endif
namespace boost{ namespace re_detail{
#ifdef BOOST_NO_STD_DISTANCE
template <class T>
@ -112,4 +118,73 @@ inline void pointer_construct(T* p, const T& t)
}} // namespaces
#endif
/*****************************************************************************
*
* helper function copy:
*
****************************************************************************/
#ifdef __cplusplus
namespace boost{ namespace re_detail{
#if BOOST_WORKAROUND(BOOST_MSVC,>=1400)
//
// MSVC 8 will either emit warnings or else refuse to compile
// code that makes perfectly legitimate use of std::copy, when
// the OutputIterator type is a user-defined class (apparently all user
// defined iterators are "unsafe"). This code works around that:
//
template<class InputIterator, class OutputIterator>
inline OutputIterator copy(
InputIterator first,
InputIterator last,
OutputIterator dest
)
{
return stdext::unchecked_copy(first, last, dest);
}
// use safe versions of strcpy etc:
using ::strcpy_s;
using ::strcat_s;
#else
using std::copy;
inline std::size_t strcpy_s(
char *strDestination,
std::size_t sizeInBytes,
const char *strSource
)
{
if(std::strlen(strSource)+1 > sizeInBytes)
return 1;
std::strcpy(strDestination, strSource);
return 0;
}
inline std::size_t strcat_s(
char *strDestination,
std::size_t sizeInBytes,
const char *strSource
)
{
if(std::strlen(strSource) + std::strlen(strDestination) + 1 > sizeInBytes)
return 1;
std::strcat(strDestination, strSource);
return 0;
}
#endif
inline void overflow_error_if_not_zero(std::size_t i)
{
if(i)
{
std::overflow_error e("String buffer too small");
boost::throw_exception(e);
}
}
}} // namespaces
#endif
#endif // include guard

View File

@ -33,12 +33,6 @@ typedef boost::match_flag_type match_flag_type;
#endif
#include <cstdio>
#if defined(BOOST_NO_STDC_NAMESPACE)
namespace std{
using ::sprintf; using ::strcpy; using ::strcat;
}
#endif
namespace boost{
#ifdef __BORLANDC__
@ -342,17 +336,17 @@ void BuildFileList(std::list<std::string>* pl, const char* files, bool recurse)
{
// go through sub directories:
char buf[MAX_PATH];
std::strcpy(buf, start.root());
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(buf, MAX_PATH, start.root()));
if(*buf == 0)
{
std::strcpy(buf, ".");
std::strcat(buf, directory_iterator::separator());
std::strcat(buf, "*");
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(buf, MAX_PATH, "."));
re_detail::overflow_error_if_not_zero(re_detail::strcat_s(buf, MAX_PATH, directory_iterator::separator()));
re_detail::overflow_error_if_not_zero(re_detail::strcat_s(buf, MAX_PATH, "*"));
}
else
{
std::strcat(buf, directory_iterator::separator());
std::strcat(buf, "*");
re_detail::overflow_error_if_not_zero(re_detail::strcat_s(buf, MAX_PATH, directory_iterator::separator()));
re_detail::overflow_error_if_not_zero(re_detail::strcat_s(buf, MAX_PATH, "*"));
}
directory_iterator dstart(buf);
directory_iterator dend;
@ -365,7 +359,11 @@ void BuildFileList(std::list<std::string>* pl, const char* files, bool recurse)
while(dstart != dend)
{
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
(::sprintf_s)(buf, sizeof(buf), "%s%s%s", dstart.path(), directory_iterator::separator(), ptr);
#else
(std::sprintf)(buf, "%s%s%s", dstart.path(), directory_iterator::separator(), ptr);
#endif
BuildFileList(pl, buf, recurse);
++dstart;
}

View File

@ -23,11 +23,8 @@
#include <stdexcept>
#include <string>
#include <boost/throw_exception.hpp>
#ifdef BOOST_REGEX_V3
#include <boost/regex/v3/fileiter.hpp>
#else
#include <boost/regex/v4/fileiter.hpp>
#endif
#include <boost/regex/v4/regex_workaround.hpp>
#include <boost/regex/pattern_except.hpp>
#include <cstdio>
@ -395,34 +392,24 @@ file_iterator::file_iterator(const char* wild)
BOOST_REGEX_NOEH_ASSERT(_root)
_path = new char[MAX_PATH];
BOOST_REGEX_NOEH_ASSERT(_path)
std::strcpy(_root, wild);
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root, MAX_PATH, wild));
ptr = _root;
while(*ptr)++ptr;
while((ptr > _root) && (*ptr != *_fi_sep) && (*ptr != *_fi_sep_alt))--ptr;
#if 0
*ptr = 0;
std::strcpy(_path, _root);
if(*_path == 0)
std::strcpy(_path, ".");
std::strcat(_path, _fi_sep);
ptr = _path + std::strlen(_path);
#else
if((ptr == _root) && ( (*ptr== *_fi_sep) || (*ptr==*_fi_sep_alt) ) )
{
_root[1]='\0';
std::strcpy(_path, _root);
ptr = _path + std::strlen(_path);
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, _root));
}
else
{
*ptr = 0;
std::strcpy(_path, _root);
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, _root));
if(*_path == 0)
std::strcpy(_path, ".");
std::strcat(_path, _fi_sep);
ptr = _path + std::strlen(_path);
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, "."));
re_detail::overflow_error_if_not_zero(re_detail::strcat_s(_path, MAX_PATH, _fi_sep));
}
#endif
ptr = _path + std::strlen(_path);
ref = new file_iterator_ref();
BOOST_REGEX_NOEH_ASSERT(ref)
@ -436,7 +423,7 @@ file_iterator::file_iterator(const char* wild)
}
else
{
std::strcpy(ptr, ref->_data.cFileName);
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(ptr, (MAX_PATH - (ptr - _path)), ref->_data.cFileName));
if(ref->_data.dwFileAttributes & _fi_dir)
next();
}
@ -463,8 +450,8 @@ file_iterator::file_iterator(const file_iterator& other)
BOOST_REGEX_NOEH_ASSERT(_root)
_path = new char[MAX_PATH];
BOOST_REGEX_NOEH_ASSERT(_path)
std::strcpy(_root, other._root);
std::strcpy(_path, other._path);
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root, MAX_PATH, other._root));
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, other._path));
ptr = _path + (other.ptr - other._path);
ref = other.ref;
#ifndef BOOST_NO_EXCEPTIONS
@ -481,8 +468,8 @@ file_iterator::file_iterator(const file_iterator& other)
file_iterator& file_iterator::operator=(const file_iterator& other)
{
std::strcpy(_root, other._root);
std::strcpy(_path, other._path);
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root, MAX_PATH, other._root));
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, other._path));
ptr = _path + (other.ptr - other._path);
if(--(ref->count) == 0)
{
@ -536,7 +523,7 @@ void file_iterator::next()
ptr = _path;
}
else
std::strcpy(ptr, ref->_data.cFileName);
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(ptr, MAX_PATH - (ptr - _path), ref->_data.cFileName));
}
}
@ -583,34 +570,26 @@ directory_iterator::directory_iterator(const char* wild)
BOOST_REGEX_NOEH_ASSERT(_root)
_path = new char[MAX_PATH];
BOOST_REGEX_NOEH_ASSERT(_path)
std::strcpy(_root, wild);
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root, MAX_PATH, wild));
ptr = _root;
while(*ptr)++ptr;
while((ptr > _root) && (*ptr != *_fi_sep) && (*ptr != *_fi_sep_alt))--ptr;
#if 0
*ptr = 0;
std::strcpy(_path, _root);
if(*_path == 0)
std::strcpy(_path, ".");
std::strcat(_path, _fi_sep);
ptr = _path + std::strlen(_path);
#else
if((ptr == _root) && ( (*ptr== *_fi_sep) || (*ptr==*_fi_sep_alt) ) )
{
_root[1]='\0';
std::strcpy(_path, _root);
ptr = _path + std::strlen(_path);
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, _root));
}
else
{
*ptr = 0;
std::strcpy(_path, _root);
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, _root));
if(*_path == 0)
std::strcpy(_path, ".");
std::strcat(_path, _fi_sep);
ptr = _path + std::strlen(_path);
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, "."));
re_detail::overflow_error_if_not_zero(re_detail::strcat_s(_path, MAX_PATH, _fi_sep));
}
#endif
ptr = _path + std::strlen(_path);
ref = new file_iterator_ref();
BOOST_REGEX_NOEH_ASSERT(ref)
ref->count = 1;
@ -622,7 +601,7 @@ directory_iterator::directory_iterator(const char* wild)
}
else
{
std::strcpy(ptr, ref->_data.cFileName);
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(ptr, MAX_PATH - (ptr - _path), ref->_data.cFileName));
if(((ref->_data.dwFileAttributes & _fi_dir) == 0) || (std::strcmp(ref->_data.cFileName, ".") == 0) || (std::strcmp(ref->_data.cFileName, "..") == 0))
next();
}
@ -661,8 +640,8 @@ directory_iterator::directory_iterator(const directory_iterator& other)
BOOST_REGEX_NOEH_ASSERT(_root)
_path = new char[MAX_PATH];
BOOST_REGEX_NOEH_ASSERT(_path)
std::strcpy(_root, other._root);
std::strcpy(_path, other._path);
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root, MAX_PATH, other._root));
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, other._path));
ptr = _path + (other.ptr - other._path);
ref = other.ref;
#ifndef BOOST_NO_EXCEPTIONS
@ -679,8 +658,8 @@ directory_iterator::directory_iterator(const directory_iterator& other)
directory_iterator& directory_iterator::operator=(const directory_iterator& other)
{
std::strcpy(_root, other._root);
std::strcpy(_path, other._path);
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root, MAX_PATH, other._root));
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, other._path));
ptr = _path + (other.ptr - other._path);
if(--(ref->count) == 0)
{
@ -723,7 +702,7 @@ void directory_iterator::next()
ptr = _path;
}
else
std::strcpy(ptr, ref->_data.cFileName);
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(ptr, MAX_PATH - (ptr - _path), ref->_data.cFileName));
}
}

View File

@ -131,7 +131,7 @@ BOOST_REGEX_DECL regsize_t BOOST_REGEX_CCALL regerrorA(int code, const regex_tA*
{
result = std::strlen(names[code]) + 1;
if(buf_size >= result)
std::strcpy(buf, names[code]);
re_detail::strcpy_s(buf, buf_size, names[code]);
return result;
}
return result;
@ -145,15 +145,23 @@ BOOST_REGEX_DECL regsize_t BOOST_REGEX_CCALL regerrorA(int code, const regex_tA*
{
if(std::strcmp(e->re_endp, names[i]) == 0)
{
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
(::sprintf_s)(localbuf, 5, "%d", i);
#else
(std::sprintf)(localbuf, "%d", i);
#endif
if(std::strlen(localbuf) < buf_size)
std::strcpy(buf, localbuf);
re_detail::strcpy_s(buf, buf_size, localbuf);
return std::strlen(localbuf) + 1;
}
}
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
(::sprintf_s)(localbuf, 5, "%d", 0);
#else
(std::sprintf)(localbuf, "%d", 0);
#endif
if(std::strlen(localbuf) < buf_size)
std::strcpy(buf, localbuf);
re_detail::strcpy_s(buf, buf_size, localbuf);
return std::strlen(localbuf) + 1;
}
if(code <= (int)REG_E_UNKNOWN)
@ -168,7 +176,7 @@ BOOST_REGEX_DECL regsize_t BOOST_REGEX_CCALL regerrorA(int code, const regex_tA*
std::size_t len = p.size();
if(len < buf_size)
{
std::strcpy(buf, p.c_str());
re_detail::strcpy_s(buf, buf_size, p.c_str());
}
return len + 1;
}

View File

@ -231,7 +231,7 @@ BOOST_REGEX_DECL std::string BOOST_REGEX_CALL w32_transform(lcid_type id, const
id, // locale identifier
LCMAP_SORTKEY, // mapping transformation type
p1, // source string
p2 - p1, // number of characters in source string
static_cast<int>(p2 - p1), // number of characters in source string
0, // destination buffer
0 // size of destination buffer
);
@ -242,7 +242,7 @@ BOOST_REGEX_DECL std::string BOOST_REGEX_CALL w32_transform(lcid_type id, const
id, // locale identifier
LCMAP_SORTKEY, // mapping transformation type
p1, // source string
p2 - p1, // number of characters in source string
static_cast<int>(p2 - p1), // number of characters in source string
&*result.begin(), // destination buffer
bytes // size of destination buffer
);
@ -262,7 +262,7 @@ BOOST_REGEX_DECL std::wstring BOOST_REGEX_CALL w32_transform(lcid_type id, const
id, // locale identifier
LCMAP_SORTKEY, // mapping transformation type
p1, // source string
p2 - p1, // number of characters in source string
static_cast<int>(p2 - p1), // number of characters in source string
0, // destination buffer
0 // size of destination buffer
);
@ -273,7 +273,7 @@ BOOST_REGEX_DECL std::wstring BOOST_REGEX_CALL w32_transform(lcid_type id, const
id, // locale identifier
LCMAP_SORTKEY, // mapping transformation type
p1, // source string
p2 - p1, // number of characters in source string
static_cast<int>(p2 - p1), // number of characters in source string
reinterpret_cast<wchar_t*>(&*result.begin()), // destination buffer *of bytes*
bytes // size of destination buffer
);
@ -295,7 +295,7 @@ BOOST_REGEX_DECL std::basic_string<unsigned short> BOOST_REGEX_CALL w32_transfor
id, // locale identifier
LCMAP_SORTKEY, // mapping transformation type
(LPCWSTR)p1, // source string
p2 - p1, // number of characters in source string
static_cast<int>(p2 - p1), // number of characters in source string
0, // destination buffer
0 // size of destination buffer
);
@ -306,7 +306,7 @@ BOOST_REGEX_DECL std::basic_string<unsigned short> BOOST_REGEX_CALL w32_transfor
id, // locale identifier
LCMAP_SORTKEY, // mapping transformation type
(LPCWSTR)p1, // source string
p2 - p1, // number of characters in source string
static_cast<int>(p2 - p1), // number of characters in source string
reinterpret_cast<wchar_t*>(&*result.begin()), // destination buffer *of bytes*
bytes // size of destination buffer
);

View File

@ -139,7 +139,11 @@ BOOST_REGEX_DECL regsize_t BOOST_REGEX_CCALL regerrorW(int code, const regex_tW*
{
result = std::wcslen(wnames[code]) + 1;
if(buf_size >= result)
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
::wcscpy_s(buf, buf_size, wnames[code]);
#else
std::wcscpy(buf, wnames[code]);
#endif
return result;
}
return result;
@ -156,13 +160,21 @@ BOOST_REGEX_DECL regsize_t BOOST_REGEX_CCALL regerrorW(int code, const regex_tW*
{
(std::swprintf)(localbuf, 5, L"%d", i);
if(std::wcslen(localbuf) < buf_size)
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
::wcscpy_s(buf, buf_size, localbuf);
#else
std::wcscpy(buf, localbuf);
#endif
return std::wcslen(localbuf) + 1;
}
}
(std::swprintf)(localbuf, 5, L"%d", 0);
if(std::wcslen(localbuf) < buf_size)
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
::wcscpy_s(buf, buf_size, localbuf);
#else
std::wcscpy(buf, localbuf);
#endif
return std::wcslen(localbuf) + 1;
}
#endif
@ -178,7 +190,7 @@ BOOST_REGEX_DECL regsize_t BOOST_REGEX_CCALL regerrorW(int code, const regex_tW*
std::size_t len = p.size();
if(len < buf_size)
{
std::copy(p.c_str(), p.c_str() + p.size() + 1, buf);
re_detail::copy(p.c_str(), p.c_str() + p.size() + 1, buf);
}
return len + 1;
}

View File

@ -35,7 +35,6 @@ int cpp_main(int /*argc*/, char * /*argv*/[])
test_character_escapes();
test_assertion_escapes();
test_tricky_cases();
test_tricky_cases2();
test_grep();
test_replace();
test_non_greedy_repeats();

View File

@ -38,6 +38,22 @@ void test_backrefs()
TEST_REGEX_SEARCH("(a)\\1bc*d", perl, "aabcccd", match_default, make_array(0, 7, 0, 1, -2, -2));
TEST_REGEX_SEARCH("(a)\\1bc*[ce]d", perl, "aabcccd", match_default, make_array(0, 7, 0, 1, -2, -2));
TEST_REGEX_SEARCH("^(a)\\1b(c)*cd$", perl, "aabcccd", match_default, make_array(0, 7, 0, 1, 4, 5, -2, -2));
TEST_REGEX_SEARCH("(ab*)[ab]*\\1", extended, "ababaaa", match_default, make_array(0, 7, 0, 1, -2, -2));
TEST_REGEX_SEARCH("a\\(b*\\)c\\1d", basic, "abbcbbd", match_default, make_array(0, 7, 1, 3, -2, -2));
TEST_REGEX_SEARCH("a\\(b*\\)c\\1d", basic, "abbcbd", match_default, make_array(-2, -2));
TEST_REGEX_SEARCH("a\\(b*\\)c\\1d", basic, "abbcbbbd", match_default, make_array(-2, -2));
TEST_REGEX_SEARCH("^\\(.\\)\\1", basic, "abc", match_default, make_array(-2, -2));
TEST_REGEX_SEARCH("a\\([bc]\\)\\1d", basic, "abcdabbd", match_default, make_array(4, 8, 5, 6, -2, -2));
// strictly speaking this is at best ambiguous, at worst wrong, this is what most
// re implimentations will match though.
TEST_REGEX_SEARCH("a\\(\\([bc]\\)\\2\\)*d", basic, "abbccd", match_default, make_array(0, 6, 3, 5, 3, 4, -2, -2));
TEST_REGEX_SEARCH("a\\(\\([bc]\\)\\2\\)*d", basic, "abbcbd", match_default, make_array(-2, -2));
TEST_REGEX_SEARCH("a\\(\\(b\\)*\\2\\)*d", basic, "abbbd", match_default, make_array(0, 5, 1, 4, 2, 3, -2, -2));
TEST_REGEX_SEARCH("\\(a\\)\\1bcd", basic, "aabcd", match_default, make_array(0, 5, 0, 1, -2, -2));
TEST_REGEX_SEARCH("\\(a\\)\\1bc*d", basic, "aabcd", match_default, make_array(0, 5, 0, 1, -2, -2));
TEST_REGEX_SEARCH("\\(a\\)\\1bc*d", basic, "aabd", match_default, make_array(0, 4, 0, 1, -2, -2));
TEST_REGEX_SEARCH("\\(a\\)\\1bc*d", basic, "aabcccd", match_default, make_array(0, 7, 0, 1, -2, -2));
TEST_REGEX_SEARCH("\\(a\\)\\1bc*[ce]d", basic, "aabcccd", match_default, make_array(0, 7, 0, 1, -2, -2));
TEST_REGEX_SEARCH("^\\(a\\)\\1b\\(c\\)*cd$", basic, "aabcccd", match_default, make_array(0, 7, 0, 1, 4, 5, -2, -2));
TEST_REGEX_SEARCH("\\(ab*\\)[ab]*\\1", basic, "ababaaa", match_default, make_array(0, 7, 0, 1, -2, -2));
}

View File

@ -12,6 +12,7 @@
#include "test.hpp"
#if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300)\
&& !BOOST_WORKAROUND(BOOST_MSVC, == 1400)\
&& !BOOST_WORKAROUND(__HP_aCC, BOOST_TESTED_AT(55500))\
&& !(defined(__GNUC__) && (__GNUC__ < 3) && !(defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)))

View File

@ -15,6 +15,9 @@
#pragma warning(disable:4127)
#endif
void test_tricky_cases2();
void test_tricky_cases3();
void test_tricky_cases()
{
using namespace boost::regex_constants;
@ -98,6 +101,92 @@ void test_tricky_cases()
TEST_REGEX_SEARCH("a(b|c){2,4}d", perl, "abcbcd", match_default, make_array(0, 6, 4, 5, -2, -2));
TEST_REGEX_SEARCH("a(b|c){2,}d", perl, "abcd", match_default, make_array(0, 4, 2, 3, -2, -2));
TEST_REGEX_SEARCH("a(b|c){2,}d", perl, "abcbd", match_default, make_array(0, 5, 3, 4, -2, -2));
test_tricky_cases2();
test_tricky_cases3();
}
void test_tricky_cases2()
{
using namespace boost::regex_constants;
TEST_REGEX_SEARCH("a(((b)))c", extended, "abc", match_default, make_array(0, 3, 1, 2, 1, 2, 1, 2, -2, -2));
TEST_REGEX_SEARCH("a(b|(c))d", extended, "abd", match_default, make_array(0, 3, 1, 2, -1, -1, -2, -2));
TEST_REGEX_SEARCH("a(b|(c))d", extended, "acd", match_default, make_array(0, 3, 1, 2, 1, 2, -2, -2));
TEST_REGEX_SEARCH("a(b*|c)d", extended, "abbd", match_default, make_array(0, 4, 1, 3, -2, -2));
// just gotta have one DFA-buster, of course
TEST_REGEX_SEARCH("a[ab]{20}", extended, "aaaaabaaaabaaaabaaaab", match_default, make_array(0, 21, -2, -2));
// and an inline expansion in case somebody gets tricky
TEST_REGEX_SEARCH("a[ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab]", extended, "aaaaabaaaabaaaabaaaab", match_default, make_array(0, 21, -2, -2));
// and in case somebody just slips in an NFA...
TEST_REGEX_SEARCH("a[ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab](wee|week)(knights|night)", extended, "aaaaabaaaabaaaabaaaabweeknights", match_default, make_array(0, 31, 21, 24, 24, 31, -2, -2));
// one really big one
TEST_REGEX_SEARCH("1234567890123456789012345678901234567890123456789012345678901234567890", extended, "a1234567890123456789012345678901234567890123456789012345678901234567890b", match_default, make_array(1, 71, -2, -2));
// fish for problems as brackets go past 8
TEST_REGEX_SEARCH("[ab][cd][ef][gh][ij][kl][mn]", extended, "xacegikmoq", match_default, make_array(1, 8, -2, -2));
TEST_REGEX_SEARCH("[ab][cd][ef][gh][ij][kl][mn][op]", extended, "xacegikmoq", match_default, make_array(1, 9, -2, -2));
TEST_REGEX_SEARCH("[ab][cd][ef][gh][ij][kl][mn][op][qr]", extended, "xacegikmoqy", match_default, make_array(1, 10, -2, -2));
TEST_REGEX_SEARCH("[ab][cd][ef][gh][ij][kl][mn][op][q]", extended, "xacegikmoqy", match_default, make_array(1, 10, -2, -2));
// and as parenthesis go past 9:
TEST_REGEX_SEARCH("(a)(b)(c)(d)(e)(f)(g)(h)", extended, "zabcdefghi", match_default, make_array(1, 9, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, -2, -2));
TEST_REGEX_SEARCH("(a)(b)(c)(d)(e)(f)(g)(h)(i)", extended, "zabcdefghij", match_default, make_array(1, 10, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, -2, -2));
TEST_REGEX_SEARCH("(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)", extended, "zabcdefghijk", match_default, make_array(1, 11, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, -2, -2));
TEST_REGEX_SEARCH("(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)", extended, "zabcdefghijkl", match_default, make_array(1, 12, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, -2, -2));
TEST_REGEX_SEARCH("(a)d|(b)c", extended, "abc", match_default, make_array(1, 3, -1, -1, 1, 2, -2, -2));
TEST_REGEX_SEARCH("_+((www)|(ftp)|(mailto)):_*", extended, "_wwwnocolon _mailto:", match_default, make_array(12, 20, 13, 19, -1, -1, -1, -1, 13, 19, -2, -2));
// subtleties of matching
TEST_REGEX_SEARCH("a\\(b\\)\\?c\\1d", basic|bk_plus_qm, "acd", match_default, make_array(0, 3, -1, -1, -2, -2));
TEST_REGEX_SEARCH("a(b?c)+d", extended, "accd", match_default, make_array(0, 4, 2, 3, -2, -2));
TEST_REGEX_SEARCH("(wee|week)(knights|night)", extended, "weeknights", match_default, make_array(0, 10, 0, 3, 3, 10, -2, -2));
TEST_REGEX_SEARCH(".*", extended, "abc", match_default, make_array(0, 3, -2, 3, 3, -2, -2));
TEST_REGEX_SEARCH("a(b|(c))d", extended, "abd", match_default, make_array(0, 3, 1, 2, -1, -1, -2, -2));
TEST_REGEX_SEARCH("a(b|(c))d", extended, "acd", match_default, make_array(0, 3, 1, 2, 1, 2, -2, -2));
TEST_REGEX_SEARCH("a(b*|c|e)d", extended, "abbd", match_default, make_array(0, 4, 1, 3, -2, -2));
TEST_REGEX_SEARCH("a(b*|c|e)d", extended, "acd", match_default, make_array(0, 3, 1, 2, -2, -2));
TEST_REGEX_SEARCH("a(b*|c|e)d", extended, "ad", match_default, make_array(0, 2, 1, 1, -2, -2));
TEST_REGEX_SEARCH("a(b?)c", extended, "abc", match_default, make_array(0, 3, 1, 2, -2, -2));
TEST_REGEX_SEARCH("a(b?)c", extended, "ac", match_default, make_array(0, 2, 1, 1, -2, -2));
TEST_REGEX_SEARCH("a(b+)c", extended, "abc", match_default, make_array(0, 3, 1, 2, -2, -2));
TEST_REGEX_SEARCH("a(b+)c", extended, "abbbc", match_default, make_array(0, 5, 1, 4, -2, -2));
TEST_REGEX_SEARCH("a(b*)c", extended, "ac", match_default, make_array(0, 2, 1, 1, -2, -2));
TEST_REGEX_SEARCH("(a|ab)(bc([de]+)f|cde)", extended, "abcdef", match_default, make_array(0, 6, 0, 1, 1, 6, 3, 5, -2, -2));
TEST_REGEX_SEARCH("a([bc]?)c", extended, "abc", match_default, make_array(0, 3, 1, 2, -2, -2));
TEST_REGEX_SEARCH("a([bc]?)c", extended, "ac", match_default, make_array(0, 2, 1, 1, -2, -2));
TEST_REGEX_SEARCH("a([bc]+)c", extended, "abc", match_default, make_array(0, 3, 1, 2, -2, -2));
TEST_REGEX_SEARCH("a([bc]+)c", extended, "abcc", match_default, make_array(0, 4, 1, 3, -2, -2));
TEST_REGEX_SEARCH("a([bc]+)bc", extended, "abcbc", match_default, make_array(0, 5, 1, 3, -2, -2));
TEST_REGEX_SEARCH("a(bb+|b)b", extended, "abb", match_default, make_array(0, 3, 1, 2, -2, -2));
TEST_REGEX_SEARCH("a(bbb+|bb+|b)b", extended, "abb", match_default, make_array(0, 3, 1, 2, -2, -2));
TEST_REGEX_SEARCH("a(bbb+|bb+|b)b", extended, "abbb", match_default, make_array(0, 4, 1, 3, -2, -2));
TEST_REGEX_SEARCH("a(bbb+|bb+|b)bb", extended, "abbb", match_default, make_array(0, 4, 1, 2, -2, -2));
TEST_REGEX_SEARCH("(.*).*", extended, "abcdef", match_default, make_array(0, 6, 0, 6, -2, 6, 6, 6, 6, -2, -2));
TEST_REGEX_SEARCH("(a*)*", extended, "bc", match_default, make_array(0, 0, 0, 0, -2, 1, 1, 1, 1, -2, 2, 2, 2, 2, -2, -2));
TEST_REGEX_SEARCH("xyx*xz", extended, "xyxxxxyxxxz", match_default, make_array(5, 11, -2, -2));
// do we get the right subexpression when it is used more than once?
TEST_REGEX_SEARCH("a(b|c)*d", extended, "ad", match_default, make_array(0, 2, -1, -1, -2, -2));
TEST_REGEX_SEARCH("a(b|c)*d", extended, "abcd", match_default, make_array(0, 4, 2, 3, -2, -2));
TEST_REGEX_SEARCH("a(b|c)+d", extended, "abd", match_default, make_array(0, 3, 1, 2, -2, -2));
TEST_REGEX_SEARCH("a(b|c)+d", extended, "abcd", match_default, make_array(0, 4, 2, 3, -2, -2));
TEST_REGEX_SEARCH("a(b|c?)+d", extended, "ad", match_default, make_array(0, 2, 1, 1, -2, -2));
TEST_REGEX_SEARCH("a(b|c){0,0}d", extended, "ad", match_default, make_array(0, 2, -1, -1, -2, -2));
TEST_REGEX_SEARCH("a(b|c){0,1}d", extended, "ad", match_default, make_array(0, 2, -1, -1, -2, -2));
TEST_REGEX_SEARCH("a(b|c){0,1}d", extended, "abd", match_default, make_array(0, 3, 1, 2, -2, -2));
TEST_REGEX_SEARCH("a(b|c){0,2}d", extended, "ad", match_default, make_array(0, 2, -1, -1, -2, -2));
TEST_REGEX_SEARCH("a(b|c){0,2}d", extended, "abcd", match_default, make_array(0, 4, 2, 3, -2, -2));
TEST_REGEX_SEARCH("a(b|c){0,}d", extended, "ad", match_default, make_array(0, 2, -1, -1, -2, -2));
TEST_REGEX_SEARCH("a(b|c){0,}d", extended, "abcd", match_default, make_array(0, 4, 2, 3, -2, -2));
TEST_REGEX_SEARCH("a(b|c){1,1}d", extended, "abd", match_default, make_array(0, 3, 1, 2, -2, -2));
TEST_REGEX_SEARCH("a(b|c){1,2}d", extended, "abd", match_default, make_array(0, 3, 1, 2, -2, -2));
TEST_REGEX_SEARCH("a(b|c){1,2}d", extended, "abcd", match_default, make_array(0, 4, 2, 3, -2, -2));
TEST_REGEX_SEARCH("a(b|c){1,}d", extended, "abd", match_default, make_array(0, 3, 1, 2, -2, -2));
TEST_REGEX_SEARCH("a(b|c){1,}d", extended, "abcd", match_default, make_array(0, 4, 2, 3, -2, -2));
TEST_REGEX_SEARCH("a(b|c){2,2}d", extended, "acbd", match_default, make_array(0, 4, 2, 3, -2, -2));
TEST_REGEX_SEARCH("a(b|c){2,2}d", extended, "abcd", match_default, make_array(0, 4, 2, 3, -2, -2));
TEST_REGEX_SEARCH("a(b|c){2,4}d", extended, "abcd", match_default, make_array(0, 4, 2, 3, -2, -2));
TEST_REGEX_SEARCH("a(b|c){2,4}d", extended, "abcbd", match_default, make_array(0, 5, 3, 4, -2, -2));
TEST_REGEX_SEARCH("a(b|c){2,4}d", extended, "abcbcd", match_default, make_array(0, 6, 4, 5, -2, -2));
TEST_REGEX_SEARCH("a(b|c){2,}d", extended, "abcd", match_default, make_array(0, 4, 2, 3, -2, -2));
TEST_REGEX_SEARCH("a(b|c){2,}d", extended, "abcbd", match_default, make_array(0, 5, 3, 4, -2, -2));
// perl only:
TEST_REGEX_SEARCH("a(b|c?)+d", perl, "abcd", match_default, make_array(0, 4, 3, 3, -2, -2));
TEST_REGEX_SEARCH("a(b+|((c)*))+d", perl, "abd", match_default, make_array(0, 3, 2, 2, 2, 2, -1, -1, -2, -2));
@ -123,12 +212,32 @@ void test_tricky_cases()
// preprossor directives:
TEST_REGEX_SEARCH("^[[:blank:]]*#([^\\n]*\\\\[[:space:]]+)*[^\\n]*", perl, "#define some_symbol", match_default, make_array(0, 19, -1, -1, -2, -2));
TEST_REGEX_SEARCH("^[[:blank:]]*#([^\\n]*\\\\[[:space:]]+)*[^\\n]*", perl, "#define some_symbol(x) #x", match_default, make_array(0, 25, -1, -1, -2, -2));
// try to match C++ syntax elements:
// line comment:
TEST_REGEX_SEARCH("//[^\\n]*", extended&~no_escape_in_lists, "++i //here is a line comment\n", match_default, make_array(4, 28, -2, -2));
// block comment:
TEST_REGEX_SEARCH("/\\*([^*]|\\*+[^*/])*\\*+/", extended&~no_escape_in_lists, "/* here is a block comment */", match_default, make_array(0, 29, 26, 27, -2, -2));
TEST_REGEX_SEARCH("/\\*([^*]|\\*+[^*/])*\\*+/", extended&~no_escape_in_lists, "/**/", match_default, make_array(0, 4, -1, -1, -2, -2));
TEST_REGEX_SEARCH("/\\*([^*]|\\*+[^*/])*\\*+/", extended&~no_escape_in_lists, "/***/", match_default, make_array(0, 5, -1, -1, -2, -2));
TEST_REGEX_SEARCH("/\\*([^*]|\\*+[^*/])*\\*+/", extended&~no_escape_in_lists, "/****/", match_default, make_array(0, 6, -1, -1, -2, -2));
TEST_REGEX_SEARCH("/\\*([^*]|\\*+[^*/])*\\*+/", extended&~no_escape_in_lists, "/*****/", match_default, make_array(0, 7, -1, -1, -2, -2));
TEST_REGEX_SEARCH("/\\*([^*]|\\*+[^*/])*\\*+/", extended&~no_escape_in_lists, "/*****/*/", match_default, make_array(0, 7, -1, -1, -2, -2));
// preprossor directives:
TEST_REGEX_SEARCH("^[[:blank:]]*#([^\\n]*\\\\[[:space:]]+)*[^\\n]*", extended&~no_escape_in_lists, "#define some_symbol", match_default, make_array(0, 19, -1, -1, -2, -2));
TEST_REGEX_SEARCH("^[[:blank:]]*#([^\\n]*\\\\[[:space:]]+)*[^\\n]*", extended&~no_escape_in_lists, "#define some_symbol(x) #x", match_default, make_array(0, 25, -1, -1, -2, -2));
// perl only:
TEST_REGEX_SEARCH("^[[:blank:]]*#([^\\n]*\\\\[[:space:]]+)*[^\\n]*", perl, "#define some_symbol(x) \\ \r\n foo();\\\r\n printf(#x);", match_default, make_array(0, 53, 30, 42, -2, -2));
// literals:
// POSIX leftmost longest checks:
TEST_REGEX_SEARCH("(aaa)|(\\w+)", extended&~no_escape_in_lists, "a", match_default, make_array(0, 1, -1, -1, 0, 1, -2, -2));
TEST_REGEX_SEARCH("(aaa)|(\\w+)", extended&~no_escape_in_lists, "aa", match_default, make_array(0, 2, -1, -1, 0, 2, -2, -2));
TEST_REGEX_SEARCH("(aaa)|(\\w+)", extended&~no_escape_in_lists, "aaa", match_default, make_array(0, 3, 0, 3, -1, -1, -2, -2));
TEST_REGEX_SEARCH("(aaa)|(\\w+)", extended&~no_escape_in_lists, "aaaa", match_default, make_array(0, 4, -1, -1, 0, 4, -2, -2));
TEST_REGEX_SEARCH("($)|(\\>)", extended&~no_escape_in_lists, "aaaa", match_default, make_array(4, 4, 4, 4, -1, -1, -2, -2));
TEST_REGEX_SEARCH("($)|(\\>)", extended&~no_escape_in_lists, "aaaa", match_default|match_not_eol, make_array(4, 4, -1, -1, 4, 4, -2, -2));
TEST_REGEX_SEARCH("(aaa)(ab)*", extended, "aaaabab", match_default, make_array(0, 7, 0, 3, 5, 7, -2, -2));
}
void test_tricky_cases2()
void test_tricky_cases3()
{
using namespace boost::regex_constants;
TEST_REGEX_SEARCH("((0x[[:xdigit:]]+)|([[:digit:]]+))u?((int(8|16|32|64))|L)?", perl, "0xFF", match_default, make_array(0, 4, 0, 4, 0, 4, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2));