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