1157 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			1157 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| /*
 | |
|  *
 | |
|  * Copyright (c) 1998-2009 John Maddock
 | |
|  * Copyright 2008 Eric Niebler. 
 | |
|  *
 | |
|  * 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         regex_format.hpp
 | |
|   *   VERSION      see <boost/version.hpp>
 | |
|   *   DESCRIPTION: Provides formatting output routines for search and replace
 | |
|   *                operations.  Note this is an internal header file included
 | |
|   *                by regex.hpp, do not include on its own.
 | |
|   */
 | |
| 
 | |
| #ifndef BOOST_REGEX_FORMAT_HPP
 | |
| #define BOOST_REGEX_FORMAT_HPP
 | |
| 
 | |
| #include <boost/type_traits/is_pointer.hpp>
 | |
| #include <boost/type_traits/is_function.hpp>
 | |
| #include <boost/type_traits/is_class.hpp>
 | |
| #include <boost/type_traits/is_same.hpp>
 | |
| #include <boost/type_traits/is_convertible.hpp>
 | |
| #include <boost/type_traits/remove_pointer.hpp>
 | |
| #include <boost/type_traits/remove_cv.hpp>
 | |
| #include <boost/mpl/if.hpp>
 | |
| #include <boost/mpl/and.hpp>
 | |
| #include <boost/mpl/not.hpp>
 | |
| #ifndef BOOST_NO_SFINAE
 | |
| #include <boost/mpl/has_xxx.hpp>
 | |
| #endif
 | |
| #include <boost/ref.hpp>
 | |
| 
 | |
| namespace boost{
 | |
| 
 | |
| #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
 | |
| 
 | |
| //
 | |
| // Forward declaration:
 | |
| //
 | |
|    template <class BidiIterator, class Allocator = BOOST_DEDUCED_TYPENAME std::vector<sub_match<BidiIterator> >::allocator_type >
 | |
| class match_results;
 | |
| 
 | |
| namespace BOOST_REGEX_DETAIL_NS{
 | |
| 
 | |
| //
 | |
| // struct trivial_format_traits:
 | |
| // defines minimum localisation support for formatting
 | |
| // in the case that the actual regex traits is unavailable.
 | |
| //
 | |
| template <class charT>
 | |
| struct trivial_format_traits
 | |
| {
 | |
|    typedef charT char_type;
 | |
| 
 | |
|    static std::ptrdiff_t length(const charT* p)
 | |
|    {
 | |
|       return global_length(p);
 | |
|    }
 | |
|    static charT tolower(charT c)
 | |
|    {
 | |
|       return ::boost::BOOST_REGEX_DETAIL_NS::global_lower(c);
 | |
|    }
 | |
|    static charT toupper(charT c)
 | |
|    {
 | |
|       return ::boost::BOOST_REGEX_DETAIL_NS::global_upper(c);
 | |
|    }
 | |
|    static int value(const charT c, int radix)
 | |
|    {
 | |
|       int result = global_value(c);
 | |
|       return result >= radix ? -1 : result;
 | |
|    }
 | |
|    int toi(const charT*& p1, const charT* p2, int radix)const
 | |
|    {
 | |
|       return (int)global_toi(p1, p2, radix, *this);
 | |
|    }
 | |
| };
 | |
| 
 | |
| template <class OutputIterator, class Results, class traits, class ForwardIter>
 | |
| class basic_regex_formatter
 | |
| {
 | |
| public:
 | |
|    typedef typename traits::char_type char_type;
 | |
|    basic_regex_formatter(OutputIterator o, const Results& r, const traits& t)
 | |
|       : m_traits(t), m_results(r), m_out(o), m_position(), m_end(), m_flags(), m_state(output_copy), m_restore_state(output_copy), m_have_conditional(false) {}
 | |
|    OutputIterator format(ForwardIter p1, ForwardIter p2, match_flag_type f);
 | |
|    OutputIterator format(ForwardIter p1, match_flag_type f)
 | |
|    {
 | |
|       return format(p1, p1 + m_traits.length(p1), f);
 | |
|    }
 | |
| private:
 | |
|    typedef typename Results::value_type sub_match_type;
 | |
|    enum output_state
 | |
|    {
 | |
|       output_copy,
 | |
|       output_next_lower,
 | |
|       output_next_upper,
 | |
|       output_lower,
 | |
|       output_upper,
 | |
|       output_none
 | |
|    };
 | |
| 
 | |
|    void put(char_type c);
 | |
|    void put(const sub_match_type& sub);
 | |
|    void format_all();
 | |
|    void format_perl();
 | |
|    void format_escape();
 | |
|    void format_conditional();
 | |
|    void format_until_scope_end();
 | |
|    bool handle_perl_verb(bool have_brace);
 | |
| 
 | |
|    inline typename Results::value_type const& get_named_sub(ForwardIter i, ForwardIter j, const mpl::false_&)
 | |
|    {
 | |
|       std::vector<char_type> v(i, j);
 | |
|       return (i != j) ? this->m_results.named_subexpression(&v[0], &v[0] + v.size())
 | |
|          : this->m_results.named_subexpression(static_cast<const char_type*>(0), static_cast<const char_type*>(0));
 | |
|    }
 | |
|    inline typename Results::value_type const& get_named_sub(ForwardIter i, ForwardIter j, const mpl::true_&)
 | |
|    {
 | |
|       return this->m_results.named_subexpression(i, j);
 | |
|    }
 | |
|    inline typename Results::value_type const& get_named_sub(ForwardIter i, ForwardIter j)
 | |
|    {
 | |
|       typedef typename boost::is_convertible<ForwardIter, const char_type*>::type tag_type;
 | |
|       return get_named_sub(i, j, tag_type());
 | |
|    }
 | |
|    inline int get_named_sub_index(ForwardIter i, ForwardIter j, const mpl::false_&)
 | |
|    {
 | |
|       std::vector<char_type> v(i, j);
 | |
|       return (i != j) ? this->m_results.named_subexpression_index(&v[0], &v[0] + v.size())
 | |
|          : this->m_results.named_subexpression_index(static_cast<const char_type*>(0), static_cast<const char_type*>(0));
 | |
|    }
 | |
|    inline int get_named_sub_index(ForwardIter i, ForwardIter j, const mpl::true_&)
 | |
|    {
 | |
|       return this->m_results.named_subexpression_index(i, j);
 | |
|    }
 | |
|    inline int get_named_sub_index(ForwardIter i, ForwardIter j)
 | |
|    {
 | |
|       typedef typename boost::is_convertible<ForwardIter, const char_type*>::type tag_type;
 | |
|       return get_named_sub_index(i, j, tag_type());
 | |
|    }
 | |
| #ifdef BOOST_MSVC
 | |
|    // msvc-8.0 issues a spurious warning on the call to std::advance here:
 | |
| #pragma warning(push)
 | |
| #pragma warning(disable:4244)
 | |
| #endif
 | |
|    inline int toi(ForwardIter& i, ForwardIter j, int base, const boost::mpl::false_&)
 | |
|    {
 | |
|       if(i != j)
 | |
|       {
 | |
|          std::vector<char_type> v(i, j);
 | |
|          const char_type* start = &v[0];
 | |
|          const char_type* pos = start;
 | |
|          int r = (int)m_traits.toi(pos, &v[0] + v.size(), base);
 | |
|          std::advance(i, pos - start);
 | |
|          return r;
 | |
|       }
 | |
|       return -1;
 | |
|    }
 | |
| #ifdef BOOST_MSVC
 | |
| #pragma warning(pop)
 | |
| #endif
 | |
|    inline int toi(ForwardIter& i, ForwardIter j, int base, const boost::mpl::true_&)
 | |
|    {
 | |
|       return m_traits.toi(i, j, base);
 | |
|    }
 | |
|    inline int toi(ForwardIter& i, ForwardIter j, int base)
 | |
|    {
 | |
| #if defined(_MSC_VER) && defined(__INTEL_COMPILER) && ((__INTEL_COMPILER == 9999) || (__INTEL_COMPILER == 1210))
 | |
|       // Workaround for Intel support issue #656654.
 | |
|       // See also https://svn.boost.org/trac/boost/ticket/6359
 | |
|       return toi(i, j, base, mpl::false_());
 | |
| #else
 | |
|       typedef typename boost::is_convertible<ForwardIter, const char_type*&>::type tag_type;
 | |
|       return toi(i, j, base, tag_type());
 | |
| #endif
 | |
|    }
 | |
| 
 | |
|    const traits&    m_traits;       // the traits class for localised formatting operations
 | |
|    const Results&   m_results;     // the match_results being used.
 | |
|    OutputIterator   m_out;         // where to send output.
 | |
|    ForwardIter      m_position;  // format string, current position
 | |
|    ForwardIter      m_end;       // format string end
 | |
|    match_flag_type  m_flags;      // format flags to use
 | |
|    output_state     m_state;      // what to do with the next character
 | |
|    output_state     m_restore_state;  // what state to restore to.
 | |
|    bool             m_have_conditional; // we are parsing a conditional
 | |
| private:
 | |
|    basic_regex_formatter(const basic_regex_formatter&);
 | |
|    basic_regex_formatter& operator=(const basic_regex_formatter&);
 | |
| };
 | |
| 
 | |
| template <class OutputIterator, class Results, class traits, class ForwardIter>
 | |
| OutputIterator basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format(ForwardIter p1, ForwardIter p2, match_flag_type f)
 | |
| {
 | |
|    m_position = p1;
 | |
|    m_end = p2;
 | |
|    m_flags = f;
 | |
|    format_all();
 | |
|    return m_out;
 | |
| }
 | |
| 
 | |
| template <class OutputIterator, class Results, class traits, class ForwardIter>
 | |
| void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_all()
 | |
| {
 | |
|    // over and over:
 | |
|    while(m_position != m_end)
 | |
|    {
 | |
|       switch(*m_position)
 | |
|       {
 | |
|       case '&':
 | |
|          if(m_flags & ::boost::regex_constants::format_sed)
 | |
|          {
 | |
|             ++m_position;
 | |
|             put(m_results[0]);
 | |
|             break;
 | |
|          }
 | |
|          put(*m_position++);
 | |
|          break;
 | |
|       case '\\':
 | |
|          format_escape();
 | |
|          break;
 | |
|       case '(':
 | |
|          if(m_flags & boost::regex_constants::format_all)
 | |
|          {
 | |
|             ++m_position;
 | |
|             bool have_conditional = m_have_conditional;
 | |
|             m_have_conditional = false;
 | |
|             format_until_scope_end();
 | |
|             m_have_conditional = have_conditional;
 | |
|             if(m_position == m_end)
 | |
|                return;
 | |
|             BOOST_ASSERT(*m_position == static_cast<char_type>(')'));
 | |
|             ++m_position;  // skip the closing ')'
 | |
|             break;
 | |
|          }
 | |
|          put(*m_position);
 | |
|          ++m_position;
 | |
|          break;
 | |
|       case ')':
 | |
|          if(m_flags & boost::regex_constants::format_all)
 | |
|          {
 | |
|             return;
 | |
|          }
 | |
|          put(*m_position);
 | |
|          ++m_position;
 | |
|          break;
 | |
|       case ':':
 | |
|          if((m_flags & boost::regex_constants::format_all) && m_have_conditional)
 | |
|          {
 | |
|             return;
 | |
|          }
 | |
|          put(*m_position);
 | |
|          ++m_position;
 | |
|          break;
 | |
|       case '?':
 | |
|          if(m_flags & boost::regex_constants::format_all)
 | |
|          {
 | |
|             ++m_position;
 | |
|             format_conditional();
 | |
|             break;
 | |
|          }
 | |
|          put(*m_position);
 | |
|          ++m_position;
 | |
|          break;
 | |
|       case '$':
 | |
|          if((m_flags & format_sed) == 0)
 | |
|          {
 | |
|             format_perl();
 | |
|             break;
 | |
|          }
 | |
|          // not a special character:
 | |
|          BOOST_FALLTHROUGH;
 | |
|       default:
 | |
|          put(*m_position);
 | |
|          ++m_position;
 | |
|          break;
 | |
|       }
 | |
|    }
 | |
| }
 | |
| 
 | |
| template <class OutputIterator, class Results, class traits, class ForwardIter>
 | |
| void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_perl()
 | |
| {
 | |
|    //
 | |
|    // On entry *m_position points to a '$' character
 | |
|    // output the information that goes with it:
 | |
|    //
 | |
|    BOOST_ASSERT(*m_position == '$');
 | |
|    //
 | |
|    // see if this is a trailing '$':
 | |
|    //
 | |
|    if(++m_position == m_end)
 | |
|    {
 | |
|       --m_position;
 | |
|       put(*m_position);
 | |
|       ++m_position;
 | |
|       return;
 | |
|    }
 | |
|    //
 | |
|    // OK find out what kind it is:
 | |
|    //
 | |
|    bool have_brace = false;
 | |
|    ForwardIter save_position = m_position;
 | |
|    switch(*m_position)
 | |
|    {
 | |
|    case '&':
 | |
|       ++m_position;
 | |
|       put(this->m_results[0]);
 | |
|       break;
 | |
|    case '`':
 | |
|       ++m_position;
 | |
|       put(this->m_results.prefix());
 | |
|       break;
 | |
|    case '\'':
 | |
|       ++m_position;
 | |
|       put(this->m_results.suffix());
 | |
|       break;
 | |
|    case '$':
 | |
|       put(*m_position++);
 | |
|       break;
 | |
|    case '+':
 | |
|       if((++m_position != m_end) && (*m_position == '{'))
 | |
|       {
 | |
|          ForwardIter base = ++m_position;
 | |
|          while((m_position != m_end) && (*m_position != '}')) ++m_position;
 | |
|          if(m_position != m_end)
 | |
|          {
 | |
|             // Named sub-expression:
 | |
|             put(get_named_sub(base, m_position));
 | |
|             ++m_position;
 | |
|             break;
 | |
|          }
 | |
|          else
 | |
|          {
 | |
|             m_position = --base;
 | |
|          }
 | |
|       }
 | |
|       put((this->m_results)[this->m_results.size() > 1 ? static_cast<int>(this->m_results.size() - 1) : 1]);
 | |
|       break;
 | |
|    case '{':
 | |
|       have_brace = true;
 | |
|       ++m_position;
 | |
|       BOOST_FALLTHROUGH;
 | |
|    default:
 | |
|       // see if we have a number:
 | |
|       {
 | |
|          std::ptrdiff_t len = ::boost::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end);
 | |
|          //len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
 | |
|          int v = this->toi(m_position, m_position + len, 10);
 | |
|          if((v < 0) || (have_brace && ((m_position == m_end) || (*m_position != '}'))))
 | |
|          {
 | |
|             // Look for a Perl-5.10 verb:
 | |
|             if(!handle_perl_verb(have_brace))
 | |
|             {
 | |
|                // leave the $ as is, and carry on:
 | |
|                m_position = --save_position;
 | |
|                put(*m_position);
 | |
|                ++m_position;
 | |
|             }
 | |
|             break;
 | |
|          }
 | |
|          // otherwise output sub v:
 | |
|          put(this->m_results[v]);
 | |
|          if(have_brace)
 | |
|             ++m_position;
 | |
|       }
 | |
|    }
 | |
| }
 | |
| 
 | |
| template <class OutputIterator, class Results, class traits, class ForwardIter>
 | |
| bool basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::handle_perl_verb(bool have_brace)
 | |
| {
 | |
|    // 
 | |
|    // We may have a capitalised string containing a Perl action:
 | |
|    //
 | |
|    static const char_type MATCH[] = { 'M', 'A', 'T', 'C', 'H' };
 | |
|    static const char_type PREMATCH[] = { 'P', 'R', 'E', 'M', 'A', 'T', 'C', 'H' };
 | |
|    static const char_type POSTMATCH[] = { 'P', 'O', 'S', 'T', 'M', 'A', 'T', 'C', 'H' };
 | |
|    static const char_type LAST_PAREN_MATCH[] = { 'L', 'A', 'S', 'T', '_', 'P', 'A', 'R', 'E', 'N', '_', 'M', 'A', 'T', 'C', 'H' };
 | |
|    static const char_type LAST_SUBMATCH_RESULT[] = { 'L', 'A', 'S', 'T', '_', 'S', 'U', 'B', 'M', 'A', 'T', 'C', 'H', '_', 'R', 'E', 'S', 'U', 'L', 'T' };
 | |
|    static const char_type LAST_SUBMATCH_RESULT_ALT[] = { '^', 'N' };
 | |
| 
 | |
|    if(m_position == m_end)
 | |
|       return false;
 | |
|    if(have_brace && (*m_position == '^'))
 | |
|       ++m_position;
 | |
| 
 | |
|    std::ptrdiff_t max_len = m_end - m_position;
 | |
| 
 | |
|    if((max_len >= 5) && std::equal(m_position, m_position + 5, MATCH))
 | |
|    {
 | |
|       m_position += 5;
 | |
|       if(have_brace)
 | |
|       {
 | |
|          if((m_position != m_end) && (*m_position == '}'))
 | |
|             ++m_position;
 | |
|          else
 | |
|          {
 | |
|             m_position -= 5;
 | |
|             return false;
 | |
|          }
 | |
|       }
 | |
|       put(this->m_results[0]);
 | |
|       return true;
 | |
|    }
 | |
|    if((max_len >= 8) && std::equal(m_position, m_position + 8, PREMATCH))
 | |
|    {
 | |
|       m_position += 8;
 | |
|       if(have_brace)
 | |
|       {
 | |
|          if((m_position != m_end) && (*m_position == '}'))
 | |
|             ++m_position;
 | |
|          else
 | |
|          {
 | |
|             m_position -= 8;
 | |
|             return false;
 | |
|          }
 | |
|       }
 | |
|       put(this->m_results.prefix());
 | |
|       return true;
 | |
|    }
 | |
|    if((max_len >= 9) && std::equal(m_position, m_position + 9, POSTMATCH))
 | |
|    {
 | |
|       m_position += 9;
 | |
|       if(have_brace)
 | |
|       {
 | |
|          if((m_position != m_end) && (*m_position == '}'))
 | |
|             ++m_position;
 | |
|          else
 | |
|          {
 | |
|             m_position -= 9;
 | |
|             return false;
 | |
|          }
 | |
|       }
 | |
|       put(this->m_results.suffix());
 | |
|       return true;
 | |
|    }
 | |
|    if((max_len >= 16) && std::equal(m_position, m_position + 16, LAST_PAREN_MATCH))
 | |
|    {
 | |
|       m_position += 16;
 | |
|       if(have_brace)
 | |
|       {
 | |
|          if((m_position != m_end) && (*m_position == '}'))
 | |
|             ++m_position;
 | |
|          else
 | |
|          {
 | |
|             m_position -= 16;
 | |
|             return false;
 | |
|          }
 | |
|       }
 | |
|       put((this->m_results)[this->m_results.size() > 1 ? static_cast<int>(this->m_results.size() - 1) : 1]);
 | |
|       return true;
 | |
|    }
 | |
|    if((max_len >= 20) && std::equal(m_position, m_position + 20, LAST_SUBMATCH_RESULT))
 | |
|    {
 | |
|       m_position += 20;
 | |
|       if(have_brace)
 | |
|       {
 | |
|          if((m_position != m_end) && (*m_position == '}'))
 | |
|             ++m_position;
 | |
|          else
 | |
|          {
 | |
|             m_position -= 20;
 | |
|             return false;
 | |
|          }
 | |
|       }
 | |
|       put(this->m_results.get_last_closed_paren());
 | |
|       return true;
 | |
|    }
 | |
|    if((max_len >= 2) && std::equal(m_position, m_position + 2, LAST_SUBMATCH_RESULT_ALT))
 | |
|    {
 | |
|       m_position += 2;
 | |
|       if(have_brace)
 | |
|       {
 | |
|          if((m_position != m_end) && (*m_position == '}'))
 | |
|             ++m_position;
 | |
|          else
 | |
|          {
 | |
|             m_position -= 2;
 | |
|             return false;
 | |
|          }
 | |
|       }
 | |
|       put(this->m_results.get_last_closed_paren());
 | |
|       return true;
 | |
|    }
 | |
|    return false;
 | |
| }
 | |
| 
 | |
| template <class OutputIterator, class Results, class traits, class ForwardIter>
 | |
| void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_escape()
 | |
| {
 | |
|    // skip the escape and check for trailing escape:
 | |
|    if(++m_position == m_end)
 | |
|    {
 | |
|       put(static_cast<char_type>('\\'));
 | |
|       return;
 | |
|    }
 | |
|    // now switch on the escape type:
 | |
|    switch(*m_position)
 | |
|    {
 | |
|    case 'a':
 | |
|       put(static_cast<char_type>('\a'));
 | |
|       ++m_position;
 | |
|       break;
 | |
|    case 'f':
 | |
|       put(static_cast<char_type>('\f'));
 | |
|       ++m_position;
 | |
|       break;
 | |
|    case 'n':
 | |
|       put(static_cast<char_type>('\n'));
 | |
|       ++m_position;
 | |
|       break;
 | |
|    case 'r':
 | |
|       put(static_cast<char_type>('\r'));
 | |
|       ++m_position;
 | |
|       break;
 | |
|    case 't':
 | |
|       put(static_cast<char_type>('\t'));
 | |
|       ++m_position;
 | |
|       break;
 | |
|    case 'v':
 | |
|       put(static_cast<char_type>('\v'));
 | |
|       ++m_position;
 | |
|       break;
 | |
|    case 'x':
 | |
|       if(++m_position == m_end)
 | |
|       {
 | |
|          put(static_cast<char_type>('x'));
 | |
|          return;
 | |
|       }
 | |
|       // maybe have \x{ddd}
 | |
|       if(*m_position == static_cast<char_type>('{'))
 | |
|       {
 | |
|          ++m_position;
 | |
|          int val = this->toi(m_position, m_end, 16);
 | |
|          if(val < 0)
 | |
|          {
 | |
|             // invalid value treat everything as literals:
 | |
|             put(static_cast<char_type>('x'));
 | |
|             put(static_cast<char_type>('{'));
 | |
|             return;
 | |
|          }
 | |
|          if((m_position == m_end) || (*m_position != static_cast<char_type>('}')))
 | |
|          {
 | |
|             --m_position;
 | |
|             while(*m_position != static_cast<char_type>('\\'))
 | |
|                --m_position;
 | |
|             ++m_position;
 | |
|             put(*m_position++);
 | |
|             return;
 | |
|          }
 | |
|          ++m_position;
 | |
|          put(static_cast<char_type>(val));
 | |
|          return;
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|          std::ptrdiff_t len = ::boost::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end);
 | |
|          len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
 | |
|          int val = this->toi(m_position, m_position + len, 16);
 | |
|          if(val < 0)
 | |
|          {
 | |
|             --m_position;
 | |
|             put(*m_position++);
 | |
|             return;
 | |
|          }
 | |
|          put(static_cast<char_type>(val));
 | |
|       }
 | |
|       break;
 | |
|    case 'c':
 | |
|       if(++m_position == m_end)
 | |
|       {
 | |
|          --m_position;
 | |
|          put(*m_position++);
 | |
|          return;
 | |
|       }
 | |
|       put(static_cast<char_type>(*m_position++ % 32));
 | |
|       break;
 | |
|    case 'e':
 | |
|       put(static_cast<char_type>(27));
 | |
|       ++m_position;
 | |
|       break;
 | |
|    default:
 | |
|       // see if we have a perl specific escape:
 | |
|       if((m_flags & boost::regex_constants::format_sed) == 0)
 | |
|       {
 | |
|          bool breakout = false;
 | |
|          switch(*m_position)
 | |
|          {
 | |
|          case 'l':
 | |
|             ++m_position;
 | |
|             m_restore_state = m_state;
 | |
|             m_state = output_next_lower;
 | |
|             breakout = true;
 | |
|             break;
 | |
|          case 'L':
 | |
|             ++m_position;
 | |
|             m_state = output_lower;
 | |
|             breakout = true;
 | |
|             break;
 | |
|          case 'u':
 | |
|             ++m_position;
 | |
|             m_restore_state = m_state;
 | |
|             m_state = output_next_upper;
 | |
|             breakout = true;
 | |
|             break;
 | |
|          case 'U':
 | |
|             ++m_position;
 | |
|             m_state = output_upper;
 | |
|             breakout = true;
 | |
|             break;
 | |
|          case 'E':
 | |
|             ++m_position;
 | |
|             m_state = output_copy;
 | |
|             breakout = true;
 | |
|             break;
 | |
|          }
 | |
|          if(breakout)
 | |
|             break;
 | |
|       }
 | |
|       // see if we have a \n sed style backreference:
 | |
|       std::ptrdiff_t len = ::boost::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end);
 | |
|       len = (std::min)(static_cast<std::ptrdiff_t>(1), len);
 | |
|       int v = this->toi(m_position, m_position+len, 10);
 | |
|       if((v > 0) || ((v == 0) && (m_flags & ::boost::regex_constants::format_sed)))
 | |
|       {
 | |
|          put(m_results[v]);
 | |
|          break;
 | |
|       }
 | |
|       else if(v == 0)
 | |
|       {
 | |
|          // octal ecape sequence:
 | |
|          --m_position;
 | |
|          len = ::boost::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end);
 | |
|          len = (std::min)(static_cast<std::ptrdiff_t>(4), len);
 | |
|          v = this->toi(m_position, m_position + len, 8);
 | |
|          BOOST_ASSERT(v >= 0);
 | |
|          put(static_cast<char_type>(v));
 | |
|          break;
 | |
|       }
 | |
|       // Otherwise output the character "as is":
 | |
|       put(*m_position++);
 | |
|       break;
 | |
|    }
 | |
| }
 | |
| 
 | |
| template <class OutputIterator, class Results, class traits, class ForwardIter>
 | |
| void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_conditional()
 | |
| {
 | |
|    if(m_position == m_end)
 | |
|    {
 | |
|       // oops trailing '?':
 | |
|       put(static_cast<char_type>('?'));
 | |
|       return;
 | |
|    }
 | |
|    int v;
 | |
|    if(*m_position == '{')
 | |
|    {
 | |
|       ForwardIter base = m_position;
 | |
|       ++m_position;
 | |
|       v = this->toi(m_position, m_end, 10);
 | |
|       if(v < 0)
 | |
|       {
 | |
|          // Try a named subexpression:
 | |
|          while((m_position != m_end) && (*m_position != '}'))
 | |
|             ++m_position;
 | |
|          v = this->get_named_sub_index(base + 1, m_position);
 | |
|       }
 | |
|       if((v < 0) || (*m_position != '}'))
 | |
|       {
 | |
|          m_position = base;
 | |
|          // oops trailing '?':
 | |
|          put(static_cast<char_type>('?'));
 | |
|          return;
 | |
|       }
 | |
|       // Skip trailing '}':
 | |
|       ++m_position;
 | |
|    }
 | |
|    else
 | |
|    {
 | |
|       std::ptrdiff_t len = ::boost::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end);
 | |
|       len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
 | |
|       v = this->toi(m_position, m_position + len, 10);
 | |
|    }
 | |
|    if(v < 0)
 | |
|    {
 | |
|       // oops not a number:
 | |
|       put(static_cast<char_type>('?'));
 | |
|       return;
 | |
|    }
 | |
| 
 | |
|    // output varies depending upon whether sub-expression v matched or not:
 | |
|    if(m_results[v].matched)
 | |
|    {
 | |
|       m_have_conditional = true;
 | |
|       format_all();
 | |
|       m_have_conditional = false;
 | |
|       if((m_position != m_end) && (*m_position == static_cast<char_type>(':')))
 | |
|       {
 | |
|          // skip the ':':
 | |
|          ++m_position;
 | |
|          // save output state, then turn it off:
 | |
|          output_state saved_state = m_state;
 | |
|          m_state = output_none;
 | |
|          // format the rest of this scope:
 | |
|          format_until_scope_end();
 | |
|          // restore output state:
 | |
|          m_state = saved_state;
 | |
|       }
 | |
|    }
 | |
|    else
 | |
|    {
 | |
|       // save output state, then turn it off:
 | |
|       output_state saved_state = m_state;
 | |
|       m_state = output_none;
 | |
|       // format until ':' or ')':
 | |
|       m_have_conditional = true;
 | |
|       format_all();
 | |
|       m_have_conditional = false;
 | |
|       // restore state:
 | |
|       m_state = saved_state;
 | |
|       if((m_position != m_end) && (*m_position == static_cast<char_type>(':')))
 | |
|       {
 | |
|          // skip the ':':
 | |
|          ++m_position;
 | |
|          // format the rest of this scope:
 | |
|          format_until_scope_end();
 | |
|       }
 | |
|    }
 | |
| }
 | |
| 
 | |
| template <class OutputIterator, class Results, class traits, class ForwardIter>
 | |
| void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_until_scope_end()
 | |
| {
 | |
|    do
 | |
|    {
 | |
|       format_all();
 | |
|       if((m_position == m_end) || (*m_position == static_cast<char_type>(')')))
 | |
|          return;
 | |
|       put(*m_position++);
 | |
|    }while(m_position != m_end);
 | |
| }
 | |
| 
 | |
| template <class OutputIterator, class Results, class traits, class ForwardIter>
 | |
| void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::put(char_type c)
 | |
| {
 | |
|    // write a single character to output
 | |
|    // according to which case translation mode we are in:
 | |
|    switch(this->m_state)
 | |
|    {
 | |
|    case output_none:
 | |
|       return;
 | |
|    case output_next_lower:
 | |
|       c = m_traits.tolower(c);
 | |
|       this->m_state = m_restore_state;
 | |
|       break;
 | |
|    case output_next_upper:
 | |
|       c = m_traits.toupper(c);
 | |
|       this->m_state = m_restore_state;
 | |
|       break;
 | |
|    case output_lower:
 | |
|       c = m_traits.tolower(c);
 | |
|       break;
 | |
|    case output_upper:
 | |
|       c = m_traits.toupper(c);
 | |
|       break;
 | |
|    default:
 | |
|       break;
 | |
|    }
 | |
|    *m_out = c;
 | |
|    ++m_out;
 | |
| }
 | |
| 
 | |
| template <class OutputIterator, class Results, class traits, class ForwardIter>
 | |
| void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::put(const sub_match_type& sub)
 | |
| {
 | |
|    typedef typename sub_match_type::iterator iterator_type;
 | |
|    iterator_type i = sub.first;
 | |
|    while(i != sub.second)
 | |
|    {
 | |
|       put(*i);
 | |
|       ++i;
 | |
|    }
 | |
| }
 | |
| 
 | |
| template <class S>
 | |
| class string_out_iterator
 | |
| #ifndef BOOST_NO_STD_ITERATOR
 | |
|    : public std::iterator<std::output_iterator_tag, typename S::value_type>
 | |
| #endif
 | |
| {
 | |
|    S* out;
 | |
| public:
 | |
|    string_out_iterator(S& s) : out(&s) {}
 | |
|    string_out_iterator& operator++() { return *this; }
 | |
|    string_out_iterator& operator++(int) { return *this; }
 | |
|    string_out_iterator& operator*() { return *this; }
 | |
|    string_out_iterator& operator=(typename S::value_type v) 
 | |
|    { 
 | |
|       out->append(1, v); 
 | |
|       return *this; 
 | |
|    }
 | |
| 
 | |
| #ifdef BOOST_NO_STD_ITERATOR
 | |
|    typedef std::ptrdiff_t difference_type;
 | |
|    typedef typename S::value_type value_type;
 | |
|    typedef value_type* pointer;
 | |
|    typedef value_type& reference;
 | |
|    typedef std::output_iterator_tag iterator_category;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| template <class OutputIterator, class Iterator, class Alloc, class ForwardIter, class traits>
 | |
| OutputIterator regex_format_imp(OutputIterator out,
 | |
|                           const match_results<Iterator, Alloc>& m,
 | |
|                           ForwardIter p1, ForwardIter p2,
 | |
|                           match_flag_type flags,
 | |
|                           const traits& t
 | |
|                          )
 | |
| {
 | |
|    if(flags & regex_constants::format_literal)
 | |
|    {
 | |
|       return BOOST_REGEX_DETAIL_NS::copy(p1, p2, out);
 | |
|    }
 | |
| 
 | |
|    BOOST_REGEX_DETAIL_NS::basic_regex_formatter<
 | |
|       OutputIterator, 
 | |
|       match_results<Iterator, Alloc>, 
 | |
|       traits, ForwardIter> f(out, m, t);
 | |
|    return f.format(p1, p2, flags);
 | |
| }
 | |
| 
 | |
| #ifndef BOOST_NO_SFINAE
 | |
| 
 | |
| BOOST_MPL_HAS_XXX_TRAIT_DEF(const_iterator)
 | |
| 
 | |
| struct any_type 
 | |
| {
 | |
|    template <class T>
 | |
|    any_type(const T&); 
 | |
|    template <class T, class U>
 | |
|    any_type(const T&, const U&); 
 | |
|    template <class T, class U, class V>
 | |
|    any_type(const T&, const U&, const V&); 
 | |
| };
 | |
| typedef char no_type;
 | |
| typedef char (&unary_type)[2];
 | |
| typedef char (&binary_type)[3];
 | |
| typedef char (&ternary_type)[4];
 | |
| 
 | |
| no_type check_is_formatter(unary_type, binary_type, ternary_type);
 | |
| template<typename T>
 | |
| unary_type check_is_formatter(T const &, binary_type, ternary_type);
 | |
| template<typename T>
 | |
| binary_type check_is_formatter(unary_type, T const &, ternary_type);
 | |
| template<typename T, typename U>
 | |
| binary_type check_is_formatter(T const &, U const &, ternary_type);
 | |
| template<typename T>
 | |
| ternary_type check_is_formatter(unary_type, binary_type, T const &);
 | |
| template<typename T, typename U>
 | |
| ternary_type check_is_formatter(T const &, binary_type, U const &);
 | |
| template<typename T, typename U>
 | |
| ternary_type check_is_formatter(unary_type, T const &, U const &);
 | |
| template<typename T, typename U, typename V>
 | |
| ternary_type check_is_formatter(T const &, U const &, V const &);
 | |
| 
 | |
| struct unary_binary_ternary
 | |
| {
 | |
|     typedef unary_type (*unary_fun)(any_type);
 | |
|     typedef binary_type (*binary_fun)(any_type, any_type);
 | |
|     typedef ternary_type (*ternary_fun)(any_type, any_type, any_type);
 | |
|     operator unary_fun();
 | |
|     operator binary_fun();
 | |
|     operator ternary_fun();
 | |
| };
 | |
| 
 | |
| template<typename Formatter, bool IsFunction = boost::is_function<Formatter>::value>
 | |
| struct formatter_wrapper
 | |
|   : Formatter
 | |
|   , unary_binary_ternary
 | |
| {
 | |
|    formatter_wrapper(){}
 | |
| };
 | |
| 
 | |
| template<typename Formatter>
 | |
| struct formatter_wrapper<Formatter, true>
 | |
|   : unary_binary_ternary
 | |
| {
 | |
|     operator Formatter *();
 | |
| };
 | |
| 
 | |
| template<typename Formatter>
 | |
| struct formatter_wrapper<Formatter *, false>
 | |
|   : unary_binary_ternary
 | |
| {
 | |
|     operator Formatter *();
 | |
| };
 | |
| 
 | |
| template <class F, class M, class O>
 | |
| struct format_traits_imp
 | |
| {
 | |
| private:
 | |
|    //
 | |
|    // F must be a pointer, a function, or a class with a function call operator:
 | |
|    //
 | |
|    BOOST_STATIC_ASSERT((::boost::is_pointer<F>::value || ::boost::is_function<F>::value || ::boost::is_class<F>::value));
 | |
|    static formatter_wrapper<typename unwrap_reference<F>::type> f;
 | |
|    static M m;
 | |
|    static O out;
 | |
|    static boost::regex_constants::match_flag_type flags;
 | |
| public:
 | |
|    BOOST_STATIC_CONSTANT(int, value = sizeof(check_is_formatter(f(m), f(m, out), f(m, out, flags))));
 | |
| };
 | |
| 
 | |
| template <class F, class M, class O>
 | |
| struct format_traits
 | |
| {
 | |
| public:
 | |
|    // 
 | |
|    // Type is mpl::int_<N> where N is one of:
 | |
|    //
 | |
|    // 0 : F is a pointer to a presumably null-terminated string.
 | |
|    // 1 : F is a character-container such as a std::string.
 | |
|    // 2 : F is a Unary Functor.
 | |
|    // 3 : F is a Binary Functor.
 | |
|    // 4 : F is a Ternary Functor.
 | |
|    //
 | |
|    typedef typename boost::mpl::if_<
 | |
|       boost::mpl::and_<boost::is_pointer<F>, boost::mpl::not_<boost::is_function<typename boost::remove_pointer<F>::type> > >,
 | |
|       boost::mpl::int_<0>,
 | |
|       typename boost::mpl::if_<
 | |
|          has_const_iterator<F>,
 | |
|          boost::mpl::int_<1>,
 | |
|          boost::mpl::int_<format_traits_imp<F, M, O>::value>
 | |
|       >::type
 | |
|    >::type type;
 | |
|    //
 | |
|    // This static assertion will fail if the functor passed does not accept
 | |
|    // the same type of arguments passed.
 | |
|    //
 | |
|    BOOST_STATIC_ASSERT( boost::is_class<F>::value && !has_const_iterator<F>::value ? (type::value > 1) : true);
 | |
| };
 | |
| 
 | |
| #else // BOOST_NO_SFINAE
 | |
| 
 | |
| template <class F, class M, class O>
 | |
| struct format_traits
 | |
| {
 | |
| public:
 | |
|    // 
 | |
|    // Type is mpl::int_<N> where N is one of:
 | |
|    //
 | |
|    // 0 : F is a pointer to a presumably null-terminated string.
 | |
|    // 1 : F is a character-container such as a std::string.
 | |
|    //
 | |
|    // Other options such as F being a Functor are not supported without
 | |
|    // SFINAE support.
 | |
|    //
 | |
|    typedef typename boost::mpl::if_<
 | |
|       boost::is_pointer<F>,
 | |
|       boost::mpl::int_<0>,
 | |
|       boost::mpl::int_<1>
 | |
|    >::type type;
 | |
| };
 | |
| 
 | |
| #endif // BOOST_NO_SFINAE
 | |
| 
 | |
| template <class Base, class Match>
 | |
| struct format_functor3
 | |
| {
 | |
|    format_functor3(Base b) : func(b) {}
 | |
|    template <class OutputIter>
 | |
|    OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f)
 | |
|    {
 | |
|       return boost::unwrap_ref(func)(m, i, f);
 | |
|    }
 | |
|    template <class OutputIter, class Traits>
 | |
|    OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits&)
 | |
|    {
 | |
|       return (*this)(m, i, f);
 | |
|    }
 | |
| private:
 | |
|    Base func;
 | |
|    format_functor3(const format_functor3&);
 | |
|    format_functor3& operator=(const format_functor3&);
 | |
| };
 | |
| 
 | |
| template <class Base, class Match>
 | |
| struct format_functor2
 | |
| {
 | |
|    format_functor2(Base b) : func(b) {}
 | |
|    template <class OutputIter>
 | |
|    OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type /*f*/)
 | |
|    {
 | |
|       return boost::unwrap_ref(func)(m, i);
 | |
|    }
 | |
|    template <class OutputIter, class Traits>
 | |
|    OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits&)
 | |
|    {
 | |
|       return (*this)(m, i, f);
 | |
|    }
 | |
| private:
 | |
|    Base func;
 | |
|    format_functor2(const format_functor2&);
 | |
|    format_functor2& operator=(const format_functor2&);
 | |
| };
 | |
| 
 | |
| template <class Base, class Match>
 | |
| struct format_functor1
 | |
| {
 | |
|    format_functor1(Base b) : func(b) {}
 | |
| 
 | |
|    template <class S, class OutputIter>
 | |
|    OutputIter do_format_string(const S& s, OutputIter i)
 | |
|    {
 | |
|       return BOOST_REGEX_DETAIL_NS::copy(s.begin(), s.end(), i);
 | |
|    }
 | |
|    template <class S, class OutputIter>
 | |
|    inline OutputIter do_format_string(const S* s, OutputIter i)
 | |
|    {
 | |
|       while(s && *s)
 | |
|       {
 | |
|          *i = *s;
 | |
|          ++i;
 | |
|          ++s;
 | |
|       }
 | |
|       return i;
 | |
|    }
 | |
|    template <class OutputIter>
 | |
|    OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type /*f*/)
 | |
|    {
 | |
|       return do_format_string(boost::unwrap_ref(func)(m), i);
 | |
|    }
 | |
|    template <class OutputIter, class Traits>
 | |
|    OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits&)
 | |
|    {
 | |
|       return (*this)(m, i, f);
 | |
|    }
 | |
| private:
 | |
|    Base func;
 | |
|    format_functor1(const format_functor1&);
 | |
|    format_functor1& operator=(const format_functor1&);
 | |
| };
 | |
| 
 | |
| template <class charT, class Match, class Traits>
 | |
| struct format_functor_c_string
 | |
| {
 | |
|    format_functor_c_string(const charT* ps) : func(ps) {}
 | |
| 
 | |
|    template <class OutputIter>
 | |
|    OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits& t = Traits())
 | |
|    {
 | |
|       //typedef typename Match::char_type char_type;
 | |
|       const charT* end = func;
 | |
|       while(*end) ++end;
 | |
|       return regex_format_imp(i, m, func, end, f, t);
 | |
|    }
 | |
| private:
 | |
|    const charT* func;
 | |
|    format_functor_c_string(const format_functor_c_string&);
 | |
|    format_functor_c_string& operator=(const format_functor_c_string&);
 | |
| };
 | |
| 
 | |
| template <class Container, class Match, class Traits>
 | |
| struct format_functor_container
 | |
| {
 | |
|    format_functor_container(const Container& c) : func(c) {}
 | |
| 
 | |
|    template <class OutputIter>
 | |
|    OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits& t = Traits())
 | |
|    {
 | |
|       //typedef typename Match::char_type char_type;
 | |
|       return BOOST_REGEX_DETAIL_NS::regex_format_imp(i, m, func.begin(), func.end(), f, t);
 | |
|    }
 | |
| private:
 | |
|    const Container& func;
 | |
|    format_functor_container(const format_functor_container&);
 | |
|    format_functor_container& operator=(const format_functor_container&);
 | |
| };
 | |
| 
 | |
| template <class Func, class Match, class OutputIterator, class Traits = BOOST_REGEX_DETAIL_NS::trivial_format_traits<typename Match::char_type> >
 | |
| struct compute_functor_type
 | |
| {
 | |
|    typedef typename format_traits<Func, Match, OutputIterator>::type tag;
 | |
|    typedef typename boost::remove_cv< typename boost::remove_pointer<Func>::type>::type maybe_char_type;
 | |
| 
 | |
|    typedef typename mpl::if_<
 | |
|       ::boost::is_same<tag, mpl::int_<0> >, format_functor_c_string<maybe_char_type, Match, Traits>,
 | |
|       typename mpl::if_<
 | |
|          ::boost::is_same<tag, mpl::int_<1> >, format_functor_container<Func, Match, Traits>,
 | |
|          typename mpl::if_<
 | |
|             ::boost::is_same<tag, mpl::int_<2> >, format_functor1<Func, Match>,
 | |
|             typename mpl::if_<
 | |
|                ::boost::is_same<tag, mpl::int_<3> >, format_functor2<Func, Match>, 
 | |
|                format_functor3<Func, Match>
 | |
|             >::type
 | |
|          >::type
 | |
|       >::type
 | |
|    >::type type;
 | |
| };
 | |
| 
 | |
| } // namespace BOOST_REGEX_DETAIL_NS
 | |
| 
 | |
| template <class OutputIterator, class Iterator, class Allocator, class Functor>
 | |
| inline OutputIterator regex_format(OutputIterator out,
 | |
|                           const match_results<Iterator, Allocator>& m,
 | |
|                           Functor fmt,
 | |
|                           match_flag_type flags = format_all
 | |
|                          )
 | |
| {
 | |
|    return m.format(out, fmt, flags);
 | |
| }
 | |
| 
 | |
| template <class Iterator, class Allocator, class Functor>
 | |
| inline std::basic_string<typename match_results<Iterator, Allocator>::char_type> regex_format(const match_results<Iterator, Allocator>& m, 
 | |
|                                       Functor fmt, 
 | |
|                                       match_flag_type flags = format_all)
 | |
| {
 | |
|    return m.format(fmt, flags);
 | |
| }
 | |
| 
 | |
| #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
 | |
| 
 | |
| } // namespace boost
 | |
| 
 | |
| #endif  // BOOST_REGEX_FORMAT_HPP
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | 
