1012 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			1012 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| /*
 | |
|  *
 | |
|  * Copyright (c) 2002
 | |
|  * John Maddock
 | |
|  *
 | |
|  * Use, modification and distribution are subject to the 
 | |
|  * Boost Software License, Version 1.0. (See accompanying file 
 | |
|  * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 | |
|  *
 | |
|  */
 | |
| 
 | |
|  /*
 | |
|   *   LOCATION:    see http://www.boost.org for most recent version.
 | |
|   *   FILE         perl_matcher_common.cpp
 | |
|   *   VERSION      see <boost/version.hpp>
 | |
|   *   DESCRIPTION: Definitions of perl_matcher member functions that are 
 | |
|   *                common to both the recursive and non-recursive versions.
 | |
|   */
 | |
| 
 | |
| #ifndef BOOST_REGEX_V4_PERL_MATCHER_COMMON_HPP
 | |
| #define BOOST_REGEX_V4_PERL_MATCHER_COMMON_HPP
 | |
| 
 | |
| #ifdef BOOST_MSVC
 | |
| #pragma warning(push)
 | |
| #pragma warning(disable: 4103)
 | |
| #endif
 | |
| #ifdef BOOST_HAS_ABI_HEADERS
 | |
| #  include BOOST_ABI_PREFIX
 | |
| #endif
 | |
| #ifdef BOOST_MSVC
 | |
| #pragma warning(pop)
 | |
| #endif
 | |
| 
 | |
| #ifdef __BORLANDC__
 | |
| #  pragma option push -w-8008 -w-8066
 | |
| #endif
 | |
| #ifdef BOOST_MSVC
 | |
| #  pragma warning(push)
 | |
| #  pragma warning(disable: 4800)
 | |
| #endif
 | |
| 
 | |
| namespace boost{
 | |
| namespace BOOST_REGEX_DETAIL_NS{
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| void perl_matcher<BidiIterator, Allocator, traits>::construct_init(const basic_regex<char_type, traits>& e, match_flag_type f)
 | |
| { 
 | |
|    typedef typename regex_iterator_traits<BidiIterator>::iterator_category category;
 | |
|    typedef typename basic_regex<char_type, traits>::flag_type expression_flag_type;
 | |
|    
 | |
|    if(e.empty())
 | |
|    {
 | |
|       // precondition failure: e is not a valid regex.
 | |
|       std::invalid_argument ex("Invalid regular expression object");
 | |
|       boost::throw_exception(ex);
 | |
|    }
 | |
|    pstate = 0;
 | |
|    m_match_flags = f;
 | |
|    estimate_max_state_count(static_cast<category*>(0));
 | |
|    expression_flag_type re_f = re.flags();
 | |
|    icase = re_f & regex_constants::icase;
 | |
|    if(!(m_match_flags & (match_perl|match_posix)))
 | |
|    {
 | |
|       if((re_f & (regbase::main_option_type|regbase::no_perl_ex)) == 0)
 | |
|          m_match_flags |= match_perl;
 | |
|       else if((re_f & (regbase::main_option_type|regbase::emacs_ex)) == (regbase::basic_syntax_group|regbase::emacs_ex))
 | |
|          m_match_flags |= match_perl;
 | |
|       else if((re_f & (regbase::main_option_type|regbase::literal)) == (regbase::literal))
 | |
|          m_match_flags |= match_perl;
 | |
|       else
 | |
|          m_match_flags |= match_posix;
 | |
|    }
 | |
|    if(m_match_flags & match_posix)
 | |
|    {
 | |
|       m_temp_match.reset(new match_results<BidiIterator, Allocator>());
 | |
|       m_presult = m_temp_match.get();
 | |
|    }
 | |
|    else
 | |
|       m_presult = &m_result;
 | |
| #ifdef BOOST_REGEX_NON_RECURSIVE
 | |
|    m_stack_base = 0;
 | |
|    m_backup_state = 0;
 | |
| #elif defined(BOOST_REGEX_RECURSIVE)
 | |
|    m_can_backtrack = true;
 | |
|    m_have_accept = false;
 | |
| #endif
 | |
|    // find the value to use for matching word boundaries:
 | |
|    m_word_mask = re.get_data().m_word_mask; 
 | |
|    // find bitmask to use for matching '.':
 | |
|    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);
 | |
|    // Disable match_any if requested in the state machine:
 | |
|    if(e.get_data().m_disable_match_any)
 | |
|       m_match_flags &= ~regex_constants::match_any;
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| void perl_matcher<BidiIterator, Allocator, traits>::estimate_max_state_count(std::random_access_iterator_tag*)
 | |
| {
 | |
|    //
 | |
|    // How many states should we allow our machine to visit before giving up?
 | |
|    // This is a heuristic: it takes the greater of O(N^2) and O(NS^2)
 | |
|    // where N is the length of the string, and S is the number of states
 | |
|    // in the machine.  It's tempting to up this to O(N^2S) or even O(N^2S^2)
 | |
|    // but these take unreasonably amounts of time to bale out in pathological
 | |
|    // cases.
 | |
|    //
 | |
|    // Calculate NS^2 first:
 | |
|    //
 | |
|    static const std::ptrdiff_t k = 100000;
 | |
|    std::ptrdiff_t dist = boost::BOOST_REGEX_DETAIL_NS::distance(base, last);
 | |
|    if(dist == 0)
 | |
|       dist = 1;
 | |
|    std::ptrdiff_t states = re.size();
 | |
|    if(states == 0)
 | |
|       states = 1;
 | |
|    states *= states;
 | |
|    if((std::numeric_limits<std::ptrdiff_t>::max)() / dist < states)
 | |
|    {
 | |
|       max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits<std::ptrdiff_t>::max)() - 2);
 | |
|       return;
 | |
|    }
 | |
|    states *= dist;
 | |
|    if((std::numeric_limits<std::ptrdiff_t>::max)() - k < states)
 | |
|    {
 | |
|       max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits<std::ptrdiff_t>::max)() - 2);
 | |
|       return;
 | |
|    }
 | |
|    states += k;
 | |
| 
 | |
|    max_state_count = states;
 | |
| 
 | |
|    //
 | |
|    // Now calculate N^2:
 | |
|    //
 | |
|    states = dist;
 | |
|    if((std::numeric_limits<std::ptrdiff_t>::max)() / dist < states)
 | |
|    {
 | |
|       max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits<std::ptrdiff_t>::max)() - 2);
 | |
|       return;
 | |
|    }
 | |
|    states *= dist;
 | |
|    if((std::numeric_limits<std::ptrdiff_t>::max)() - k < states)
 | |
|    {
 | |
|       max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits<std::ptrdiff_t>::max)() - 2);
 | |
|       return;
 | |
|    }
 | |
|    states += k;
 | |
|    //
 | |
|    // N^2 can be a very large number indeed, to prevent things getting out
 | |
|    // of control, cap the max states:
 | |
|    //
 | |
|    if(states > BOOST_REGEX_MAX_STATE_COUNT)
 | |
|       states = BOOST_REGEX_MAX_STATE_COUNT;
 | |
|    //
 | |
|    // If (the possibly capped) N^2 is larger than our first estimate,
 | |
|    // use this instead:
 | |
|    //
 | |
|    if(states > max_state_count)
 | |
|       max_state_count = states;
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| inline void perl_matcher<BidiIterator, Allocator, traits>::estimate_max_state_count(void*)
 | |
| {
 | |
|    // we don't know how long the sequence is:
 | |
|    max_state_count = BOOST_REGEX_MAX_STATE_COUNT;
 | |
| }
 | |
| 
 | |
| #ifdef BOOST_REGEX_HAS_MS_STACK_GUARD
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| inline bool perl_matcher<BidiIterator, Allocator, traits>::protected_call(
 | |
|    protected_proc_type proc)
 | |
| {
 | |
|    ::boost::BOOST_REGEX_DETAIL_NS::concrete_protected_call
 | |
|       <perl_matcher<BidiIterator, Allocator, traits> >
 | |
|       obj(this, proc);
 | |
|    return obj.execute();
 | |
| 
 | |
| }
 | |
| #endif
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| inline bool perl_matcher<BidiIterator, Allocator, traits>::match()
 | |
| {
 | |
| #ifdef BOOST_REGEX_HAS_MS_STACK_GUARD
 | |
|    return protected_call(&perl_matcher<BidiIterator, Allocator, traits>::match_imp);
 | |
| #else
 | |
|    return match_imp();
 | |
| #endif
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::match_imp()
 | |
| {
 | |
|    // initialise our stack if we are non-recursive:
 | |
| #ifdef BOOST_REGEX_NON_RECURSIVE
 | |
|    save_state_init init(&m_stack_base, &m_backup_state);
 | |
|    used_block_count = BOOST_REGEX_MAX_BLOCKS;
 | |
| #if !defined(BOOST_NO_EXCEPTIONS)
 | |
|    try{
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
|    // reset our state machine:
 | |
|    position = base;
 | |
|    search_base = base;
 | |
|    state_count = 0;
 | |
|    m_match_flags |= regex_constants::match_all;
 | |
|    m_presult->set_size((m_match_flags & match_nosubs) ? 1u : static_cast<typename results_type::size_type>(1u + re.mark_count()), search_base, last);
 | |
|    m_presult->set_base(base);
 | |
|    m_presult->set_named_subs(this->re.get_named_subs());
 | |
|    if(m_match_flags & match_posix)
 | |
|       m_result = *m_presult;
 | |
|    verify_options(re.flags(), m_match_flags);
 | |
|    if(0 == match_prefix())
 | |
|       return false;
 | |
|    return (m_result[0].second == last) && (m_result[0].first == base);
 | |
| 
 | |
| #if defined(BOOST_REGEX_NON_RECURSIVE) && !defined(BOOST_NO_EXCEPTIONS)
 | |
|    }
 | |
|    catch(...)
 | |
|    {
 | |
|       // unwind all pushed states, apart from anything else this
 | |
|       // ensures that all the states are correctly destructed
 | |
|       // not just the memory freed.
 | |
|       while(unwind(true)){}
 | |
|       throw;
 | |
|    }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| inline bool perl_matcher<BidiIterator, Allocator, traits>::find()
 | |
| {
 | |
| #ifdef BOOST_REGEX_HAS_MS_STACK_GUARD
 | |
|    return protected_call(&perl_matcher<BidiIterator, Allocator, traits>::find_imp);
 | |
| #else
 | |
|    return find_imp();
 | |
| #endif
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::find_imp()
 | |
| {
 | |
|    static matcher_proc_type const s_find_vtable[7] = 
 | |
|    {
 | |
|       &perl_matcher<BidiIterator, Allocator, traits>::find_restart_any,
 | |
|       &perl_matcher<BidiIterator, Allocator, traits>::find_restart_word,
 | |
|       &perl_matcher<BidiIterator, Allocator, traits>::find_restart_line,
 | |
|       &perl_matcher<BidiIterator, Allocator, traits>::find_restart_buf,
 | |
|       &perl_matcher<BidiIterator, Allocator, traits>::match_prefix,
 | |
|       &perl_matcher<BidiIterator, Allocator, traits>::find_restart_lit,
 | |
|       &perl_matcher<BidiIterator, Allocator, traits>::find_restart_lit,
 | |
|    };
 | |
| 
 | |
|    // initialise our stack if we are non-recursive:
 | |
| #ifdef BOOST_REGEX_NON_RECURSIVE
 | |
|    save_state_init init(&m_stack_base, &m_backup_state);
 | |
|    used_block_count = BOOST_REGEX_MAX_BLOCKS;
 | |
| #if !defined(BOOST_NO_EXCEPTIONS)
 | |
|    try{
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
|    state_count = 0;
 | |
|    if((m_match_flags & regex_constants::match_init) == 0)
 | |
|    {
 | |
|       // reset our state machine:
 | |
|       search_base = position = base;
 | |
|       pstate = re.get_first_state();
 | |
|       m_presult->set_size((m_match_flags & match_nosubs) ? 1u : static_cast<typename results_type::size_type>(1u + re.mark_count()), base, last);
 | |
|       m_presult->set_base(base);
 | |
|       m_presult->set_named_subs(this->re.get_named_subs());
 | |
|       m_match_flags |= regex_constants::match_init;
 | |
|    }
 | |
|    else
 | |
|    {
 | |
|       // start again:
 | |
|       search_base = position = m_result[0].second;
 | |
|       // If last match was null and match_not_null was not set then increment
 | |
|       // our start position, otherwise we go into an infinite loop:
 | |
|       if(((m_match_flags & match_not_null) == 0) && (m_result.length() == 0))
 | |
|       {
 | |
|          if(position == last)
 | |
|             return false;
 | |
|          else 
 | |
|             ++position;
 | |
|       }
 | |
|       // reset $` start:
 | |
|       m_presult->set_size((m_match_flags & match_nosubs) ? 1u : static_cast<typename results_type::size_type>(1u + re.mark_count()), search_base, last);
 | |
|       //if((base != search_base) && (base == backstop))
 | |
|       //   m_match_flags |= match_prev_avail;
 | |
|    }
 | |
|    if(m_match_flags & match_posix)
 | |
|    {
 | |
|       m_result.set_size(static_cast<typename results_type::size_type>(1u + re.mark_count()), base, last);
 | |
|       m_result.set_base(base);
 | |
|    }
 | |
| 
 | |
|    verify_options(re.flags(), m_match_flags);
 | |
|    // find out what kind of expression we have:
 | |
|    unsigned type = (m_match_flags & match_continuous) ? 
 | |
|       static_cast<unsigned int>(regbase::restart_continue) 
 | |
|          : static_cast<unsigned int>(re.get_restart_type());
 | |
| 
 | |
|    // call the appropriate search routine:
 | |
|    matcher_proc_type proc = s_find_vtable[type];
 | |
|    return (this->*proc)();
 | |
| 
 | |
| #if defined(BOOST_REGEX_NON_RECURSIVE) && !defined(BOOST_NO_EXCEPTIONS)
 | |
|    }
 | |
|    catch(...)
 | |
|    {
 | |
|       // unwind all pushed states, apart from anything else this
 | |
|       // ensures that all the states are correctly destructed
 | |
|       // not just the memory freed.
 | |
|       while(unwind(true)){}
 | |
|       throw;
 | |
|    }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::match_prefix()
 | |
| {
 | |
|    m_has_partial_match = false;
 | |
|    m_has_found_match = false;
 | |
|    pstate = re.get_first_state();
 | |
|    m_presult->set_first(position);
 | |
|    restart = position;
 | |
|    match_all_states();
 | |
|    if(!m_has_found_match && m_has_partial_match && (m_match_flags & match_partial))
 | |
|    {
 | |
|       m_has_found_match = true;
 | |
|       m_presult->set_second(last, 0, false);
 | |
|       position = last;
 | |
|       if((m_match_flags & match_posix) == match_posix)
 | |
|       {
 | |
|          m_result.maybe_assign(*m_presult);
 | |
|       }
 | |
|    }
 | |
| #ifdef BOOST_REGEX_MATCH_EXTRA
 | |
|    if(m_has_found_match && (match_extra & m_match_flags))
 | |
|    {
 | |
|       //
 | |
|       // we have a match, reverse the capture information:
 | |
|       //
 | |
|       for(unsigned i = 0; i < m_presult->size(); ++i)
 | |
|       {
 | |
|          typename sub_match<BidiIterator>::capture_sequence_type & seq = ((*m_presult)[i]).get_captures();
 | |
|          std::reverse(seq.begin(), seq.end());
 | |
|       }
 | |
|    }
 | |
| #endif
 | |
|    if(!m_has_found_match)
 | |
|       position = restart; // reset search postion
 | |
| #ifdef BOOST_REGEX_RECURSIVE
 | |
|    m_can_backtrack = true; // reset for further searches
 | |
| #endif
 | |
|    return m_has_found_match;
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::match_literal()
 | |
| {
 | |
|    unsigned int len = static_cast<const re_literal*>(pstate)->length;
 | |
|    const char_type* what = reinterpret_cast<const char_type*>(static_cast<const re_literal*>(pstate) + 1);
 | |
|    //
 | |
|    // compare string with what we stored in
 | |
|    // our records:
 | |
|    for(unsigned int i = 0; i < len; ++i, ++position)
 | |
|    {
 | |
|       if((position == last) || (traits_inst.translate(*position, icase) != what[i]))
 | |
|          return false;
 | |
|    }
 | |
|    pstate = pstate->next.p;
 | |
|    return true;
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::match_start_line()
 | |
| {
 | |
|    if(position == backstop)
 | |
|    {
 | |
|       if((m_match_flags & match_prev_avail) == 0)
 | |
|       {
 | |
|          if((m_match_flags & match_not_bol) == 0)
 | |
|          {
 | |
|             pstate = pstate->next.p;
 | |
|             return true;
 | |
|          }
 | |
|          return false;
 | |
|       }
 | |
|    }
 | |
|    else if(m_match_flags & match_single_line)
 | |
|       return false;
 | |
| 
 | |
|    // check the previous value character:
 | |
|    BidiIterator t(position);
 | |
|    --t;
 | |
|    if(position != last)
 | |
|    {
 | |
|       if(is_separator(*t) && !((*t == static_cast<char_type>('\r')) && (*position == static_cast<char_type>('\n'))) )
 | |
|       {
 | |
|          pstate = pstate->next.p;
 | |
|          return true;
 | |
|       }
 | |
|    }
 | |
|    else if(is_separator(*t))
 | |
|    {
 | |
|       pstate = pstate->next.p;
 | |
|       return true;
 | |
|    }
 | |
|    return false;
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::match_end_line()
 | |
| {
 | |
|    if(position != last)
 | |
|    {
 | |
|       if(m_match_flags & match_single_line)
 | |
|          return false;
 | |
|       // we're not yet at the end so *first is always valid:
 | |
|       if(is_separator(*position))
 | |
|       {
 | |
|          if((position != backstop) || (m_match_flags & match_prev_avail))
 | |
|          {
 | |
|             // check that we're not in the middle of \r\n sequence
 | |
|             BidiIterator t(position);
 | |
|             --t;
 | |
|             if((*t == static_cast<char_type>('\r')) && (*position == static_cast<char_type>('\n')))
 | |
|             {
 | |
|                return false;
 | |
|             }
 | |
|          }
 | |
|          pstate = pstate->next.p;
 | |
|          return true;
 | |
|       }
 | |
|    }
 | |
|    else if((m_match_flags & match_not_eol) == 0)
 | |
|    {
 | |
|       pstate = pstate->next.p;
 | |
|       return true;
 | |
|    }
 | |
|    return false;
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::match_wild()
 | |
| {
 | |
|    if(position == last) 
 | |
|       return false;
 | |
|    if(is_separator(*position) && ((match_any_mask & static_cast<const re_dot*>(pstate)->mask) == 0))
 | |
|       return false;
 | |
|    if((*position == char_type(0)) && (m_match_flags & match_not_dot_null))
 | |
|       return false;
 | |
|    pstate = pstate->next.p;
 | |
|    ++position;
 | |
|    return true;
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::match_word_boundary()
 | |
| {
 | |
|    bool b; // indcates whether next character is a word character
 | |
|    if(position != last)
 | |
|    {
 | |
|       // prev and this character must be opposites:
 | |
|       b = traits_inst.isctype(*position, m_word_mask);
 | |
|    }
 | |
|    else
 | |
|    {
 | |
|       b = (m_match_flags & match_not_eow) ? true : false;
 | |
|    }
 | |
|    if((position == backstop) && ((m_match_flags & match_prev_avail) == 0))
 | |
|    {
 | |
|       if(m_match_flags & match_not_bow)
 | |
|          b ^= true;
 | |
|       else
 | |
|          b ^= false;
 | |
|    }
 | |
|    else
 | |
|    {
 | |
|       --position;
 | |
|       b ^= traits_inst.isctype(*position, m_word_mask);
 | |
|       ++position;
 | |
|    }
 | |
|    if(b)
 | |
|    {
 | |
|       pstate = pstate->next.p;
 | |
|       return true;
 | |
|    }
 | |
|    return false; // no match if we get to here...
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::match_within_word()
 | |
| {
 | |
|    if(position == last)
 | |
|       return false;
 | |
|    // both prev and this character must be m_word_mask:
 | |
|    bool prev = traits_inst.isctype(*position, m_word_mask);
 | |
|    {
 | |
|       bool b;
 | |
|       if((position == backstop) && ((m_match_flags & match_prev_avail) == 0)) 
 | |
|          return false;
 | |
|       else
 | |
|       {
 | |
|          --position;
 | |
|          b = traits_inst.isctype(*position, m_word_mask);
 | |
|          ++position;
 | |
|       }
 | |
|       if(b == prev)
 | |
|       {
 | |
|          pstate = pstate->next.p;
 | |
|          return true;
 | |
|       }
 | |
|    }
 | |
|    return false;
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::match_word_start()
 | |
| {
 | |
|    if(position == last)
 | |
|       return false; // can't be starting a word if we're already at the end of input
 | |
|    if(!traits_inst.isctype(*position, m_word_mask))
 | |
|       return false; // next character isn't a word character
 | |
|    if((position == backstop) && ((m_match_flags & match_prev_avail) == 0))
 | |
|    {
 | |
|       if(m_match_flags & match_not_bow)
 | |
|          return false; // no previous input
 | |
|    }
 | |
|    else
 | |
|    {
 | |
|       // otherwise inside buffer:
 | |
|       BidiIterator t(position);
 | |
|       --t;
 | |
|       if(traits_inst.isctype(*t, m_word_mask))
 | |
|          return false; // previous character not non-word
 | |
|    }
 | |
|    // OK we have a match:
 | |
|    pstate = pstate->next.p;
 | |
|    return true;
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::match_word_end()
 | |
| {
 | |
|    if((position == backstop) && ((m_match_flags & match_prev_avail) == 0))
 | |
|       return false;  // start of buffer can't be end of word
 | |
|    BidiIterator t(position);
 | |
|    --t;
 | |
|    if(traits_inst.isctype(*t, m_word_mask) == false)
 | |
|       return false;  // previous character wasn't a word character
 | |
| 
 | |
|    if(position == last)
 | |
|    {
 | |
|       if(m_match_flags & match_not_eow)
 | |
|          return false; // end of buffer but not end of word
 | |
|    }
 | |
|    else
 | |
|    {
 | |
|       // otherwise inside buffer:
 | |
|       if(traits_inst.isctype(*position, m_word_mask))
 | |
|          return false; // next character is a word character
 | |
|    }
 | |
|    pstate = pstate->next.p;
 | |
|    return true;      // if we fall through to here then we've succeeded
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::match_buffer_start()
 | |
| {
 | |
|    if((position != backstop) || (m_match_flags & match_not_bob))
 | |
|       return false;
 | |
|    // OK match:
 | |
|    pstate = pstate->next.p;
 | |
|    return true;
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::match_buffer_end()
 | |
| {
 | |
|    if((position != last) || (m_match_flags & match_not_eob))
 | |
|       return false;
 | |
|    // OK match:
 | |
|    pstate = pstate->next.p;
 | |
|    return true;
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::match_backref()
 | |
| {
 | |
|    //
 | |
|    // Compare with what we previously matched.
 | |
|    // Note that this succeeds if the backref did not partisipate
 | |
|    // in the match, this is in line with ECMAScript, but not Perl
 | |
|    // or PCRE.
 | |
|    //
 | |
|    int index = static_cast<const re_brace*>(pstate)->index;
 | |
|    if(index >= 10000)
 | |
|    {
 | |
|       named_subexpressions::range_type r = re.get_data().equal_range(index);
 | |
|       BOOST_ASSERT(r.first != r.second);
 | |
|       do
 | |
|       {
 | |
|          index = r.first->index;
 | |
|          ++r.first;
 | |
|       }while((r.first != r.second) && ((*m_presult)[index].matched != true));
 | |
|    }
 | |
| 
 | |
|    if((m_match_flags & match_perl) && !(*m_presult)[index].matched)
 | |
|       return false;
 | |
| 
 | |
|    BidiIterator i = (*m_presult)[index].first;
 | |
|    BidiIterator j = (*m_presult)[index].second;
 | |
|    while(i != j)
 | |
|    {
 | |
|       if((position == last) || (traits_inst.translate(*position, icase) != traits_inst.translate(*i, icase)))
 | |
|          return false;
 | |
|       ++i;
 | |
|       ++position;
 | |
|    }
 | |
|    pstate = pstate->next.p;
 | |
|    return true;
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::match_long_set()
 | |
| {
 | |
|    typedef typename traits::char_class_type char_class_type;
 | |
|    // let the traits class do the work:
 | |
|    if(position == last)
 | |
|       return false;
 | |
|    BidiIterator t = re_is_set_member(position, last, static_cast<const re_set_long<char_class_type>*>(pstate), re.get_data(), icase);
 | |
|    if(t != position)
 | |
|    {
 | |
|       pstate = pstate->next.p;
 | |
|       position = t;
 | |
|       return true;
 | |
|    }
 | |
|    return false;
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::match_set()
 | |
| {
 | |
|    if(position == last)
 | |
|       return false;
 | |
|    if(static_cast<const re_set*>(pstate)->_map[static_cast<unsigned char>(traits_inst.translate(*position, icase))])
 | |
|    {
 | |
|       pstate = pstate->next.p;
 | |
|       ++position;
 | |
|       return true;
 | |
|    }
 | |
|    return false;
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::match_jump()
 | |
| {
 | |
|    pstate = static_cast<const re_jump*>(pstate)->alt.p;
 | |
|    return true;
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::match_combining()
 | |
| {
 | |
|    if(position == last)
 | |
|       return false;
 | |
|    if(is_combining(traits_inst.translate(*position, icase)))
 | |
|       return false;
 | |
|    ++position;
 | |
|    while((position != last) && is_combining(traits_inst.translate(*position, icase)))
 | |
|       ++position;
 | |
|    pstate = pstate->next.p;
 | |
|    return true;
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::match_soft_buffer_end()
 | |
| {
 | |
|    if(m_match_flags & match_not_eob)
 | |
|       return false;
 | |
|    BidiIterator p(position);
 | |
|    while((p != last) && is_separator(traits_inst.translate(*p, icase)))++p;
 | |
|    if(p != last)
 | |
|       return false;
 | |
|    pstate = pstate->next.p;
 | |
|    return true;
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::match_restart_continue()
 | |
| {
 | |
|    if(position == search_base)
 | |
|    {
 | |
|       pstate = pstate->next.p;
 | |
|       return true;
 | |
|    }
 | |
|    return false;
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::match_backstep()
 | |
| {
 | |
| #ifdef BOOST_MSVC
 | |
| #pragma warning(push)
 | |
| #pragma warning(disable:4127)
 | |
| #endif
 | |
|    if( ::boost::is_random_access_iterator<BidiIterator>::value)
 | |
|    {
 | |
|       std::ptrdiff_t maxlen = ::boost::BOOST_REGEX_DETAIL_NS::distance(backstop, position);
 | |
|       if(maxlen < static_cast<const re_brace*>(pstate)->index)
 | |
|          return false;
 | |
|       std::advance(position, -static_cast<const re_brace*>(pstate)->index);
 | |
|    }
 | |
|    else
 | |
|    {
 | |
|       int c = static_cast<const re_brace*>(pstate)->index;
 | |
|       while(c--)
 | |
|       {
 | |
|          if(position == backstop)
 | |
|             return false;
 | |
|          --position;
 | |
|       }
 | |
|    }
 | |
|    pstate = pstate->next.p;
 | |
|    return true;
 | |
| #ifdef BOOST_MSVC
 | |
| #pragma warning(pop)
 | |
| #endif
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| inline bool perl_matcher<BidiIterator, Allocator, traits>::match_assert_backref()
 | |
| {
 | |
|    // return true if marked sub-expression N has been matched:
 | |
|    int index = static_cast<const re_brace*>(pstate)->index;
 | |
|    bool result = false;
 | |
|    if(index == 9999)
 | |
|    {
 | |
|       // Magic value for a (DEFINE) block:
 | |
|       return false;
 | |
|    }
 | |
|    else if(index > 0)
 | |
|    {
 | |
|       // Have we matched subexpression "index"?
 | |
|       // Check if index is a hash value:
 | |
|       if(index >= 10000)
 | |
|       {
 | |
|          named_subexpressions::range_type r = re.get_data().equal_range(index);
 | |
|          while(r.first != r.second)
 | |
|          {
 | |
|             if((*m_presult)[r.first->index].matched)
 | |
|             {
 | |
|                result = true;
 | |
|                break;
 | |
|             }
 | |
|             ++r.first;
 | |
|          }
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|          result = (*m_presult)[index].matched;
 | |
|       }
 | |
|       pstate = pstate->next.p;
 | |
|    }
 | |
|    else
 | |
|    {
 | |
|       // Have we recursed into subexpression "index"?
 | |
|       // If index == 0 then check for any recursion at all, otherwise for recursion to -index-1.
 | |
|       int idx = -index-1;
 | |
|       if(idx >= 10000)
 | |
|       {
 | |
|          named_subexpressions::range_type r = re.get_data().equal_range(idx);
 | |
|          int stack_index = recursion_stack.empty() ? -1 : recursion_stack.back().idx;
 | |
|          while(r.first != r.second)
 | |
|          {
 | |
|             result |= (stack_index == r.first->index);
 | |
|             if(result)break;
 | |
|             ++r.first;
 | |
|          }
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|          result = !recursion_stack.empty() && ((recursion_stack.back().idx == idx) || (index == 0));
 | |
|       }
 | |
|       pstate = pstate->next.p;
 | |
|    }
 | |
|    return result;
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::match_fail()
 | |
| {
 | |
|    // Just force a backtrack:
 | |
|    return false;
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::match_accept()
 | |
| {
 | |
|    if(!recursion_stack.empty())
 | |
|    {
 | |
|       return skip_until_paren(recursion_stack.back().idx);
 | |
|    }
 | |
|    else
 | |
|    {
 | |
|       return skip_until_paren(INT_MAX);
 | |
|    }
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::find_restart_any()
 | |
| {
 | |
| #ifdef BOOST_MSVC
 | |
| #pragma warning(push)
 | |
| #pragma warning(disable:4127)
 | |
| #endif
 | |
|    const unsigned char* _map = re.get_map();
 | |
|    while(true)
 | |
|    {
 | |
|       // skip everything we can't match:
 | |
|       while((position != last) && !can_start(*position, _map, (unsigned char)mask_any) )
 | |
|          ++position;
 | |
|       if(position == last)
 | |
|       {
 | |
|          // run out of characters, try a null match if possible:
 | |
|          if(re.can_be_null())
 | |
|             return match_prefix();
 | |
|          break;
 | |
|       }
 | |
|       // now try and obtain a match:
 | |
|       if(match_prefix())
 | |
|          return true;
 | |
|       if(position == last)
 | |
|          return false;
 | |
|       ++position;
 | |
|    }
 | |
|    return false;
 | |
| #ifdef BOOST_MSVC
 | |
| #pragma warning(pop)
 | |
| #endif
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::find_restart_word()
 | |
| {
 | |
| #ifdef BOOST_MSVC
 | |
| #pragma warning(push)
 | |
| #pragma warning(disable:4127)
 | |
| #endif
 | |
|    // do search optimised for word starts:
 | |
|    const unsigned char* _map = re.get_map();
 | |
|    if((m_match_flags & match_prev_avail) || (position != base))
 | |
|       --position;
 | |
|    else if(match_prefix())
 | |
|       return true;
 | |
|    do
 | |
|    {
 | |
|       while((position != last) && traits_inst.isctype(*position, m_word_mask))
 | |
|          ++position;
 | |
|       while((position != last) && !traits_inst.isctype(*position, m_word_mask))
 | |
|          ++position;
 | |
|       if(position == last)
 | |
|          break;
 | |
| 
 | |
|       if(can_start(*position, _map, (unsigned char)mask_any) )
 | |
|       {
 | |
|          if(match_prefix())
 | |
|             return true;
 | |
|       }
 | |
|       if(position == last)
 | |
|          break;
 | |
|    } while(true);
 | |
|    return false;
 | |
| #ifdef BOOST_MSVC
 | |
| #pragma warning(pop)
 | |
| #endif
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::find_restart_line()
 | |
| {
 | |
|    // do search optimised for line starts:
 | |
|    const unsigned char* _map = re.get_map();
 | |
|    if(match_prefix())
 | |
|       return true;
 | |
|    while(position != last)
 | |
|    {
 | |
|       while((position != last) && !is_separator(*position))
 | |
|          ++position;
 | |
|       if(position == last)
 | |
|          return false;
 | |
|       ++position;
 | |
|       if(position == last)
 | |
|       {
 | |
|          if(re.can_be_null() && match_prefix())
 | |
|             return true;
 | |
|          return false;
 | |
|       }
 | |
| 
 | |
|       if( can_start(*position, _map, (unsigned char)mask_any) )
 | |
|       {
 | |
|          if(match_prefix())
 | |
|             return true;
 | |
|       }
 | |
|       if(position == last)
 | |
|          return false;
 | |
|       //++position;
 | |
|    }
 | |
|    return false;
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::find_restart_buf()
 | |
| {
 | |
|    if((position == base) && ((m_match_flags & match_not_bob) == 0))
 | |
|       return match_prefix();
 | |
|    return false;
 | |
| }
 | |
| 
 | |
| template <class BidiIterator, class Allocator, class traits>
 | |
| bool perl_matcher<BidiIterator, Allocator, traits>::find_restart_lit()
 | |
| {
 | |
| #if 0
 | |
|    if(position == last)
 | |
|       return false; // can't possibly match if we're at the end already
 | |
| 
 | |
|    unsigned type = (m_match_flags & match_continuous) ? 
 | |
|       static_cast<unsigned int>(regbase::restart_continue) 
 | |
|          : static_cast<unsigned int>(re.get_restart_type());
 | |
| 
 | |
|    const kmp_info<char_type>* info = access::get_kmp(re);
 | |
|    int len = info->len;
 | |
|    const char_type* x = info->pstr;
 | |
|    int j = 0; 
 | |
|    while (position != last) 
 | |
|    {
 | |
|       while((j > -1) && (x[j] != traits_inst.translate(*position, icase))) 
 | |
|          j = info->kmp_next[j];
 | |
|       ++position;
 | |
|       ++j;
 | |
|       if(j >= len) 
 | |
|       {
 | |
|          if(type == regbase::restart_fixed_lit)
 | |
|          {
 | |
|             std::advance(position, -j);
 | |
|             restart = position;
 | |
|             std::advance(restart, len);
 | |
|             m_result.set_first(position);
 | |
|             m_result.set_second(restart);
 | |
|             position = restart;
 | |
|             return true;
 | |
|          }
 | |
|          else
 | |
|          {
 | |
|             restart = position;
 | |
|             std::advance(position, -j);
 | |
|             if(match_prefix())
 | |
|                return true;
 | |
|             else
 | |
|             {
 | |
|                for(int k = 0; (restart != position) && (k < j); ++k, --restart)
 | |
|                      {} // dwa 10/20/2000 - warning suppression for MWCW
 | |
|                if(restart != last)
 | |
|                   ++restart;
 | |
|                position = restart;
 | |
|                j = 0;  //we could do better than this...
 | |
|             }
 | |
|          }
 | |
|       }
 | |
|    }
 | |
|    if((m_match_flags & match_partial) && (position == last) && j)
 | |
|    {
 | |
|       // we need to check for a partial match:
 | |
|       restart = position;
 | |
|       std::advance(position, -j);
 | |
|       return match_prefix();
 | |
|    }
 | |
| #endif
 | |
|    return false;
 | |
| }
 | |
| 
 | |
| } // namespace BOOST_REGEX_DETAIL_NS
 | |
| 
 | |
| } // namespace boost
 | |
| 
 | |
| #ifdef BOOST_MSVC
 | |
| #  pragma warning(pop)
 | |
| #endif
 | |
| 
 | |
| #ifdef __BORLANDC__
 | |
| #  pragma option pop
 | |
| #endif
 | |
| #ifdef BOOST_MSVC
 | |
| #pragma warning(push)
 | |
| #pragma warning(disable: 4103)
 | |
| #endif
 | |
| #ifdef BOOST_HAS_ABI_HEADERS
 | |
| #  include BOOST_ABI_SUFFIX
 | |
| #endif
 | |
| #ifdef BOOST_MSVC
 | |
| #pragma warning(pop)
 | |
| #endif
 | |
| 
 | |
| #endif
 | |
| 
 | 
