1 /*
2  *
3  * Copyright (c) 2002
4  * John Maddock
5  *
6  * Use, modification and distribution are subject to the
7  * Boost Software License, Version 1.0. (See accompanying file
8  * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9  *
10  */
11 
12  /*
13   *   LOCATION:    see http://www.boost.org for most recent version.
14   *   FILE         perl_matcher_common.cpp
15   *   VERSION      see <boost/version.hpp>
16   *   DESCRIPTION: Definitions of perl_matcher member functions that are
17   *                common to both the recursive and non-recursive versions.
18   */
19 
20 #ifndef BOOST_REGEX_V4_PERL_MATCHER_COMMON_HPP
21 #define BOOST_REGEX_V4_PERL_MATCHER_COMMON_HPP
22 
23 #ifdef BOOST_MSVC
24 #pragma warning(push)
25 #pragma warning(disable: 4103)
26 #endif
27 #ifdef BOOST_HAS_ABI_HEADERS
28 #  include BOOST_ABI_PREFIX
29 #endif
30 #ifdef BOOST_MSVC
31 #pragma warning(pop)
32 #endif
33 
34 #ifdef __BORLANDC__
35 #  pragma option push -w-8008 -w-8066
36 #endif
37 #ifdef BOOST_MSVC
38 #  pragma warning(push)
39 #  pragma warning(disable: 4800)
40 #endif
41 
42 namespace boost{
43 namespace re_detail{
44 
45 template <class BidiIterator, class Allocator, class traits>
construct_init(const basic_regex<char_type,traits> & e,match_flag_type f)46 void perl_matcher<BidiIterator, Allocator, traits>::construct_init(const basic_regex<char_type, traits>& e, match_flag_type f)
47 {
48    typedef typename regex_iterator_traits<BidiIterator>::iterator_category category;
49    typedef typename basic_regex<char_type, traits>::flag_type expression_flag_type;
50 
51    if(e.empty())
52    {
53       // precondition failure: e is not a valid regex.
54       std::invalid_argument ex("Invalid regular expression object");
55       boost::throw_exception(ex);
56    }
57    pstate = 0;
58    m_match_flags = f;
59    estimate_max_state_count(static_cast<category*>(0));
60    expression_flag_type re_f = re.flags();
61    icase = re_f & regex_constants::icase;
62    if(!(m_match_flags & (match_perl|match_posix)))
63    {
64       if((re_f & (regbase::main_option_type|regbase::no_perl_ex)) == 0)
65          m_match_flags |= match_perl;
66       else if((re_f & (regbase::main_option_type|regbase::emacs_ex)) == (regbase::basic_syntax_group|regbase::emacs_ex))
67          m_match_flags |= match_perl;
68       else
69          m_match_flags |= match_posix;
70    }
71    if(m_match_flags & match_posix)
72    {
73       m_temp_match.reset(new match_results<BidiIterator, Allocator>());
74       m_presult = m_temp_match.get();
75    }
76    else
77       m_presult = &m_result;
78 #ifdef BOOST_REGEX_NON_RECURSIVE
79    m_stack_base = 0;
80    m_backup_state = 0;
81 #endif
82    // find the value to use for matching word boundaries:
83    m_word_mask = re.get_data().m_word_mask;
84    // find bitmask to use for matching '.':
85    match_any_mask = static_cast<unsigned char>((f & match_not_dot_newline) ? re_detail::test_not_newline : re_detail::test_newline);
86 }
87 
88 template <class BidiIterator, class Allocator, class traits>
estimate_max_state_count(std::random_access_iterator_tag *)89 void perl_matcher<BidiIterator, Allocator, traits>::estimate_max_state_count(std::random_access_iterator_tag*)
90 {
91    //
92    // How many states should we allow our machine to visit before giving up?
93    // This is a heuristic: it takes the greater of O(N^2) and O(NS^2)
94    // where N is the length of the string, and S is the number of states
95    // in the machine.  It's tempting to up this to O(N^2S) or even O(N^2S^2)
96    // but these take unreasonably amounts of time to bale out in pathological
97    // cases.
98    //
99    // Calculate NS^2 first:
100    //
101    static const std::ptrdiff_t k = 100000;
102    std::ptrdiff_t dist = boost::re_detail::distance(base, last);
103    if(dist == 0)
104       dist = 1;
105    std::ptrdiff_t states = re.size();
106    if(states == 0)
107       states = 1;
108    states *= states;
109    if((std::numeric_limits<std::ptrdiff_t>::max)() / dist < states)
110    {
111       max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits<std::ptrdiff_t>::max)() - 2);
112       return;
113    }
114    states *= dist;
115    if((std::numeric_limits<std::ptrdiff_t>::max)() - k < states)
116    {
117       max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits<std::ptrdiff_t>::max)() - 2);
118       return;
119    }
120    states += k;
121 
122    max_state_count = states;
123 
124    //
125    // Now calculate N^2:
126    //
127    states = dist;
128    if((std::numeric_limits<std::ptrdiff_t>::max)() / dist < states)
129    {
130       max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits<std::ptrdiff_t>::max)() - 2);
131       return;
132    }
133    states *= dist;
134    if((std::numeric_limits<std::ptrdiff_t>::max)() - k < states)
135    {
136       max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits<std::ptrdiff_t>::max)() - 2);
137       return;
138    }
139    states += k;
140    //
141    // N^2 can be a very large number indeed, to prevent things getting out
142    // of control, cap the max states:
143    //
144    if(states > BOOST_REGEX_MAX_STATE_COUNT)
145       states = BOOST_REGEX_MAX_STATE_COUNT;
146    //
147    // If (the possibly capped) N^2 is larger than our first estimate,
148    // use this instead:
149    //
150    if(states > max_state_count)
151       max_state_count = states;
152 }
153 
154 template <class BidiIterator, class Allocator, class traits>
estimate_max_state_count(void *)155 inline void perl_matcher<BidiIterator, Allocator, traits>::estimate_max_state_count(void*)
156 {
157    // we don't know how long the sequence is:
158    max_state_count = BOOST_REGEX_MAX_STATE_COUNT;
159 }
160 
161 #ifdef BOOST_REGEX_HAS_MS_STACK_GUARD
162 template <class BidiIterator, class Allocator, class traits>
protected_call(protected_proc_type proc)163 inline bool perl_matcher<BidiIterator, Allocator, traits>::protected_call(
164    protected_proc_type proc)
165 {
166    ::boost::re_detail::concrete_protected_call
167       <perl_matcher<BidiIterator, Allocator, traits> >
168       obj(this, proc);
169    return obj.execute();
170 
171 }
172 #endif
173 
174 template <class BidiIterator, class Allocator, class traits>
match()175 inline bool perl_matcher<BidiIterator, Allocator, traits>::match()
176 {
177 #ifdef BOOST_REGEX_HAS_MS_STACK_GUARD
178    return protected_call(&perl_matcher<BidiIterator, Allocator, traits>::match_imp);
179 #else
180    return match_imp();
181 #endif
182 }
183 
184 template <class BidiIterator, class Allocator, class traits>
match_imp()185 bool perl_matcher<BidiIterator, Allocator, traits>::match_imp()
186 {
187    // initialise our stack if we are non-recursive:
188 #ifdef BOOST_REGEX_NON_RECURSIVE
189    save_state_init init(&m_stack_base, &m_backup_state);
190    used_block_count = BOOST_REGEX_MAX_BLOCKS;
191 #if !defined(BOOST_NO_EXCEPTIONS)
192    try{
193 #endif
194 #endif
195 
196    // reset our state machine:
197    position = base;
198    search_base = base;
199    state_count = 0;
200    m_match_flags |= regex_constants::match_all;
201    m_presult->set_size((m_match_flags & match_nosubs) ? 1 : re.mark_count(), search_base, last);
202    m_presult->set_base(base);
203    m_presult->set_named_subs(this->re.get_named_subs());
204    if(m_match_flags & match_posix)
205       m_result = *m_presult;
206    verify_options(re.flags(), m_match_flags);
207    if(0 == match_prefix())
208       return false;
209    return (m_result[0].second == last) && (m_result[0].first == base);
210 
211 #if defined(BOOST_REGEX_NON_RECURSIVE) && !defined(BOOST_NO_EXCEPTIONS)
212    }
213    catch(...)
214    {
215       // unwind all pushed states, apart from anything else this
216       // ensures that all the states are correctly destructed
217       // not just the memory freed.
218       while(unwind(true)){}
219       throw;
220    }
221 #endif
222 }
223 
224 template <class BidiIterator, class Allocator, class traits>
find()225 inline bool perl_matcher<BidiIterator, Allocator, traits>::find()
226 {
227 #ifdef BOOST_REGEX_HAS_MS_STACK_GUARD
228    return protected_call(&perl_matcher<BidiIterator, Allocator, traits>::find_imp);
229 #else
230    return find_imp();
231 #endif
232 }
233 
234 template <class BidiIterator, class Allocator, class traits>
find_imp()235 bool perl_matcher<BidiIterator, Allocator, traits>::find_imp()
236 {
237    static matcher_proc_type const s_find_vtable[7] =
238    {
239       &perl_matcher<BidiIterator, Allocator, traits>::find_restart_any,
240       &perl_matcher<BidiIterator, Allocator, traits>::find_restart_word,
241       &perl_matcher<BidiIterator, Allocator, traits>::find_restart_line,
242       &perl_matcher<BidiIterator, Allocator, traits>::find_restart_buf,
243       &perl_matcher<BidiIterator, Allocator, traits>::match_prefix,
244       &perl_matcher<BidiIterator, Allocator, traits>::find_restart_lit,
245       &perl_matcher<BidiIterator, Allocator, traits>::find_restart_lit,
246    };
247 
248    // initialise our stack if we are non-recursive:
249 #ifdef BOOST_REGEX_NON_RECURSIVE
250    save_state_init init(&m_stack_base, &m_backup_state);
251    used_block_count = BOOST_REGEX_MAX_BLOCKS;
252 #if !defined(BOOST_NO_EXCEPTIONS)
253    try{
254 #endif
255 #endif
256 
257    state_count = 0;
258    if((m_match_flags & regex_constants::match_init) == 0)
259    {
260       // reset our state machine:
261       search_base = position = base;
262       pstate = re.get_first_state();
263       m_presult->set_size((m_match_flags & match_nosubs) ? 1 : re.mark_count(), base, last);
264       m_presult->set_base(base);
265       m_presult->set_named_subs(this->re.get_named_subs());
266       m_match_flags |= regex_constants::match_init;
267    }
268    else
269    {
270       // start again:
271       search_base = position = m_result[0].second;
272       // If last match was null and match_not_null was not set then increment
273       // our start position, otherwise we go into an infinite loop:
274       if(((m_match_flags & match_not_null) == 0) && (m_result.length() == 0))
275       {
276          if(position == last)
277             return false;
278          else
279             ++position;
280       }
281       // reset $` start:
282       m_presult->set_size((m_match_flags & match_nosubs) ? 1 : re.mark_count(), search_base, last);
283       //if((base != search_base) && (base == backstop))
284       //   m_match_flags |= match_prev_avail;
285    }
286    if(m_match_flags & match_posix)
287    {
288       m_result.set_size(re.mark_count(), base, last);
289       m_result.set_base(base);
290    }
291 
292    verify_options(re.flags(), m_match_flags);
293    // find out what kind of expression we have:
294    unsigned type = (m_match_flags & match_continuous) ?
295       static_cast<unsigned int>(regbase::restart_continue)
296          : static_cast<unsigned int>(re.get_restart_type());
297 
298    // call the appropriate search routine:
299    matcher_proc_type proc = s_find_vtable[type];
300    return (this->*proc)();
301 
302 #if defined(BOOST_REGEX_NON_RECURSIVE) && !defined(BOOST_NO_EXCEPTIONS)
303    }
304    catch(...)
305    {
306       // unwind all pushed states, apart from anything else this
307       // ensures that all the states are correctly destructed
308       // not just the memory freed.
309       while(unwind(true)){}
310       throw;
311    }
312 #endif
313 }
314 
315 template <class BidiIterator, class Allocator, class traits>
match_prefix()316 bool perl_matcher<BidiIterator, Allocator, traits>::match_prefix()
317 {
318    m_has_partial_match = false;
319    m_has_found_match = false;
320    pstate = re.get_first_state();
321    m_presult->set_first(position);
322    restart = position;
323    match_all_states();
324    if(!m_has_found_match && m_has_partial_match && (m_match_flags & match_partial))
325    {
326       m_has_found_match = true;
327       m_presult->set_second(last, 0, false);
328       position = last;
329    }
330 #ifdef BOOST_REGEX_MATCH_EXTRA
331    if(m_has_found_match && (match_extra & m_match_flags))
332    {
333       //
334       // we have a match, reverse the capture information:
335       //
336       for(unsigned i = 0; i < m_presult->size(); ++i)
337       {
338          typename sub_match<BidiIterator>::capture_sequence_type & seq = ((*m_presult)[i]).get_captures();
339          std::reverse(seq.begin(), seq.end());
340       }
341    }
342 #endif
343    if(!m_has_found_match)
344       position = restart; // reset search postion
345    return m_has_found_match;
346 }
347 
348 template <class BidiIterator, class Allocator, class traits>
match_literal()349 bool perl_matcher<BidiIterator, Allocator, traits>::match_literal()
350 {
351    unsigned int len = static_cast<const re_literal*>(pstate)->length;
352    const char_type* what = reinterpret_cast<const char_type*>(static_cast<const re_literal*>(pstate) + 1);
353    //
354    // compare string with what we stored in
355    // our records:
356    for(unsigned int i = 0; i < len; ++i, ++position)
357    {
358       if((position == last) || (traits_inst.translate(*position, icase) != what[i]))
359          return false;
360    }
361    pstate = pstate->next.p;
362    return true;
363 }
364 
365 template <class BidiIterator, class Allocator, class traits>
match_start_line()366 bool perl_matcher<BidiIterator, Allocator, traits>::match_start_line()
367 {
368    if(position == backstop)
369    {
370       if((m_match_flags & match_prev_avail) == 0)
371       {
372          if((m_match_flags & match_not_bol) == 0)
373          {
374             pstate = pstate->next.p;
375             return true;
376          }
377          return false;
378       }
379    }
380    else if(m_match_flags & match_single_line)
381       return false;
382 
383    // check the previous value character:
384    BidiIterator t(position);
385    --t;
386    if(position != last)
387    {
388       if(is_separator(*t) && !((*t == static_cast<char_type>('\r')) && (*position == static_cast<char_type>('\n'))) )
389       {
390          pstate = pstate->next.p;
391          return true;
392       }
393    }
394    else if(is_separator(*t))
395    {
396       pstate = pstate->next.p;
397       return true;
398    }
399    return false;
400 }
401 
402 template <class BidiIterator, class Allocator, class traits>
match_end_line()403 bool perl_matcher<BidiIterator, Allocator, traits>::match_end_line()
404 {
405    if(position != last)
406    {
407       if(m_match_flags & match_single_line)
408          return false;
409       // we're not yet at the end so *first is always valid:
410       if(is_separator(*position))
411       {
412          if((position != backstop) || (m_match_flags & match_prev_avail))
413          {
414             // check that we're not in the middle of \r\n sequence
415             BidiIterator t(position);
416             --t;
417             if((*t == static_cast<char_type>('\r')) && (*position == static_cast<char_type>('\n')))
418             {
419                return false;
420             }
421          }
422          pstate = pstate->next.p;
423          return true;
424       }
425    }
426    else if((m_match_flags & match_not_eol) == 0)
427    {
428       pstate = pstate->next.p;
429       return true;
430    }
431    return false;
432 }
433 
434 template <class BidiIterator, class Allocator, class traits>
match_wild()435 bool perl_matcher<BidiIterator, Allocator, traits>::match_wild()
436 {
437    if(position == last)
438       return false;
439    if(is_separator(*position) && ((match_any_mask & static_cast<const re_dot*>(pstate)->mask) == 0))
440       return false;
441    if((*position == char_type(0)) && (m_match_flags & match_not_dot_null))
442       return false;
443    pstate = pstate->next.p;
444    ++position;
445    return true;
446 }
447 
448 template <class BidiIterator, class Allocator, class traits>
match_word_boundary()449 bool perl_matcher<BidiIterator, Allocator, traits>::match_word_boundary()
450 {
451    bool b; // indcates whether next character is a word character
452    if(position != last)
453    {
454       // prev and this character must be opposites:
455    #if defined(BOOST_REGEX_USE_C_LOCALE) && defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ < 95)
456       b = traits::isctype(*position, m_word_mask);
457    #else
458       b = traits_inst.isctype(*position, m_word_mask);
459    #endif
460    }
461    else
462    {
463       b = (m_match_flags & match_not_eow) ? true : false;
464    }
465    if((position == backstop) && ((m_match_flags & match_prev_avail) == 0))
466    {
467       if(m_match_flags & match_not_bow)
468          b ^= true;
469       else
470          b ^= false;
471    }
472    else
473    {
474       --position;
475       b ^= traits_inst.isctype(*position, m_word_mask);
476       ++position;
477    }
478    if(b)
479    {
480       pstate = pstate->next.p;
481       return true;
482    }
483    return false; // no match if we get to here...
484 }
485 
486 template <class BidiIterator, class Allocator, class traits>
match_within_word()487 bool perl_matcher<BidiIterator, Allocator, traits>::match_within_word()
488 {
489    if(position == last)
490       return false;
491    // both prev and this character must be m_word_mask:
492    bool prev = traits_inst.isctype(*position, m_word_mask);
493    {
494       bool b;
495       if((position == backstop) && ((m_match_flags & match_prev_avail) == 0))
496          return false;
497       else
498       {
499          --position;
500          b = traits_inst.isctype(*position, m_word_mask);
501          ++position;
502       }
503       if(b == prev)
504       {
505          pstate = pstate->next.p;
506          return true;
507       }
508    }
509    return false;
510 }
511 
512 template <class BidiIterator, class Allocator, class traits>
match_word_start()513 bool perl_matcher<BidiIterator, Allocator, traits>::match_word_start()
514 {
515    if(position == last)
516       return false; // can't be starting a word if we're already at the end of input
517    if(!traits_inst.isctype(*position, m_word_mask))
518       return false; // next character isn't a word character
519    if((position == backstop) && ((m_match_flags & match_prev_avail) == 0))
520    {
521       if(m_match_flags & match_not_bow)
522          return false; // no previous input
523    }
524    else
525    {
526       // otherwise inside buffer:
527       BidiIterator t(position);
528       --t;
529       if(traits_inst.isctype(*t, m_word_mask))
530          return false; // previous character not non-word
531    }
532    // OK we have a match:
533    pstate = pstate->next.p;
534    return true;
535 }
536 
537 template <class BidiIterator, class Allocator, class traits>
match_word_end()538 bool perl_matcher<BidiIterator, Allocator, traits>::match_word_end()
539 {
540    if((position == backstop) && ((m_match_flags & match_prev_avail) == 0))
541       return false;  // start of buffer can't be end of word
542    BidiIterator t(position);
543    --t;
544    if(traits_inst.isctype(*t, m_word_mask) == false)
545       return false;  // previous character wasn't a word character
546 
547    if(position == last)
548    {
549       if(m_match_flags & match_not_eow)
550          return false; // end of buffer but not end of word
551    }
552    else
553    {
554       // otherwise inside buffer:
555       if(traits_inst.isctype(*position, m_word_mask))
556          return false; // next character is a word character
557    }
558    pstate = pstate->next.p;
559    return true;      // if we fall through to here then we've succeeded
560 }
561 
562 template <class BidiIterator, class Allocator, class traits>
match_buffer_start()563 bool perl_matcher<BidiIterator, Allocator, traits>::match_buffer_start()
564 {
565    if((position != backstop) || (m_match_flags & match_not_bob))
566       return false;
567    // OK match:
568    pstate = pstate->next.p;
569    return true;
570 }
571 
572 template <class BidiIterator, class Allocator, class traits>
match_buffer_end()573 bool perl_matcher<BidiIterator, Allocator, traits>::match_buffer_end()
574 {
575    if((position != last) || (m_match_flags & match_not_eob))
576       return false;
577    // OK match:
578    pstate = pstate->next.p;
579    return true;
580 }
581 
582 template <class BidiIterator, class Allocator, class traits>
match_backref()583 bool perl_matcher<BidiIterator, Allocator, traits>::match_backref()
584 {
585    //
586    // Compare with what we previously matched.
587    // Note that this succeeds if the backref did not partisipate
588    // in the match, this is in line with ECMAScript, but not Perl
589    // or PCRE.
590    //
591    int index = static_cast<const re_brace*>(pstate)->index;
592    if(index >= 10000)
593    {
594       named_subexpressions::range_type r = re.get_data().equal_range(index);
595       BOOST_ASSERT(r.first != r.second);
596       do
597       {
598          index = r.first->index;
599          ++r.first;
600       }while((r.first != r.second) && ((*m_presult)[index].matched != true));
601    }
602 
603    if((m_match_flags & match_perl) && !(*m_presult)[index].matched)
604       return false;
605 
606    BidiIterator i = (*m_presult)[index].first;
607    BidiIterator j = (*m_presult)[index].second;
608    while(i != j)
609    {
610       if((position == last) || (traits_inst.translate(*position, icase) != traits_inst.translate(*i, icase)))
611          return false;
612       ++i;
613       ++position;
614    }
615    pstate = pstate->next.p;
616    return true;
617 }
618 
619 template <class BidiIterator, class Allocator, class traits>
match_long_set()620 bool perl_matcher<BidiIterator, Allocator, traits>::match_long_set()
621 {
622    typedef typename traits::char_class_type char_class_type;
623    // let the traits class do the work:
624    if(position == last)
625       return false;
626    BidiIterator t = re_is_set_member(position, last, static_cast<const re_set_long<char_class_type>*>(pstate), re.get_data(), icase);
627    if(t != position)
628    {
629       pstate = pstate->next.p;
630       position = t;
631       return true;
632    }
633    return false;
634 }
635 
636 template <class BidiIterator, class Allocator, class traits>
match_set()637 bool perl_matcher<BidiIterator, Allocator, traits>::match_set()
638 {
639    if(position == last)
640       return false;
641    if(static_cast<const re_set*>(pstate)->_map[static_cast<unsigned char>(traits_inst.translate(*position, icase))])
642    {
643       pstate = pstate->next.p;
644       ++position;
645       return true;
646    }
647    return false;
648 }
649 
650 template <class BidiIterator, class Allocator, class traits>
match_jump()651 bool perl_matcher<BidiIterator, Allocator, traits>::match_jump()
652 {
653    pstate = static_cast<const re_jump*>(pstate)->alt.p;
654    return true;
655 }
656 
657 template <class BidiIterator, class Allocator, class traits>
match_combining()658 bool perl_matcher<BidiIterator, Allocator, traits>::match_combining()
659 {
660    if(position == last)
661       return false;
662    if(is_combining(traits_inst.translate(*position, icase)))
663       return false;
664    ++position;
665    while((position != last) && is_combining(traits_inst.translate(*position, icase)))
666       ++position;
667    pstate = pstate->next.p;
668    return true;
669 }
670 
671 template <class BidiIterator, class Allocator, class traits>
match_soft_buffer_end()672 bool perl_matcher<BidiIterator, Allocator, traits>::match_soft_buffer_end()
673 {
674    if(m_match_flags & match_not_eob)
675       return false;
676    BidiIterator p(position);
677    while((p != last) && is_separator(traits_inst.translate(*p, icase)))++p;
678    if(p != last)
679       return false;
680    pstate = pstate->next.p;
681    return true;
682 }
683 
684 template <class BidiIterator, class Allocator, class traits>
match_restart_continue()685 bool perl_matcher<BidiIterator, Allocator, traits>::match_restart_continue()
686 {
687    if(position == search_base)
688    {
689       pstate = pstate->next.p;
690       return true;
691    }
692    return false;
693 }
694 
695 template <class BidiIterator, class Allocator, class traits>
match_backstep()696 bool perl_matcher<BidiIterator, Allocator, traits>::match_backstep()
697 {
698 #ifdef BOOST_MSVC
699 #pragma warning(push)
700 #pragma warning(disable:4127)
701 #endif
702    if( ::boost::is_random_access_iterator<BidiIterator>::value)
703    {
704       std::ptrdiff_t maxlen = ::boost::re_detail::distance(backstop, position);
705       if(maxlen < static_cast<const re_brace*>(pstate)->index)
706          return false;
707       std::advance(position, -static_cast<const re_brace*>(pstate)->index);
708    }
709    else
710    {
711       int c = static_cast<const re_brace*>(pstate)->index;
712       while(c--)
713       {
714          if(position == backstop)
715             return false;
716          --position;
717       }
718    }
719    pstate = pstate->next.p;
720    return true;
721 #ifdef BOOST_MSVC
722 #pragma warning(pop)
723 #endif
724 }
725 
726 template <class BidiIterator, class Allocator, class traits>
match_assert_backref()727 inline bool perl_matcher<BidiIterator, Allocator, traits>::match_assert_backref()
728 {
729    // return true if marked sub-expression N has been matched:
730    int index = static_cast<const re_brace*>(pstate)->index;
731    bool result = false;
732    if(index == 9999)
733    {
734       // Magic value for a (DEFINE) block:
735       return false;
736    }
737    else if(index > 0)
738    {
739       // Have we matched subexpression "index"?
740       // Check if index is a hash value:
741       if(index >= 10000)
742       {
743          named_subexpressions::range_type r = re.get_data().equal_range(index);
744          while(r.first != r.second)
745          {
746             if((*m_presult)[r.first->index].matched)
747             {
748                result = true;
749                break;
750             }
751             ++r.first;
752          }
753       }
754       else
755       {
756          result = (*m_presult)[index].matched;
757       }
758       pstate = pstate->next.p;
759    }
760    else
761    {
762       // Have we recursed into subexpression "index"?
763       // If index == 0 then check for any recursion at all, otherwise for recursion to -index-1.
764       int idx = -index-1;
765       if(idx >= 10000)
766       {
767          named_subexpressions::range_type r = re.get_data().equal_range(idx);
768          int stack_index = recursion_stack.empty() ? -1 : recursion_stack.back().idx;
769          while(r.first != r.second)
770          {
771             result |= (stack_index == r.first->index);
772             if(result)break;
773             ++r.first;
774          }
775       }
776       else
777       {
778          result = !recursion_stack.empty() && ((recursion_stack.back().idx == idx) || (index == 0));
779       }
780       pstate = pstate->next.p;
781    }
782    return result;
783 }
784 
785 template <class BidiIterator, class Allocator, class traits>
match_toggle_case()786 bool perl_matcher<BidiIterator, Allocator, traits>::match_toggle_case()
787 {
788    // change our case sensitivity:
789    this->icase = static_cast<const re_case*>(pstate)->icase;
790    pstate = pstate->next.p;
791    return true;
792 }
793 
794 
795 template <class BidiIterator, class Allocator, class traits>
find_restart_any()796 bool perl_matcher<BidiIterator, Allocator, traits>::find_restart_any()
797 {
798 #ifdef BOOST_MSVC
799 #pragma warning(push)
800 #pragma warning(disable:4127)
801 #endif
802    const unsigned char* _map = re.get_map();
803    while(true)
804    {
805       // skip everything we can't match:
806       while((position != last) && !can_start(*position, _map, (unsigned char)mask_any) )
807          ++position;
808       if(position == last)
809       {
810          // run out of characters, try a null match if possible:
811          if(re.can_be_null())
812             return match_prefix();
813          break;
814       }
815       // now try and obtain a match:
816       if(match_prefix())
817          return true;
818       if(position == last)
819          return false;
820       ++position;
821    }
822    return false;
823 #ifdef BOOST_MSVC
824 #pragma warning(pop)
825 #endif
826 }
827 
828 template <class BidiIterator, class Allocator, class traits>
find_restart_word()829 bool perl_matcher<BidiIterator, Allocator, traits>::find_restart_word()
830 {
831 #ifdef BOOST_MSVC
832 #pragma warning(push)
833 #pragma warning(disable:4127)
834 #endif
835    // do search optimised for word starts:
836    const unsigned char* _map = re.get_map();
837    if((m_match_flags & match_prev_avail) || (position != base))
838       --position;
839    else if(match_prefix())
840       return true;
841    do
842    {
843       while((position != last) && traits_inst.isctype(*position, m_word_mask))
844          ++position;
845       while((position != last) && !traits_inst.isctype(*position, m_word_mask))
846          ++position;
847       if(position == last)
848          break;
849 
850       if(can_start(*position, _map, (unsigned char)mask_any) )
851       {
852          if(match_prefix())
853             return true;
854       }
855       if(position == last)
856          break;
857    } while(true);
858    return false;
859 #ifdef BOOST_MSVC
860 #pragma warning(pop)
861 #endif
862 }
863 
864 template <class BidiIterator, class Allocator, class traits>
find_restart_line()865 bool perl_matcher<BidiIterator, Allocator, traits>::find_restart_line()
866 {
867    // do search optimised for line starts:
868    const unsigned char* _map = re.get_map();
869    if(match_prefix())
870       return true;
871    while(position != last)
872    {
873       while((position != last) && !is_separator(*position))
874          ++position;
875       if(position == last)
876          return false;
877       ++position;
878       if(position == last)
879       {
880          if(re.can_be_null() && match_prefix())
881             return true;
882          return false;
883       }
884 
885       if( can_start(*position, _map, (unsigned char)mask_any) )
886       {
887          if(match_prefix())
888             return true;
889       }
890       if(position == last)
891          return false;
892       //++position;
893    }
894    return false;
895 }
896 
897 template <class BidiIterator, class Allocator, class traits>
find_restart_buf()898 bool perl_matcher<BidiIterator, Allocator, traits>::find_restart_buf()
899 {
900    if((position == base) && ((m_match_flags & match_not_bob) == 0))
901       return match_prefix();
902    return false;
903 }
904 
905 template <class BidiIterator, class Allocator, class traits>
find_restart_lit()906 bool perl_matcher<BidiIterator, Allocator, traits>::find_restart_lit()
907 {
908 #if 0
909    if(position == last)
910       return false; // can't possibly match if we're at the end already
911 
912    unsigned type = (m_match_flags & match_continuous) ?
913       static_cast<unsigned int>(regbase::restart_continue)
914          : static_cast<unsigned int>(re.get_restart_type());
915 
916    const kmp_info<char_type>* info = access::get_kmp(re);
917    int len = info->len;
918    const char_type* x = info->pstr;
919    int j = 0;
920    while (position != last)
921    {
922       while((j > -1) && (x[j] != traits_inst.translate(*position, icase)))
923          j = info->kmp_next[j];
924       ++position;
925       ++j;
926       if(j >= len)
927       {
928          if(type == regbase::restart_fixed_lit)
929          {
930             std::advance(position, -j);
931             restart = position;
932             std::advance(restart, len);
933             m_result.set_first(position);
934             m_result.set_second(restart);
935             position = restart;
936             return true;
937          }
938          else
939          {
940             restart = position;
941             std::advance(position, -j);
942             if(match_prefix())
943                return true;
944             else
945             {
946                for(int k = 0; (restart != position) && (k < j); ++k, --restart)
947                      {} // dwa 10/20/2000 - warning suppression for MWCW
948                if(restart != last)
949                   ++restart;
950                position = restart;
951                j = 0;  //we could do better than this...
952             }
953          }
954       }
955    }
956    if((m_match_flags & match_partial) && (position == last) && j)
957    {
958       // we need to check for a partial match:
959       restart = position;
960       std::advance(position, -j);
961       return match_prefix();
962    }
963 #endif
964    return false;
965 }
966 
967 } // namespace re_detail
968 
969 } // namespace boost
970 
971 #ifdef BOOST_MSVC
972 #  pragma warning(pop)
973 #endif
974 
975 #ifdef __BORLANDC__
976 #  pragma option pop
977 #endif
978 #ifdef BOOST_MSVC
979 #pragma warning(push)
980 #pragma warning(disable: 4103)
981 #endif
982 #ifdef BOOST_HAS_ABI_HEADERS
983 #  include BOOST_ABI_SUFFIX
984 #endif
985 #ifdef BOOST_MSVC
986 #pragma warning(pop)
987 #endif
988 
989 #endif
990 
991