reimpl2.h
上传用户:dzyhzl
上传日期:2019-04-29
资源大小:56270k
文件大小:40k
源码类别:

模拟服务器

开发平台:

C/C++

  1. //+---------------------------------------------------------------------------
  2. //
  3. //  Copyright ( C ) Microsoft Corporation, 1994 - 2002.
  4. //
  5. //  File:       reimpl2.h
  6. //
  7. //  Functions:  helpers for matching and substituting regular expressions
  8. //
  9. //  Notes:      implementation details that really belong in a cpp file,
  10. //              but can't because of template weirdness
  11. //
  12. //  Author:     Eric Niebler ( ericne@microsoft.com )
  13. //
  14. //  History:    8/15/2001   ericne   Created
  15. //
  16. //----------------------------------------------------------------------------
  17. #ifndef REIMPL_H
  18. #define REIMPL_H
  19. //
  20. // Helper functions for match and substitute
  21. //
  22. #ifndef _MSC_VER
  23. #define __assume( x ) assert( false ); break;
  24. #endif
  25. namespace detail
  26. {
  27. // For use while doing uppercase/lowercase conversions:
  28. // For use while doing uppercase/lowercase conversions:
  29. inline  char   regex_toupper(  char   ch ) { return ( char  )toupper( ch ); }
  30. inline  char   regex_tolower(  char   ch ) { return ( char  )tolower( ch ); }
  31. inline wchar_t regex_toupper( wchar_t ch ) { return ( wchar_t )towupper( ch ); }
  32. inline wchar_t regex_tolower( wchar_t ch ) { return ( wchar_t )towlower( ch ); }
  33. template< typename II, typename CI >
  34. inline void regex_toupper( II ibegin, CI iend )
  35. {
  36.     typedef typename std::iterator_traits<CI>::value_type char_type;
  37.     typedef std::char_traits<char_type> traits_type;
  38.     for( ; iend != ibegin; ++ibegin )
  39.         traits_type::assign( *ibegin, regex_toupper( *ibegin ) );
  40. }
  41. template< typename II, typename CI >
  42. inline void regex_tolower( II ibegin, CI iend )
  43. {
  44.     typedef typename std::iterator_traits<CI>::value_type char_type;
  45.     typedef std::char_traits<char_type> traits_type;
  46.     for( ; iend != ibegin; ++ibegin )
  47.         traits_type::assign( *ibegin, regex_tolower( *ibegin ) );
  48. }
  49. // Work-around for a template-template parameter problem on VC7.0
  50. template<typename T> struct type2type { typedef T type; };
  51. template<bool F> struct bool2type { enum { value = F }; };
  52. typedef bool2type<true>  true_t;
  53. typedef bool2type<false> false_t;
  54. //
  55. // Helper fn for swapping two auto_ptr's
  56. //
  57. template< typename T >
  58. inline void swap_auto_ptr( std::auto_ptr<T> & left, std::auto_ptr<T> & right )
  59. {
  60.     std::auto_ptr<T> temp( left );
  61.     left = right;
  62.     right = temp;
  63. }
  64. // --------------------------------------------------------------------------
  65. //
  66. // Class:       match_param
  67. //
  68. // Description: Struct that contains the state of the matching operation.
  69. //              Passed by reference to all recursive_match_all_ and recursive_match_this routines.
  70. //
  71. // Methods:     match_param - ctor
  72. //              match_param - ctor
  73. //
  74. // Members:     ibegin      - start of the string
  75. //              istart      - start of this iteration
  76. //              istop       - end of the string
  77. //              prgbackrefs - pointer to backref array
  78. //
  79. // History:     8/14/2000 - ericne - Created
  80. //
  81. // --------------------------------------------------------------------------
  82. template< typename CI >
  83. struct match_param
  84. {
  85.     typedef backref_tag< CI >         backref_type;
  86.     typedef std::vector<backref_type> backref_vector;
  87.     // Used by the recursive_match routines
  88.     backref_vector * prgbackrefs;
  89.     CI ibegin;
  90.     CI istart;
  91.     CI istop;
  92.     // Used by the iterative_match routines
  93.     CI icur;
  94.     unsafe_stack * pstack;
  95.     sub_expr_base<CI> const * next;
  96.     bool no0len;
  97.     sub_expr_base<CI> const * first;
  98.     match_param(
  99.         CI _istart,
  100.         CI _istop,
  101.         std::vector< backref_tag< CI > > * _prgbackrefs )
  102.       : prgbackrefs( _prgbackrefs ),
  103.         ibegin( _istart ),
  104.         istart( _istart ),
  105.         istop( _istop ),
  106.         icur( _istart ),
  107.         pstack( NULL ),
  108.         next( NULL ),
  109.         no0len( false )
  110.     {
  111.     }
  112.     match_param(
  113.         CI _ibegin,
  114.         CI _istart,
  115.         CI _istop,
  116.         std::vector< backref_tag< CI > > * _prgbackrefs )
  117.       : prgbackrefs( _prgbackrefs ),
  118.         ibegin( _ibegin ),
  119.         istart( _istart ),
  120.         istop( _istop ),
  121.         icur( _istart ),
  122.         pstack( NULL ),
  123.         next( NULL ),
  124.         no0len( false )
  125.     {
  126.     }
  127. };
  128. // --------------------------------------------------------------------------
  129. //
  130. // Class:       regex_arena
  131. //
  132. // Description: A small, fast allocator for speeding up pattern compilation.
  133. //              Every basic_rpattern object has an arena as a member.
  134. //              sub_expr objects can only be allocated from this arena.
  135. //              Memory is alloc'ed in chunks using ::operator new(). Chunks
  136. //              are freed en-masse when the arena gets destroyed, or when
  137. //              deallocate is explicitly called.
  138. //
  139. // Methods:     _new_block    - create a new block & put it in m_pfirst
  140. //              regex_arena   - c'tor
  141. //              ~regex_arena  - free all memory blocks
  142. //              allocate      - Grab some preallocated memory.
  143. //              deallocate    - free all memory blocks.
  144. //              max_size      - the largest chunk of memory the arena is
  145. //                              capable of allocating.
  146. //
  147. // Members:     m_pfirst      - ptr to first block in list
  148. //
  149. // History:     8/17/2001 - ericne - Created
  150. //
  151. // --------------------------------------------------------------------------
  152. class regex_arena
  153. {
  154.     struct block;
  155.     friend struct block;
  156.     block * m_pfirst;
  157.     size_t m_default_size;
  158.     void _new_block( size_t size ); //throw( std::bad_alloc );
  159.     regex_arena( regex_arena const & );
  160.     regex_arena & operator=( regex_arena const & );
  161. public:
  162.     explicit regex_arena( size_t default_size );
  163.     ~regex_arena();
  164.     void * allocate( size_t size ); //throw( std::bad_alloc );
  165.     void deallocate(); //throw();
  166.     size_t max_size() const;
  167.     void swap( regex_arena & that ); // throw()
  168. };
  169. // --------------------------------------------------------------------------
  170. //
  171. // Class:       sub_expr_base
  172. //
  173. // Description: patterns are "compiled" into a directed graph of sub_expr_base
  174. //              structs.  Matching is accomplished by traversing this graph.
  175. //
  176. // Methods:     ~sub_expr_base - virt dtor so cleanup happens correctly
  177. //              recursive_match_all_      - match this sub-expression and all following
  178. //                               sub-expression
  179. //
  180. // History:     8/14/2000 - ericne - Created
  181. //
  182. // --------------------------------------------------------------------------
  183. template< typename CI >
  184. struct sub_expr_base
  185. {
  186.     virtual ~sub_expr_base() = 0;
  187.     virtual bool recursive_match_all_( match_param<CI> &, CI ) const = 0; //throw() = 0;
  188.     virtual bool recursive_match_all_c( match_param<CI> &, CI ) const = 0; //throw() = 0;
  189.     virtual bool iterative_match_this_( match_param<CI> & ) const = 0; //throw() = 0;
  190.     virtual bool iterative_match_this_c( match_param<CI> & ) const = 0; //throw() = 0;
  191.     virtual bool iterative_rematch_this_( match_param<CI> & ) const = 0; //throw() = 0;
  192.     virtual bool iterative_rematch_this_c( match_param<CI> & ) const = 0; //throw() = 0;
  193.     // Use the regex_arena for memory management
  194.     static void * operator new( size_t size, regex_arena & arena )
  195.     {
  196.         return arena.allocate( size );
  197.     }
  198.     static void operator delete( void *, regex_arena & )
  199.     {
  200.     }
  201.     // Invoke the d'tor, but don't bother freeing memory. That will
  202.     // happen automatically when the arena object gets destroyed.
  203.     static void operator delete( void * )
  204.     {
  205.     }
  206.     // For choosing an appropriate virtual function based on a compile time constant
  207.     bool recursive_match_all_( match_param<CI> & param, CI icur, false_t ) const //throw()
  208.     {
  209.         return recursive_match_all_( param, icur );
  210.     }
  211.     bool recursive_match_all_( match_param<CI> & param, CI icur, true_t ) const //throw()
  212.     {
  213.         return recursive_match_all_c( param, icur );
  214.     }
  215.     bool iterative_match_this_( match_param<CI> & param, false_t ) const //throw()
  216.     {
  217.         return iterative_match_this_( param );
  218.     }
  219.     bool iterative_match_this_( match_param<CI> & param, true_t ) const //throw()
  220.     {
  221.         return iterative_match_this_c( param );
  222.     }
  223.     bool iterative_rematch_this_( match_param<CI> & param, false_t ) const //throw()
  224.     {
  225.         return iterative_rematch_this_( param );
  226.     }
  227.     bool iterative_rematch_this_( match_param<CI> & param, true_t ) const //throw()
  228.     {
  229.         return iterative_rematch_this_c( param );
  230.     }
  231. };
  232. template< typename CI >
  233. inline sub_expr_base<CI>::~sub_expr_base()
  234. {
  235. }
  236. // --------------------------------------------------------------------------
  237. //
  238. // Class:       subst_node
  239. //
  240. // Description: Substitution strings are parsed into an array of these
  241. //              structures in order to speed up subst operations.
  242. //
  243. // Members:     stype         - type of this struct
  244. //              subst_string  - do a string substitution
  245. //              subst_backref - do a bacref substitution
  246. //              op            - execute an operation
  247. //
  248. // History:     8/14/2000 - ericne - Created
  249. //
  250. // --------------------------------------------------------------------------
  251. struct subst_node
  252. {
  253.     enum subst_type
  254.     {
  255.         SUBST_STRING,
  256.         SUBST_BACKREF,
  257.         SUBST_OP
  258.     };
  259.     enum { PREMATCH = -1, POSTMATCH = -2 };
  260.     enum op_type
  261.     {
  262.         UPPER_ON   = SUBST_UPPER_ON,
  263.         UPPER_NEXT = SUBST_UPPER_NEXT,
  264.         LOWER_ON   = SUBST_LOWER_ON,
  265.         LOWER_NEXT = SUBST_LOWER_NEXT,
  266.         ALL_OFF    = SUBST_ALL_OFF
  267.     };
  268.     subst_type stype;
  269.     union
  270.     {
  271.         struct
  272.         {
  273.             size_t rstart;
  274.             size_t rlength;
  275.         } subst_string;
  276.         size_t  subst_backref;
  277.         op_type op;
  278.     };
  279. };
  280. typedef std::list<subst_node> subst_list_type;
  281. size_t DEFAULT_BLOCK_SIZE();
  282. // --------------------------------------------------------------------------
  283. //
  284. // Class:       basic_rpattern_base_impl
  285. //
  286. // Description:
  287. //
  288. // Methods:     basic_rpattern_base_impl - ctor
  289. //              flags                   - get the state of the flags
  290. //              uses_backrefs           - true if the backrefs are referenced
  291. //              get_first_subexpression - return ptr to first sub_expr struct
  292. //              get_width               - get min/max nbr chars this pattern can match
  293. //              loops                   - if false, we only need to try to match at 1st position
  294. //              cgroups                 - number of visible groups
  295. //              _cgroups_total          - total number of groups, including hidden ( ?: ) groups
  296. //              get_pat                 - get string representing the pattern
  297. //              get_subst               - get string representing the substitution string
  298. //              get_subst_list          - get the list of subst nodes
  299. //              _normalize_string       - perform character escaping
  300. //
  301. // Members:     m_fuses_backrefs        - true if subst string refers to backrefs
  302. //              m_floop                 - false if pat only needs to be matched in one place
  303. //              m_cgroups               - total count of groups
  304. //              m_cgroups_visible       - count of visible groups
  305. //              m_flags                 - the flags
  306. //              m_nwidth                - width of this pattern
  307. //              m_pat                   - pattern string
  308. //              m_subst                 - substitution string
  309. //              m_subst_list            - list of substitution nodes
  310. //              m_pfirst                - ptr to first subexpression to match
  311. //
  312. // Typedefs:    char_type               -
  313. //              string_type             -
  314. //              size_type               -
  315. //
  316. // History:     8/14/2000 - ericne - Created
  317. //
  318. // --------------------------------------------------------------------------
  319. template< typename CI >
  320. class basic_rpattern_base_impl
  321. {
  322.     basic_rpattern_base_impl( basic_rpattern_base_impl<CI> const & );
  323.     basic_rpattern_base_impl & operator=( basic_rpattern_base_impl<CI> const & );
  324. protected:
  325.     typedef typename std::iterator_traits<CI>::value_type char_type;
  326.     typedef std::char_traits<char_type>                   traits_type;
  327.     typedef std::basic_string<char_type>                  string_type;
  328.     typedef size_t                                        size_type;
  329.     typedef backref_tag<CI>                               backref_type;
  330.     typedef std::vector<backref_type>                     backref_vector;
  331.     explicit basic_rpattern_base_impl(
  332.         REGEX_FLAGS flags = NOFLAGS,
  333.         REGEX_MODE mode = MODE_DEFAULT,
  334.         string_type const & pat   = string_type(),
  335.         string_type const & subst = string_type() ) //throw()
  336.       : m_arena( DEFAULT_BLOCK_SIZE() ),
  337.         m_fuses_backrefs( false ),
  338.         m_floop( true ),
  339.         m_fok_to_recurse( true ),
  340.         m_cgroups( 0 ),
  341.         m_cgroups_visible( 0 ),
  342.         m_flags( flags ),
  343.         m_mode( mode ),
  344.         m_nwidth( uninit_width() ),
  345.         m_pat( new string_type( pat ) ),
  346.         m_subst( new string_type( subst ) ),
  347.         m_subst_list(),
  348.         m_pfirst( NULL ),
  349.         m_invisible_groups()
  350.     {
  351.     }
  352.     virtual ~basic_rpattern_base_impl();
  353.     regex_arena m_arena;           // The sub_expr arena
  354.     bool        m_fuses_backrefs;  // true if the substitution uses backrefs
  355.     bool        m_floop;           // false if m_pfirst->recursive_match_all_ only needs to be called once
  356.     bool        m_fok_to_recurse;  // false if the pattern would recurse too deeply
  357.     size_t      m_cgroups;         // number of groups ( always at least one )
  358.     size_t      m_cgroups_visible; // number of visible groups
  359.     REGEX_FLAGS m_flags;           // flags used to customize search/replace
  360.     REGEX_MODE  m_mode;            // Used to pick the fast or safe algorithm
  361.     width_type  m_nwidth;          // width of the pattern
  362.     std::auto_ptr<string_type> m_pat;   // contains the unparsed pattern
  363.     std::auto_ptr<string_type> m_subst; // contains the unparsed substitution
  364.     subst_list_type m_subst_list; // used to speed up substitution
  365.     std::auto_ptr<sub_expr_base<CI> const> m_pfirst;     // first subexpression in pattern
  366.     std::list<size_t> m_invisible_groups; // groups w/o backrefs
  367.     size_t _cgroups_total() const //throw()
  368.     {
  369.         return m_cgroups;
  370.     }
  371.     bool _loops() const //throw()
  372.     {
  373.         return m_floop;
  374.     }
  375.     size_t _get_next_group_nbr()
  376.     {
  377.         return m_cgroups++;
  378.     }
  379.     void _normalize_string( string_type & str ) const //throw()
  380.     {
  381.         if( NORMALIZE & flags() )
  382.             process_escapes( str, true );
  383.     }
  384.     bool _save_backrefs() const //throw()
  385.     {
  386.         return m_fuses_backrefs || ! ( flags() & NOBACKREFS );
  387.     }
  388.     sub_expr_base<CI> const * _get_first_subexpression() const //throw()
  389.     {
  390.         return m_pfirst.get();
  391.     }
  392.     bool _ok_to_recurse() const //throw()
  393.     {
  394.         switch( m_mode )
  395.         {
  396.         case MODE_FAST:
  397.             return true;
  398.         case MODE_SAFE:
  399.             return false;
  400.         case MODE_MIXED:
  401.             return m_fok_to_recurse;
  402.         default:
  403.             return false;
  404.         }
  405.     }
  406.     // These are virtual so that when the instantiator object implicitly
  407.     // instantiates this template, these functions still get external linkage.
  408.     virtual bool   _do_match( match_param<CI> & param, bool use_null ) const;
  409.     virtual bool   _do_match( match_param<CI> & param, char_type const * szbegin ) const;
  410.     virtual size_t _do_count( match_param<CI> & param, bool use_null ) const;
  411.     virtual size_t _do_count( match_param<CI> & param, char_type const * szbegin ) const;
  412.     friend struct matcher_helper<CI>;
  413.     REGEX_FLAGS flags() const //throw()
  414.     {
  415.         return m_flags;
  416.     }
  417.     REGEX_MODE mode() const // throw()
  418.     {
  419.         return m_mode;
  420.     }
  421.     width_type get_width() const //throw()
  422.     {
  423.         return m_nwidth;
  424.     }
  425.     size_t cgroups() const //throw()
  426.     {
  427.         return m_cgroups_visible;
  428.     }
  429.     string_type const & get_pat() const //throw()
  430.     {
  431.         return *m_pat;
  432.     }
  433.     string_type const & get_subst() const //throw()
  434.     {
  435.         return *m_subst;
  436.     }
  437.     void swap( basic_rpattern_base_impl<CI> & that ) // throw()
  438.     {
  439.         std::swap( m_fuses_backrefs, that.m_fuses_backrefs );
  440.         std::swap( m_floop, that.m_floop );
  441.         std::swap( m_fok_to_recurse, that.m_fok_to_recurse );
  442.         std::swap( m_cgroups, that.m_cgroups );
  443.         std::swap( m_cgroups_visible, that.m_cgroups_visible );
  444.         std::swap( m_flags, that.m_flags );
  445.         std::swap( m_mode, that.m_mode );
  446.         std::swap( m_nwidth, that.m_nwidth );
  447.         swap_auto_ptr( m_pat, that.m_pat );
  448.         swap_auto_ptr( m_subst, that.m_subst );
  449.         swap_auto_ptr( m_pfirst, that.m_pfirst );
  450.         m_subst_list.swap( that.m_subst_list );
  451.         m_invisible_groups.swap( m_invisible_groups );
  452.         m_arena.swap( that.m_arena );
  453.     }
  454.     static size_t const npos;
  455. };
  456. template< typename CI >
  457. size_t const basic_rpattern_base_impl<CI>::npos = size_t( -1 );
  458. template< typename CI >
  459. struct matcher_helper
  460. {
  461.     typedef basic_rpattern_base_impl<CI>             rpattern_type;
  462.     typedef typename rpattern_type::size_type        size_type;
  463.     typedef typename rpattern_type::char_type        char_type;
  464.     typedef typename rpattern_type::traits_type      traits_type;
  465.     typedef typename rpattern_type::backref_type     backref_type;
  466.     typedef typename rpattern_type::backref_vector   backref_vector;
  467.     static match_param<CI> init_param( CI ibegin, CI iend, basic_match_results<CI> & results )
  468.     {
  469.         results.ibegin = ibegin;
  470.         return match_param<CI>( ibegin, iend, & results.m_rgbackrefs );
  471.     }
  472.     // Here is the main dispatch loop.  It is responsible for calling
  473.     // match on the current sub-expression and repeating for the next
  474.     // sub-expression. It also backtracks the match when it needs to.
  475.     template< typename CSTRINGS >
  476.     static bool _Do_match_iterative( sub_expr_base<CI> const * expr, match_param<CI> & param, CI icur, CSTRINGS )
  477.     {
  478.         unsafe_stack & s = *param.pstack;
  479.         void * jump_ptr = s.set_jump(); // the bottom of the stack
  480.         param.icur = icur;
  481.         if( ! expr->iterative_match_this_( param, CSTRINGS() ) )
  482.         {
  483.             return false;
  484.         }
  485.         for( ;; )
  486.         {
  487.             do
  488.             {
  489.                 if( param.next == NULL ) // This means we're done
  490.                     if( param.no0len && param.istart == param.icur )
  491.                         goto keep_looking;
  492.                     else
  493.                         return s.long_jump( jump_ptr ), true;
  494.                 s.push( expr );
  495.                 expr = param.next;
  496.             }
  497.             while( expr->iterative_match_this_( param, CSTRINGS() ) );
  498.             do
  499.             {
  500.                 if( jump_ptr == s.set_jump() ) // No more posibilities to try
  501.                     return false;
  502.                 s.pop( expr );
  503.     keep_looking:;
  504.             }
  505.             while( ! expr->iterative_rematch_this_( param, CSTRINGS() ) );
  506.         }
  507.     }
  508.     static bool _Do_match_iterative_helper( sub_expr_base<CI> const * expr, match_param<CI> & param, CI icur )
  509.     {
  510.         return _Do_match_iterative( expr, param, icur, false_t() );
  511.     }
  512.     static bool _Do_match_iterative_helper_c( sub_expr_base<CI> const * expr, match_param<CI> & param, CI icur )
  513.     {
  514.         return _Do_match_iterative( expr, param, icur, true_t() );
  515.     }
  516.     static bool _Do_match_recursive( sub_expr_base<CI> const * expr, match_param<CI> & param, CI icur )
  517.     {
  518.         return expr->recursive_match_all_( param, icur );
  519.     }
  520.     static bool _Do_match_recursive_c( sub_expr_base<CI> const * expr, match_param<CI> & param, CI icur )
  521.     {
  522.         return expr->recursive_match_all_c( param, icur );
  523.     }
  524.     static bool _Do_match_impl( rpattern_type const & pat, match_param<CI> & param, bool const use_null )
  525.     {
  526.         typedef std::list<size_t>::const_iterator LCI;
  527.         typedef bool ( *pfndomatch_t )( sub_expr_base<CI> const * expr, match_param<CI> & param, CI icur );
  528.         bool       floop   = pat._loops();
  529.         unsigned   flags   = pat.flags();
  530.         width_type nwidth  = pat.get_width();
  531.         // If the pstack parameter is not NULL, we should do a safe, iterative match.
  532.         // Otherwise, we should do a fast, recursive match.
  533.         pfndomatch_t pfndomatch;
  534.         if( NULL != param.pstack )
  535.             if( use_null )
  536.                 pfndomatch = &_Do_match_iterative_helper_c;
  537.             else
  538.                 pfndomatch = &_Do_match_iterative_helper;
  539.         else
  540.             if( use_null )
  541.                 pfndomatch = &_Do_match_recursive_c;
  542.             else
  543.                 pfndomatch = &_Do_match_recursive;
  544.         sub_expr_base<CI> const * pfirst = pat._get_first_subexpression();
  545.         param.first = pfirst;
  546.         assert( NULL != param.prgbackrefs );
  547.         param.prgbackrefs->resize( pat._cgroups_total() );
  548.         std::fill( param.prgbackrefs->begin(), param.prgbackrefs->end(), backref_type() );
  549. #ifdef _MSC_VER
  550.         __try
  551.         {
  552. #endif
  553.             if( ! use_null )
  554.             {
  555.                 // If the minimum width of the pattern exceeds the width of the
  556.                 // string, a succesful match is impossible
  557.                 if( nwidth.m_min <= ( size_t )std::distance( param.istart, param.istop ) )
  558.                 {
  559.                     CI local_istop = param.istop;
  560.                     std::advance( local_istop, -int( nwidth.m_min ) );
  561.                     if( RIGHTMOST & flags )
  562.                     {
  563.                         // begin trying to match after the last character.
  564.                         // Continue to the beginning
  565.                         for( CI icur = local_istop; icur >= param.istart; --icur, param.no0len = false )
  566.                             if( ( *pfndomatch )( pfirst, param, icur ) )
  567.                                 break; // m_floop not used for rightmost matches
  568.                     }
  569.                     else
  570.                     {
  571.                         // begin trying to match before the first character.
  572.                         // Continue to the end
  573.                         for( CI icur = param.istart; icur <= local_istop; ++icur, param.no0len = false )
  574.                             if( ( *pfndomatch )( pfirst, param, icur ) || ! floop )
  575.                                 break;
  576.                     }
  577.                 }
  578.             }
  579.             else
  580.             {
  581.                 assert( 0 == ( RIGHTMOST & flags ) );
  582.                 // begin trying to match before the first character.
  583.                 // Continue to the end
  584.                 for( CI icur = param.istart; ; ++icur, param.no0len = false )
  585.                 {
  586.                     if( ( *pfndomatch )( pfirst, param, icur ) || ! floop )
  587.                         break;
  588.                     if( traits_type::eq( REGEX_CHAR(char_type,''), *icur ) )
  589.                         break;
  590.                 }
  591.             }
  592. #ifdef _MSC_VER
  593.         }
  594.         __except( REGEX_STACK_OVERFLOW == _exception_code() )
  595.         {
  596.             // we have overflowed the stack. reset the guard page.
  597.             _resetstkoflw();
  598.             // This match fails silently.
  599.             std::fill( param.prgbackrefs->begin(), param.prgbackrefs->end(), backref_tag<CI>() );
  600.         }
  601. #endif
  602.         // Remove information about the "invisible" groups
  603.         if( ( *param.prgbackrefs )[0].matched )
  604.         {
  605.             size_t dropped = 0;
  606.             std::list<size_t> const & l = pat.m_invisible_groups;
  607.             for( LCI curr = l.begin(), next = l.begin(); curr != l.end(); curr = next, ++dropped )
  608.             {
  609.                 if( ++next == l.end() )
  610.                 {
  611.                     std::copy(
  612.                         param.prgbackrefs->begin() + *curr + 1,
  613.                         param.prgbackrefs->end(),
  614.                         param.prgbackrefs->begin() + *curr - dropped );
  615.                 }
  616.                 else
  617.                 {
  618.                     std::copy(
  619.                         param.prgbackrefs->begin() + *curr + 1,
  620.                         param.prgbackrefs->begin() + *next,
  621.                         param.prgbackrefs->begin() + *curr - dropped );
  622.                 }
  623.             }
  624.             param.prgbackrefs->resize( param.prgbackrefs->size() - dropped );
  625.         }
  626.         else
  627.         {
  628.             param.prgbackrefs->resize( param.prgbackrefs->size() - pat.m_invisible_groups.size() );
  629.         }
  630.         return ( *param.prgbackrefs )[0].matched;
  631.     }
  632.     static bool _Do_match_with_stack( rpattern_type const & pat, match_param<CI> & param, bool const use_null );
  633.     static bool _Do_match( rpattern_type const & pat, match_param<CI> & param, bool const use_null )
  634.     {
  635.         if( pat._ok_to_recurse() )
  636.             return _Do_match_impl( pat, param, use_null );
  637.         return _Do_match_with_stack( pat, param, use_null );
  638.     }
  639.     template< typename CH, typename TR, typename AL >
  640.     static size_t _Do_subst_internal(
  641.         std::basic_string<CH, TR, AL> & str,
  642.         basic_subst_results<CH, TR, AL> const & results,
  643.         rpattern_type const & pat,
  644.         size_type strpos,
  645.         size_type strlen )
  646.     {
  647.         typedef subst_list_type::const_iterator LCI;
  648.         enum { UPPER = -1, NIL, LOWER } next = NIL, rest = NIL;
  649.         bool first = true;
  650.         size_t old_strpos = strpos;
  651.         typename std::basic_string<CH, TR, AL>::iterator itstrlen = str.begin();
  652.         std::advance( itstrlen, strpos + strlen );
  653.         std::basic_string<char_type> const & subst = pat.get_subst();
  654.         for( LCI isubst = pat.m_subst_list.begin(); isubst != pat.m_subst_list.end(); ++isubst )
  655.         {
  656.             size_t sublen;
  657.             typename std::basic_string<CH, TR, AL>::const_iterator  itsubpos1; // iter into str
  658.             typename std::basic_string<CH, TR, AL>::const_iterator  itsublen1;
  659.             typename std::basic_string<char_type>::const_iterator   itsubpos2; // iter into subst string
  660.             typename std::basic_string<char_type>::const_iterator   itsublen2;
  661.             typename std::basic_string<CH, TR, AL>::iterator itstrpos = str.begin();
  662.             std::advance( itstrpos, strpos );
  663.             switch( isubst->stype )
  664.             {
  665.             case subst_node::SUBST_STRING:
  666.                 itsubpos2 = subst.begin();
  667.                 std::advance( itsubpos2, isubst->subst_string.rstart );
  668.                 itsublen2 = itsubpos2;
  669.                 std::advance( itsublen2, isubst->subst_string.rlength );
  670.                 if( first )
  671.                     str.replace( itstrpos, itstrlen, itsubpos2, itsublen2 );
  672.                 else
  673.                     str.insert( itstrpos, itsubpos2, itsublen2 );
  674.                 sublen = std::distance( itsubpos2, itsublen2 );
  675.                 break;
  676.             case subst_node::SUBST_BACKREF:
  677.                 switch( isubst->subst_backref )
  678.                 {
  679.                 case subst_node::PREMATCH:
  680.                     itsubpos1 = results.backref_str().begin();
  681.                     itsublen1 = itsubpos1;
  682.                     std::advance( itsublen1, sublen = results.rstart() );
  683.                     break;
  684.                 case subst_node::POSTMATCH:
  685.                     itsubpos1 = results.backref_str().begin();
  686.                     std::advance( itsubpos1, results.rstart() + results.rlength() );
  687.                     itsublen1 = results.backref_str().end();
  688.                     break;
  689.                 default:
  690.                     itsubpos1 = results.backref_str().begin();
  691.                     std::advance( itsubpos1, results.rstart( isubst->subst_backref ) );
  692.                     itsublen1 = itsubpos1;
  693.                     std::advance( itsublen1, results.rlength( isubst->subst_backref ) );
  694.                     break;
  695.                 }
  696.                 if( first )
  697.                     str.replace( itstrpos, itstrlen, itsubpos1, itsublen1 );
  698.                 else
  699.                     str.insert( itstrpos, itsubpos1, itsublen1 );
  700.                 sublen = std::distance( itsubpos1, itsublen1 );
  701.                 break;
  702.             case subst_node::SUBST_OP:
  703.                 switch( isubst->op )
  704.                 {
  705.                 case subst_node::UPPER_ON:
  706.                     rest = UPPER;
  707.                     break;
  708.                 case subst_node::UPPER_NEXT:
  709.                     next = UPPER;
  710.                     break;
  711.                 case subst_node::LOWER_ON:
  712.                     rest = LOWER;
  713.                     break;
  714.                 case subst_node::LOWER_NEXT:
  715.                     next = LOWER;
  716.                     break;
  717.                 case subst_node::ALL_OFF:
  718.                     rest = NIL;
  719.                     break;
  720.                 default:
  721.                     __assume( 0 );
  722.                 }
  723.                 continue; // jump to the next item in the list
  724.                 default:
  725.                     __assume( 0 );
  726.             }
  727.             first = false;
  728.             // Are we upper- or lower-casing this string?
  729.             if( rest )
  730.             {
  731.                 typename std::basic_string<CH, TR, AL>::iterator istart = str.begin();
  732.                 std::advance( istart, strpos );
  733.                 typename std::basic_string<CH, TR, AL>::const_iterator istop = istart;
  734.                 std::advance( istop, sublen );
  735.                 switch( rest )
  736.                 {
  737.                 case UPPER:
  738.                     regex_toupper( istart, istop );
  739.                     break;
  740.                 case LOWER:
  741.                     regex_tolower( istart, istop );
  742.                     break;
  743.                 default:
  744.                     __assume( 0 );
  745.                 }
  746.             }
  747.             // Are we upper- or lower-casing the next character?
  748.             if( next )
  749.             {
  750.                 switch( next )
  751.                 {
  752.                 case UPPER:
  753.                     str[strpos] = regex_toupper( str[strpos] );
  754.                     break;
  755.                 case LOWER:
  756.                     str[strpos] = regex_tolower( str[strpos] );
  757.                     break;
  758.                 default:
  759.                     __assume( 0 );
  760.                 }
  761.                 next = NIL;
  762.             }
  763.             strpos += sublen;
  764.         }
  765.         // If *first* is still true, then we never called str.replace, and the substitution
  766.         // string is empty. Erase the part of the string that the pattern matched.
  767.         if( first )
  768.             str.erase( strpos, strlen );
  769.         // return length of the substitution
  770.         return strpos - old_strpos;
  771.     }
  772.     template< typename CH, typename TR, typename AL >
  773.     static size_t _Do_subst(
  774.         rpattern_type const & pat,
  775.         std::basic_string<CH, TR, AL> & str,
  776.         basic_subst_results<CH, TR, AL> & results,
  777.         size_type pos,
  778.         size_type len )
  779.     {
  780.         typedef std::basic_string<CH, TR, AL> string_type;
  781.         results.m_pbackref_str = pat._save_backrefs() ? &( results.m_backref_str = str ) : &str;
  782.         results.ibegin = results.m_pbackref_str->begin();
  783.         size_t csubst = 0;
  784.         size_type stop_offset = results.m_pbackref_str->size();
  785.         if( len != rpattern_type::npos )
  786.             stop_offset = (std::min)( size_t( pos + len ), stop_offset );
  787.         match_param<CI> param( results.ibegin, results.ibegin, & results.m_rgbackrefs );
  788.         std::advance( param.istart, pos );
  789.         std::advance( param.istop, stop_offset );
  790.         param.ibegin = param.istart;
  791.         if( GLOBAL & pat.flags() )
  792.         {
  793.             bool const fAll   = ( ALLBACKREFS   == ( ALLBACKREFS   & pat.flags() ) );
  794.             bool const fFirst = ( FIRSTBACKREFS == ( FIRSTBACKREFS & pat.flags() ) );
  795.             backref_vector rgtempbackrefs; // temporary vector used if fsave_backrefs
  796.             size_type pos_offset = 0; // keep track of how much the backref_str and
  797.                                     // the current string are out of sync
  798.             while( _Do_match( pat, param, false ) )
  799.             {
  800.                 backref_type const & br = results.m_rgbackrefs[0];
  801.                 ++csubst;
  802.                 size_type match_length = std::distance( br.first, br.second );
  803.                 pos = std::distance( results.ibegin, br.first );
  804.                 size_type subst_length = _Do_subst_internal( str, results, pat, pos + pos_offset, match_length );
  805.                 if( pat._save_backrefs() )
  806.                 {
  807.                     pos += match_length;
  808.                     pos_offset += ( subst_length - match_length );
  809.                     // Handle specially the backref flags
  810.                     if( fFirst )
  811.                         rgtempbackrefs.push_back( br );
  812.                     else if( fAll )
  813.                         rgtempbackrefs.insert( rgtempbackrefs.end(),
  814.                                             param.prgbackrefs->begin(),
  815.                                             param.prgbackrefs->end() );
  816.                     else
  817.                         rgtempbackrefs.swap( *param.prgbackrefs );
  818.                 }
  819.                 else
  820.                 {
  821.                     pos += subst_length;
  822.                     stop_offset += ( subst_length - match_length );
  823.                     results.ibegin = results.m_pbackref_str->begin();
  824.                     // we're not saving backref information, so we don't
  825.                     // need to do any special backref maintenance here
  826.                 }
  827.                 // prevent a pattern that matches 0 characters from matching
  828.                 // again at the same point in the string
  829.                 param.no0len = ( 0 == match_length );
  830.                 param.istart = results.ibegin;
  831.                 std::advance( param.istart, pos ); // ineffecient for bidirectional iterators.
  832.                 param.istop = results.ibegin;
  833.                 std::advance( param.istop, stop_offset ); // ineffecient for bidirectional iterators.
  834.             }
  835.             // If we did special backref handling, swap the backref vectors
  836.             if( pat._save_backrefs() )
  837.             {
  838.                 param.prgbackrefs->swap( rgtempbackrefs );
  839.             }
  840.             else if( ! ( *param.prgbackrefs )[0].matched )
  841.             {
  842.                 param.prgbackrefs->clear();
  843.             }
  844.         }
  845.         else if( _Do_match( pat, param, false ) )
  846.         {
  847.             backref_type const & br = results.m_rgbackrefs[0];
  848.             ++csubst;
  849.             _Do_subst_internal(
  850.                 str, results, pat,
  851.                 std::distance( results.ibegin, br.first ),
  852.                 std::distance( br.first, br.second ) );
  853.             results.ibegin = results.m_pbackref_str->begin();
  854.         }
  855.         if( NOBACKREFS == ( pat.flags() & NOBACKREFS ) )
  856.         {
  857.             param.prgbackrefs->clear();
  858.         }
  859.         return csubst;
  860.     }
  861. };
  862. template< typename CI >
  863. REGEX_NOINLINE bool matcher_helper<CI>::_Do_match_with_stack( rpattern_type const & pat, match_param<CI> & param, bool const use_null )
  864. {
  865.     unsafe_stack s;
  866.     param.pstack = &s;
  867.     return _Do_match_impl( pat, param, use_null );
  868. }
  869. //
  870. // Some helper functions needed by process_escapes
  871. //
  872. template< typename CH >
  873. inline bool regex_isxdigit( CH ch )
  874. {
  875.     return ( REGEX_CHAR(CH,'0') <= ch && REGEX_CHAR(CH,'9') >= ch )
  876.         || ( REGEX_CHAR(CH,'a') <= ch && REGEX_CHAR(CH,'f') >= ch )
  877.         || ( REGEX_CHAR(CH,'A') <= ch && REGEX_CHAR(CH,'F') >= ch );
  878. }
  879. template< typename CH >
  880. inline int regex_xdigit2int( CH ch )
  881. {
  882.     if( REGEX_CHAR(CH,'a') <= ch && REGEX_CHAR(CH,'f') >= ch )
  883.         return ch - REGEX_CHAR(CH,'a') + 10;
  884.     if( REGEX_CHAR(CH,'A') <= ch && REGEX_CHAR(CH,'F') >= ch )
  885.         return ch - REGEX_CHAR(CH,'A') + 10;
  886.     return ch - REGEX_CHAR(CH,'0');
  887. }
  888. } // namespace detail
  889. // --------------------------------------------------------------------------
  890. //
  891. // Function:    process_escapes
  892. //
  893. // Description: Turn the escape sequnces f n r t v \ into their
  894. //              ASCII character equivalents. Also, optionally process
  895. //              perl escape sequences.
  896. //
  897. // Returns:     void
  898. //
  899. // Arguments:   str      - the string to process
  900. //              fPattern - true if the string is to be processed as a regex
  901. //
  902. // Notes:       When fPattern is true, the perl escape sequences are not
  903. //              processed.  If there is an octal or hex excape sequence, we
  904. //              don't want to turn it into a regex metacharacter here.  We
  905. //              leave it unescaped so the regex parser correctly interprests
  906. //              it as a character literal.
  907. //
  908. // History:     8/1/2001 - ericne - Created
  909. //
  910. // --------------------------------------------------------------------------
  911. template< typename CH, typename TR, typename AL >
  912. inline void process_escapes( std::basic_string<CH, TR, AL> & str, bool fPattern ) //throw()
  913. {
  914.     typedef typename std::basic_string<CH, TR, AL>::size_type size_type;
  915.     size_type i = 0;
  916.     size_type const npos = std::basic_string<CH, TR, AL>::npos;
  917.     if( str.empty() )
  918.         return;
  919.     while( npos != ( i = str.find( REGEX_CHAR(CH,'\'), i ) ) )
  920.     {
  921.         if( str.size() - 1 == i )
  922.             return;
  923.         switch( str[i+1] )
  924.         {
  925.         case REGEX_CHAR(CH,'a'):
  926.             str.replace( i, 2, 1, REGEX_CHAR(CH,'a') );
  927.             break;
  928.         case REGEX_CHAR(CH,'b'):
  929.             if( ! fPattern )
  930.                 str.replace( i, 2, 1, REGEX_CHAR(CH,'b') );
  931.             else
  932.                 ++i;
  933.             break;
  934.         case REGEX_CHAR(CH,'e'):
  935.             str.replace( i, 2, 1, CH( 27 ) );
  936.             break;
  937.         case REGEX_CHAR(CH,'f'):
  938.             str.replace( i, 2, 1, REGEX_CHAR(CH,'f') );
  939.             break;
  940.         case REGEX_CHAR(CH,'n'):
  941.             str.replace( i, 2, 1, REGEX_CHAR(CH,'n') );
  942.             break;
  943.         case REGEX_CHAR(CH,'r'):
  944.             str.replace( i, 2, 1, REGEX_CHAR(CH,'r') );
  945.             break;
  946.         case REGEX_CHAR(CH,'t'):
  947.             str.replace( i, 2, 1, REGEX_CHAR(CH,'t') );
  948.             break;
  949.         case REGEX_CHAR(CH,'v'):
  950.             str.replace( i, 2, 1, REGEX_CHAR(CH,'v') );
  951.             break;
  952.         case REGEX_CHAR(CH,'\'):
  953.             if( fPattern )
  954.             {
  955.                 if( i+3 < str.size() && REGEX_CHAR(CH,'\') == str[i+2] && REGEX_CHAR(CH,'\') == str[i+3] )
  956.                     str.erase( i, 2 );
  957.                 ++i;
  958.             }
  959.             else
  960.                 str.erase( i, 1 );
  961.             break;
  962.         case REGEX_CHAR(CH,'0'): case REGEX_CHAR(CH,'1'): case REGEX_CHAR(CH,'2'): case REGEX_CHAR(CH,'3'):
  963.         case REGEX_CHAR(CH,'4'): case REGEX_CHAR(CH,'5'): case REGEX_CHAR(CH,'6'): case REGEX_CHAR(CH,'7'):
  964.             if( ! fPattern )
  965.             {
  966.                 size_t j=i+2;
  967.                 CH ch = CH( str[i+1] - REGEX_CHAR(CH,'0') );
  968.                 for( ; j-i < 4 && j < str.size() && REGEX_CHAR(CH,'0') <= str[j] && REGEX_CHAR(CH,'7') >= str[j]; ++j )
  969.                     ch = CH( ch * 8 + ( str[j] - REGEX_CHAR(CH,'0') ) );
  970.                 str.replace( i, j-i, 1, ch );
  971.             }
  972.             break;
  973.         case REGEX_CHAR(CH,'x'):
  974.             if( ! fPattern )
  975.             {
  976.                 CH ch = 0;
  977.                 size_t j=i+2;
  978.                 for( ; j-i < 4 && j < str.size() && detail::regex_isxdigit( str[j] ); ++j )
  979.                     ch = CH( ch * 16 + detail::regex_xdigit2int( str[j] ) );
  980.                 str.replace( i, j-i, 1, ch );
  981.             }
  982.             break;
  983.         case REGEX_CHAR(CH,'c'):
  984.             if( ! fPattern && i+2 < str.size() )
  985.             {
  986.                 CH ch = str[i+2];
  987.                 if( REGEX_CHAR(CH,'a') <= ch && REGEX_CHAR(CH,'z') >= ch )
  988.                     ch = detail::regex_toupper( ch );
  989.                 str.replace( i, 3, 1, CH( ch ^ 0x40 ) );
  990.             }
  991.             break;
  992.         default:
  993.             if( fPattern )
  994.                 ++i;
  995.             else
  996.                 str.erase( i, 1 );
  997.             break;
  998.         }
  999.         ++i;
  1000.         if( str.size() <= i )
  1001.             return;
  1002.     }
  1003. }
  1004. #ifndef _MSC_VER
  1005. #undef __assume
  1006. #endif
  1007. #endif