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