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