1 /*
2  *
3  * Copyright (c) 1998-2009 John Maddock
4  * Copyright 2008 Eric Niebler.
5  *
6  * Use, modification and distribution are subject to the
7  * Boost Software License, Version 1.0. (See accompanying file
8  * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9  *
10  */
11 
12  /*
13   *   LOCATION:    see http://www.boost.org for most recent version.
14   *   FILE         regex_format.hpp
15   *   VERSION      see <boost/version.hpp>
16   *   DESCRIPTION: Provides formatting output routines for search and replace
17   *                operations.  Note this is an internal header file included
18   *                by regex.hpp, do not include on its own.
19   */
20 
21 #ifndef BOOST_REGEX_FORMAT_HPP
22 #define BOOST_REGEX_FORMAT_HPP
23 
24 #include <boost/type_traits/is_pointer.hpp>
25 #include <boost/type_traits/is_function.hpp>
26 #include <boost/type_traits/is_class.hpp>
27 #include <boost/type_traits/is_same.hpp>
28 #include <boost/type_traits/is_convertible.hpp>
29 #include <boost/type_traits/remove_pointer.hpp>
30 #include <boost/type_traits/remove_cv.hpp>
31 #include <boost/mpl/if.hpp>
32 #include <boost/mpl/and.hpp>
33 #include <boost/mpl/not.hpp>
34 #ifndef BOOST_NO_SFINAE
35 #include <boost/mpl/has_xxx.hpp>
36 #endif
37 #include <boost/ref.hpp>
38 
39 namespace boost{
40 
41 #ifdef BOOST_MSVC
42 #pragma warning(push)
43 #pragma warning(disable: 4103)
44 #endif
45 #ifdef BOOST_HAS_ABI_HEADERS
46 #  include BOOST_ABI_PREFIX
47 #endif
48 #ifdef BOOST_MSVC
49 #pragma warning(pop)
50 #endif
51 
52 //
53 // Forward declaration:
54 //
55    template <class BidiIterator, class Allocator = BOOST_DEDUCED_TYPENAME std::vector<sub_match<BidiIterator> >::allocator_type >
56 class match_results;
57 
58 namespace re_detail{
59 
60 //
61 // struct trivial_format_traits:
62 // defines minimum localisation support for formatting
63 // in the case that the actual regex traits is unavailable.
64 //
65 template <class charT>
66 struct trivial_format_traits
67 {
68    typedef charT char_type;
69 
lengthboost::re_detail::trivial_format_traits70    static std::ptrdiff_t length(const charT* p)
71    {
72       return global_length(p);
73    }
tolowerboost::re_detail::trivial_format_traits74    static charT tolower(charT c)
75    {
76       return ::boost::re_detail::global_lower(c);
77    }
toupperboost::re_detail::trivial_format_traits78    static charT toupper(charT c)
79    {
80       return ::boost::re_detail::global_upper(c);
81    }
valueboost::re_detail::trivial_format_traits82    static int value(const charT c, int radix)
83    {
84       int result = global_value(c);
85       return result >= radix ? -1 : result;
86    }
toiboost::re_detail::trivial_format_traits87    int toi(const charT*& p1, const charT* p2, int radix)const
88    {
89       return global_toi(p1, p2, radix, *this);
90    }
91 };
92 
93 template <class OutputIterator, class Results, class traits, class ForwardIter>
94 class basic_regex_formatter
95 {
96 public:
97    typedef typename traits::char_type char_type;
basic_regex_formatter(OutputIterator o,const Results & r,const traits & t)98    basic_regex_formatter(OutputIterator o, const Results& r, const traits& t)
99       : 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) {}
100    OutputIterator format(ForwardIter p1, ForwardIter p2, match_flag_type f);
format(ForwardIter p1,match_flag_type f)101    OutputIterator format(ForwardIter p1, match_flag_type f)
102    {
103       return format(p1, p1 + m_traits.length(p1), f);
104    }
105 private:
106    typedef typename Results::value_type sub_match_type;
107    enum output_state
108    {
109       output_copy,
110       output_next_lower,
111       output_next_upper,
112       output_lower,
113       output_upper,
114       output_none
115    };
116 
117    void put(char_type c);
118    void put(const sub_match_type& sub);
119    void format_all();
120    void format_perl();
121    void format_escape();
122    void format_conditional();
123    void format_until_scope_end();
124    bool handle_perl_verb(bool have_brace);
125 
get_named_sub(ForwardIter i,ForwardIter j,const mpl::false_ &)126    inline typename Results::value_type const& get_named_sub(ForwardIter i, ForwardIter j, const mpl::false_&)
127    {
128       std::vector<char_type> v(i, j);
129       return (i != j) ? this->m_results.named_subexpression(&v[0], &v[0] + v.size())
130          : this->m_results.named_subexpression(static_cast<const char_type*>(0), static_cast<const char_type*>(0));
131    }
get_named_sub(ForwardIter i,ForwardIter j,const mpl::true_ &)132    inline typename Results::value_type const& get_named_sub(ForwardIter i, ForwardIter j, const mpl::true_&)
133    {
134       return this->m_results.named_subexpression(i, j);
135    }
get_named_sub(ForwardIter i,ForwardIter j)136    inline typename Results::value_type const& get_named_sub(ForwardIter i, ForwardIter j)
137    {
138       typedef typename boost::is_convertible<ForwardIter, const char_type*>::type tag_type;
139       return get_named_sub(i, j, tag_type());
140    }
get_named_sub_index(ForwardIter i,ForwardIter j,const mpl::false_ &)141    inline int get_named_sub_index(ForwardIter i, ForwardIter j, const mpl::false_&)
142    {
143       std::vector<char_type> v(i, j);
144       return (i != j) ? this->m_results.named_subexpression_index(&v[0], &v[0] + v.size())
145          : this->m_results.named_subexpression_index(static_cast<const char_type*>(0), static_cast<const char_type*>(0));
146    }
get_named_sub_index(ForwardIter i,ForwardIter j,const mpl::true_ &)147    inline int get_named_sub_index(ForwardIter i, ForwardIter j, const mpl::true_&)
148    {
149       return this->m_results.named_subexpression_index(i, j);
150    }
get_named_sub_index(ForwardIter i,ForwardIter j)151    inline int get_named_sub_index(ForwardIter i, ForwardIter j)
152    {
153       typedef typename boost::is_convertible<ForwardIter, const char_type*>::type tag_type;
154       return get_named_sub_index(i, j, tag_type());
155    }
156 #ifdef BOOST_MSVC
157    // msvc-8.0 issues a spurious warning on the call to std::advance here:
158 #pragma warning(push)
159 #pragma warning(disable:4244)
160 #endif
toi(ForwardIter & i,ForwardIter j,int base,const boost::mpl::false_ &)161    inline int toi(ForwardIter& i, ForwardIter j, int base, const boost::mpl::false_&)
162    {
163       if(i != j)
164       {
165          std::vector<char_type> v(i, j);
166          const char_type* start = &v[0];
167          const char_type* pos = start;
168          int r = m_traits.toi(pos, &v[0] + v.size(), base);
169          std::advance(i, pos - start);
170          return r;
171       }
172       return -1;
173    }
174 #ifdef BOOST_MSVC
175 #pragma warning(pop)
176 #endif
toi(ForwardIter & i,ForwardIter j,int base,const boost::mpl::true_ &)177    inline int toi(ForwardIter& i, ForwardIter j, int base, const boost::mpl::true_&)
178    {
179       return m_traits.toi(i, j, base);
180    }
toi(ForwardIter & i,ForwardIter j,int base)181    inline int toi(ForwardIter& i, ForwardIter j, int base)
182    {
183 #if defined(_MSC_VER) && defined(__INTEL_COMPILER) && ((__INTEL_COMPILER == 9999) || (__INTEL_COMPILER == 1210))
184       // Workaround for Intel support issue #656654.
185       // See also https://svn.boost.org/trac/boost/ticket/6359
186       return toi(i, j, base, mpl::false_());
187 #else
188       typedef typename boost::is_convertible<ForwardIter, const char_type*&>::type tag_type;
189       return toi(i, j, base, tag_type());
190 #endif
191    }
192 
193    const traits&    m_traits;       // the traits class for localised formatting operations
194    const Results&   m_results;     // the match_results being used.
195    OutputIterator   m_out;         // where to send output.
196    ForwardIter      m_position;  // format string, current position
197    ForwardIter      m_end;       // format string end
198    match_flag_type  m_flags;      // format flags to use
199    output_state     m_state;      // what to do with the next character
200    output_state     m_restore_state;  // what state to restore to.
201    bool             m_have_conditional; // we are parsing a conditional
202 private:
203    basic_regex_formatter(const basic_regex_formatter&);
204    basic_regex_formatter& operator=(const basic_regex_formatter&);
205 };
206 
207 template <class OutputIterator, class Results, class traits, class ForwardIter>
208 OutputIterator basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format(ForwardIter p1, ForwardIter p2, match_flag_type f)
209 {
210    m_position = p1;
211    m_end = p2;
212    m_flags = f;
213    format_all();
214    return m_out;
215 }
216 
217 template <class OutputIterator, class Results, class traits, class ForwardIter>
format_all()218 void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_all()
219 {
220    // over and over:
221    while(m_position != m_end)
222    {
223       switch(*m_position)
224       {
225       case '&':
226          if(m_flags & ::boost::regex_constants::format_sed)
227          {
228             ++m_position;
229             put(m_results[0]);
230             break;
231          }
232          put(*m_position++);
233          break;
234       case '\\':
235          format_escape();
236          break;
237       case '(':
238          if(m_flags & boost::regex_constants::format_all)
239          {
240             ++m_position;
241             bool have_conditional = m_have_conditional;
242             m_have_conditional = false;
243             format_until_scope_end();
244             m_have_conditional = have_conditional;
245             if(m_position == m_end)
246                return;
247             BOOST_ASSERT(*m_position == static_cast<char_type>(')'));
248             ++m_position;  // skip the closing ')'
249             break;
250          }
251          put(*m_position);
252          ++m_position;
253          break;
254       case ')':
255          if(m_flags & boost::regex_constants::format_all)
256          {
257             return;
258          }
259          put(*m_position);
260          ++m_position;
261          break;
262       case ':':
263          if((m_flags & boost::regex_constants::format_all) && m_have_conditional)
264          {
265             return;
266          }
267          put(*m_position);
268          ++m_position;
269          break;
270       case '?':
271          if(m_flags & boost::regex_constants::format_all)
272          {
273             ++m_position;
274             format_conditional();
275             break;
276          }
277          put(*m_position);
278          ++m_position;
279          break;
280       case '$':
281          if((m_flags & format_sed) == 0)
282          {
283             format_perl();
284             break;
285          }
286          // not a special character:
287          BOOST_FALLTHROUGH;
288       default:
289          put(*m_position);
290          ++m_position;
291          break;
292       }
293    }
294 }
295 
296 template <class OutputIterator, class Results, class traits, class ForwardIter>
format_perl()297 void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_perl()
298 {
299    //
300    // On entry *m_position points to a '$' character
301    // output the information that goes with it:
302    //
303    BOOST_ASSERT(*m_position == '$');
304    //
305    // see if this is a trailing '$':
306    //
307    if(++m_position == m_end)
308    {
309       --m_position;
310       put(*m_position);
311       ++m_position;
312       return;
313    }
314    //
315    // OK find out what kind it is:
316    //
317    bool have_brace = false;
318    ForwardIter save_position = m_position;
319    switch(*m_position)
320    {
321    case '&':
322       ++m_position;
323       put(this->m_results[0]);
324       break;
325    case '`':
326       ++m_position;
327       put(this->m_results.prefix());
328       break;
329    case '\'':
330       ++m_position;
331       put(this->m_results.suffix());
332       break;
333    case '$':
334       put(*m_position++);
335       break;
336    case '+':
337       if((++m_position != m_end) && (*m_position == '{'))
338       {
339          ForwardIter base = ++m_position;
340          while((m_position != m_end) && (*m_position != '}')) ++m_position;
341          if(m_position != m_end)
342          {
343             // Named sub-expression:
344             put(get_named_sub(base, m_position));
345             ++m_position;
346             break;
347          }
348          else
349          {
350             m_position = --base;
351          }
352       }
353       put((this->m_results)[this->m_results.size() > 1 ? static_cast<int>(this->m_results.size() - 1) : 1]);
354       break;
355    case '{':
356       have_brace = true;
357       ++m_position;
358       BOOST_FALLTHROUGH;
359    default:
360       // see if we have a number:
361       {
362          std::ptrdiff_t len = ::boost::re_detail::distance(m_position, m_end);
363          //len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
364          int v = this->toi(m_position, m_position + len, 10);
365          if((v < 0) || (have_brace && ((m_position == m_end) || (*m_position != '}'))))
366          {
367             // Look for a Perl-5.10 verb:
368             if(!handle_perl_verb(have_brace))
369             {
370                // leave the $ as is, and carry on:
371                m_position = --save_position;
372                put(*m_position);
373                ++m_position;
374             }
375             break;
376          }
377          // otherwise output sub v:
378          put(this->m_results[v]);
379          if(have_brace)
380             ++m_position;
381       }
382    }
383 }
384 
385 template <class OutputIterator, class Results, class traits, class ForwardIter>
handle_perl_verb(bool have_brace)386 bool basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::handle_perl_verb(bool have_brace)
387 {
388    //
389    // We may have a capitalised string containing a Perl action:
390    //
391    static const char_type MATCH[] = { 'M', 'A', 'T', 'C', 'H' };
392    static const char_type PREMATCH[] = { 'P', 'R', 'E', 'M', 'A', 'T', 'C', 'H' };
393    static const char_type POSTMATCH[] = { 'P', 'O', 'S', 'T', 'M', 'A', 'T', 'C', 'H' };
394    static const char_type LAST_PAREN_MATCH[] = { 'L', 'A', 'S', 'T', '_', 'P', 'A', 'R', 'E', 'N', '_', 'M', 'A', 'T', 'C', 'H' };
395    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' };
396    static const char_type LAST_SUBMATCH_RESULT_ALT[] = { '^', 'N' };
397 
398    if(m_position == m_end)
399       return false;
400    if(have_brace && (*m_position == '^'))
401       ++m_position;
402 
403    std::ptrdiff_t max_len = m_end - m_position;
404 
405    if((max_len >= 5) && std::equal(m_position, m_position + 5, MATCH))
406    {
407       m_position += 5;
408       if(have_brace)
409       {
410          if((m_position != m_end) && (*m_position == '}'))
411             ++m_position;
412          else
413          {
414             m_position -= 5;
415             return false;
416          }
417       }
418       put(this->m_results[0]);
419       return true;
420    }
421    if((max_len >= 8) && std::equal(m_position, m_position + 8, PREMATCH))
422    {
423       m_position += 8;
424       if(have_brace)
425       {
426          if((m_position != m_end) && (*m_position == '}'))
427             ++m_position;
428          else
429          {
430             m_position -= 8;
431             return false;
432          }
433       }
434       put(this->m_results.prefix());
435       return true;
436    }
437    if((max_len >= 9) && std::equal(m_position, m_position + 9, POSTMATCH))
438    {
439       m_position += 9;
440       if(have_brace)
441       {
442          if((m_position != m_end) && (*m_position == '}'))
443             ++m_position;
444          else
445          {
446             m_position -= 9;
447             return false;
448          }
449       }
450       put(this->m_results.suffix());
451       return true;
452    }
453    if((max_len >= 16) && std::equal(m_position, m_position + 16, LAST_PAREN_MATCH))
454    {
455       m_position += 16;
456       if(have_brace)
457       {
458          if((m_position != m_end) && (*m_position == '}'))
459             ++m_position;
460          else
461          {
462             m_position -= 16;
463             return false;
464          }
465       }
466       put((this->m_results)[this->m_results.size() > 1 ? static_cast<int>(this->m_results.size() - 1) : 1]);
467       return true;
468    }
469    if((max_len >= 20) && std::equal(m_position, m_position + 20, LAST_SUBMATCH_RESULT))
470    {
471       m_position += 20;
472       if(have_brace)
473       {
474          if((m_position != m_end) && (*m_position == '}'))
475             ++m_position;
476          else
477          {
478             m_position -= 20;
479             return false;
480          }
481       }
482       put(this->m_results.get_last_closed_paren());
483       return true;
484    }
485    if((max_len >= 2) && std::equal(m_position, m_position + 2, LAST_SUBMATCH_RESULT_ALT))
486    {
487       m_position += 2;
488       if(have_brace)
489       {
490          if((m_position != m_end) && (*m_position == '}'))
491             ++m_position;
492          else
493          {
494             m_position -= 2;
495             return false;
496          }
497       }
498       put(this->m_results.get_last_closed_paren());
499       return true;
500    }
501    return false;
502 }
503 
504 template <class OutputIterator, class Results, class traits, class ForwardIter>
format_escape()505 void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_escape()
506 {
507    // skip the escape and check for trailing escape:
508    if(++m_position == m_end)
509    {
510       put(static_cast<char_type>('\\'));
511       return;
512    }
513    // now switch on the escape type:
514    switch(*m_position)
515    {
516    case 'a':
517       put(static_cast<char_type>('\a'));
518       ++m_position;
519       break;
520    case 'f':
521       put(static_cast<char_type>('\f'));
522       ++m_position;
523       break;
524    case 'n':
525       put(static_cast<char_type>('\n'));
526       ++m_position;
527       break;
528    case 'r':
529       put(static_cast<char_type>('\r'));
530       ++m_position;
531       break;
532    case 't':
533       put(static_cast<char_type>('\t'));
534       ++m_position;
535       break;
536    case 'v':
537       put(static_cast<char_type>('\v'));
538       ++m_position;
539       break;
540    case 'x':
541       if(++m_position == m_end)
542       {
543          put(static_cast<char_type>('x'));
544          return;
545       }
546       // maybe have \x{ddd}
547       if(*m_position == static_cast<char_type>('{'))
548       {
549          ++m_position;
550          int val = this->toi(m_position, m_end, 16);
551          if(val < 0)
552          {
553             // invalid value treat everything as literals:
554             put(static_cast<char_type>('x'));
555             put(static_cast<char_type>('{'));
556             return;
557          }
558          if((m_position == m_end) || (*m_position != static_cast<char_type>('}')))
559          {
560             --m_position;
561             while(*m_position != static_cast<char_type>('\\'))
562                --m_position;
563             ++m_position;
564             put(*m_position++);
565             return;
566          }
567          ++m_position;
568          put(static_cast<char_type>(val));
569          return;
570       }
571       else
572       {
573          std::ptrdiff_t len = ::boost::re_detail::distance(m_position, m_end);
574          len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
575          int val = this->toi(m_position, m_position + len, 16);
576          if(val < 0)
577          {
578             --m_position;
579             put(*m_position++);
580             return;
581          }
582          put(static_cast<char_type>(val));
583       }
584       break;
585    case 'c':
586       if(++m_position == m_end)
587       {
588          --m_position;
589          put(*m_position++);
590          return;
591       }
592       put(static_cast<char_type>(*m_position++ % 32));
593       break;
594    case 'e':
595       put(static_cast<char_type>(27));
596       ++m_position;
597       break;
598    default:
599       // see if we have a perl specific escape:
600       if((m_flags & boost::regex_constants::format_sed) == 0)
601       {
602          bool breakout = false;
603          switch(*m_position)
604          {
605          case 'l':
606             ++m_position;
607             m_restore_state = m_state;
608             m_state = output_next_lower;
609             breakout = true;
610             break;
611          case 'L':
612             ++m_position;
613             m_state = output_lower;
614             breakout = true;
615             break;
616          case 'u':
617             ++m_position;
618             m_restore_state = m_state;
619             m_state = output_next_upper;
620             breakout = true;
621             break;
622          case 'U':
623             ++m_position;
624             m_state = output_upper;
625             breakout = true;
626             break;
627          case 'E':
628             ++m_position;
629             m_state = output_copy;
630             breakout = true;
631             break;
632          }
633          if(breakout)
634             break;
635       }
636       // see if we have a \n sed style backreference:
637       std::ptrdiff_t len = ::boost::re_detail::distance(m_position, m_end);
638       len = (std::min)(static_cast<std::ptrdiff_t>(1), len);
639       int v = this->toi(m_position, m_position+len, 10);
640       if((v > 0) || ((v == 0) && (m_flags & ::boost::regex_constants::format_sed)))
641       {
642          put(m_results[v]);
643          break;
644       }
645       else if(v == 0)
646       {
647          // octal ecape sequence:
648          --m_position;
649          len = ::boost::re_detail::distance(m_position, m_end);
650          len = (std::min)(static_cast<std::ptrdiff_t>(4), len);
651          v = this->toi(m_position, m_position + len, 8);
652          BOOST_ASSERT(v >= 0);
653          put(static_cast<char_type>(v));
654          break;
655       }
656       // Otherwise output the character "as is":
657       put(*m_position++);
658       break;
659    }
660 }
661 
662 template <class OutputIterator, class Results, class traits, class ForwardIter>
format_conditional()663 void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_conditional()
664 {
665    if(m_position == m_end)
666    {
667       // oops trailing '?':
668       put(static_cast<char_type>('?'));
669       return;
670    }
671    int v;
672    if(*m_position == '{')
673    {
674       ForwardIter base = m_position;
675       ++m_position;
676       v = this->toi(m_position, m_end, 10);
677       if(v < 0)
678       {
679          // Try a named subexpression:
680          while((m_position != m_end) && (*m_position != '}'))
681             ++m_position;
682          v = this->get_named_sub_index(base + 1, m_position);
683       }
684       if((v < 0) || (*m_position != '}'))
685       {
686          m_position = base;
687          // oops trailing '?':
688          put(static_cast<char_type>('?'));
689          return;
690       }
691       // Skip trailing '}':
692       ++m_position;
693    }
694    else
695    {
696       std::ptrdiff_t len = ::boost::re_detail::distance(m_position, m_end);
697       len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
698       v = this->toi(m_position, m_position + len, 10);
699    }
700    if(v < 0)
701    {
702       // oops not a number:
703       put(static_cast<char_type>('?'));
704       return;
705    }
706 
707    // output varies depending upon whether sub-expression v matched or not:
708    if(m_results[v].matched)
709    {
710       m_have_conditional = true;
711       format_all();
712       m_have_conditional = false;
713       if((m_position != m_end) && (*m_position == static_cast<char_type>(':')))
714       {
715          // skip the ':':
716          ++m_position;
717          // save output state, then turn it off:
718          output_state saved_state = m_state;
719          m_state = output_none;
720          // format the rest of this scope:
721          format_until_scope_end();
722          // restore output state:
723          m_state = saved_state;
724       }
725    }
726    else
727    {
728       // save output state, then turn it off:
729       output_state saved_state = m_state;
730       m_state = output_none;
731       // format until ':' or ')':
732       m_have_conditional = true;
733       format_all();
734       m_have_conditional = false;
735       // restore state:
736       m_state = saved_state;
737       if((m_position != m_end) && (*m_position == static_cast<char_type>(':')))
738       {
739          // skip the ':':
740          ++m_position;
741          // format the rest of this scope:
742          format_until_scope_end();
743       }
744    }
745 }
746 
747 template <class OutputIterator, class Results, class traits, class ForwardIter>
format_until_scope_end()748 void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_until_scope_end()
749 {
750    do
751    {
752       format_all();
753       if((m_position == m_end) || (*m_position == static_cast<char_type>(')')))
754          return;
755       put(*m_position++);
756    }while(m_position != m_end);
757 }
758 
759 template <class OutputIterator, class Results, class traits, class ForwardIter>
put(char_type c)760 void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::put(char_type c)
761 {
762    // write a single character to output
763    // according to which case translation mode we are in:
764    switch(this->m_state)
765    {
766    case output_none:
767       return;
768    case output_next_lower:
769       c = m_traits.tolower(c);
770       this->m_state = m_restore_state;
771       break;
772    case output_next_upper:
773       c = m_traits.toupper(c);
774       this->m_state = m_restore_state;
775       break;
776    case output_lower:
777       c = m_traits.tolower(c);
778       break;
779    case output_upper:
780       c = m_traits.toupper(c);
781       break;
782    default:
783       break;
784    }
785    *m_out = c;
786    ++m_out;
787 }
788 
789 template <class OutputIterator, class Results, class traits, class ForwardIter>
put(const sub_match_type & sub)790 void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::put(const sub_match_type& sub)
791 {
792    typedef typename sub_match_type::iterator iterator_type;
793    iterator_type i = sub.first;
794    while(i != sub.second)
795    {
796       put(*i);
797       ++i;
798    }
799 }
800 
801 template <class S>
802 class string_out_iterator
803 #ifndef BOOST_NO_STD_ITERATOR
804    : public std::iterator<std::output_iterator_tag, typename S::value_type>
805 #endif
806 {
807    S* out;
808 public:
string_out_iterator(S & s)809    string_out_iterator(S& s) : out(&s) {}
operator ++()810    string_out_iterator& operator++() { return *this; }
operator ++(int)811    string_out_iterator& operator++(int) { return *this; }
operator *()812    string_out_iterator& operator*() { return *this; }
operator =(typename S::value_type v)813    string_out_iterator& operator=(typename S::value_type v)
814    {
815       out->append(1, v);
816       return *this;
817    }
818 
819 #ifdef BOOST_NO_STD_ITERATOR
820    typedef std::ptrdiff_t difference_type;
821    typedef typename S::value_type value_type;
822    typedef value_type* pointer;
823    typedef value_type& reference;
824    typedef std::output_iterator_tag iterator_category;
825 #endif
826 };
827 
828 template <class OutputIterator, class Iterator, class Alloc, class ForwardIter, class traits>
829 OutputIterator regex_format_imp(OutputIterator out,
830                           const match_results<Iterator, Alloc>& m,
831                           ForwardIter p1, ForwardIter p2,
832                           match_flag_type flags,
833                           const traits& t
834                          )
835 {
836    if(flags & regex_constants::format_literal)
837    {
838       return re_detail::copy(p1, p2, out);
839    }
840 
841    re_detail::basic_regex_formatter<
842       OutputIterator,
843       match_results<Iterator, Alloc>,
844       traits, ForwardIter> f(out, m, t);
845    return f.format(p1, p2, flags);
846 }
847 
848 #ifndef BOOST_NO_SFINAE
849 
850 BOOST_MPL_HAS_XXX_TRAIT_DEF(const_iterator)
851 
852 struct any_type
853 {
854    template <class T>
855    any_type(const T&);
856    template <class T, class U>
857    any_type(const T&, const U&);
858    template <class T, class U, class V>
859    any_type(const T&, const U&, const V&);
860 };
861 typedef char no_type;
862 typedef char (&unary_type)[2];
863 typedef char (&binary_type)[3];
864 typedef char (&ternary_type)[4];
865 
866 no_type check_is_formatter(unary_type, binary_type, ternary_type);
867 template<typename T>
868 unary_type check_is_formatter(T const &, binary_type, ternary_type);
869 template<typename T>
870 binary_type check_is_formatter(unary_type, T const &, ternary_type);
871 template<typename T, typename U>
872 binary_type check_is_formatter(T const &, U const &, ternary_type);
873 template<typename T>
874 ternary_type check_is_formatter(unary_type, binary_type, T const &);
875 template<typename T, typename U>
876 ternary_type check_is_formatter(T const &, binary_type, U const &);
877 template<typename T, typename U>
878 ternary_type check_is_formatter(unary_type, T const &, U const &);
879 template<typename T, typename U, typename V>
880 ternary_type check_is_formatter(T const &, U const &, V const &);
881 
882 struct unary_binary_ternary
883 {
884     typedef unary_type (*unary_fun)(any_type);
885     typedef binary_type (*binary_fun)(any_type, any_type);
886     typedef ternary_type (*ternary_fun)(any_type, any_type, any_type);
887     operator unary_fun();
888     operator binary_fun();
889     operator ternary_fun();
890 };
891 
892 template<typename Formatter, bool IsFunction = boost::is_function<Formatter>::value>
893 struct formatter_wrapper
894   : Formatter
895   , unary_binary_ternary
896 {
formatter_wrapperboost::re_detail::formatter_wrapper897    formatter_wrapper(){}
898 };
899 
900 template<typename Formatter>
901 struct formatter_wrapper<Formatter, true>
902   : unary_binary_ternary
903 {
904     operator Formatter *();
905 };
906 
907 template<typename Formatter>
908 struct formatter_wrapper<Formatter *, false>
909   : unary_binary_ternary
910 {
911     operator Formatter *();
912 };
913 
914 template <class F, class M, class O>
915 struct format_traits_imp
916 {
917 private:
918    //
919    // F must be a pointer, a function, or a class with a function call operator:
920    //
921    BOOST_STATIC_ASSERT((::boost::is_pointer<F>::value || ::boost::is_function<F>::value || ::boost::is_class<F>::value));
922    static formatter_wrapper<typename unwrap_reference<F>::type> f;
923    static M m;
924    static O out;
925    static boost::regex_constants::match_flag_type flags;
926 public:
927    BOOST_STATIC_CONSTANT(int, value = sizeof(check_is_formatter(f(m), f(m, out), f(m, out, flags))));
928 };
929 
930 template <class F, class M, class O>
931 struct format_traits
932 {
933 public:
934    //
935    // Type is mpl::int_<N> where N is one of:
936    //
937    // 0 : F is a pointer to a presumably null-terminated string.
938    // 1 : F is a character-container such as a std::string.
939    // 2 : F is a Unary Functor.
940    // 3 : F is a Binary Functor.
941    // 4 : F is a Ternary Functor.
942    //
943    typedef typename boost::mpl::if_<
944       boost::mpl::and_<boost::is_pointer<F>, boost::mpl::not_<boost::is_function<typename boost::remove_pointer<F>::type> > >,
945       boost::mpl::int_<0>,
946       typename boost::mpl::if_<
947          has_const_iterator<F>,
948          boost::mpl::int_<1>,
949          boost::mpl::int_<format_traits_imp<F, M, O>::value>
950       >::type
951    >::type type;
952    //
953    // This static assertion will fail if the functor passed does not accept
954    // the same type of arguments passed.
955    //
956    BOOST_STATIC_ASSERT( boost::is_class<F>::value && !has_const_iterator<F>::value ? (type::value > 1) : true);
957 };
958 
959 #else // BOOST_NO_SFINAE
960 
961 template <class F, class M, class O>
962 struct format_traits
963 {
964 public:
965    //
966    // Type is mpl::int_<N> where N is one of:
967    //
968    // 0 : F is a pointer to a presumably null-terminated string.
969    // 1 : F is a character-container such as a std::string.
970    //
971    // Other options such as F being a Functor are not supported without
972    // SFINAE support.
973    //
974    typedef typename boost::mpl::if_<
975       boost::is_pointer<F>,
976       boost::mpl::int_<0>,
977       boost::mpl::int_<1>
978    >::type type;
979 };
980 
981 #endif // BOOST_NO_SFINAE
982 
983 template <class Base, class Match>
984 struct format_functor3
985 {
format_functor3boost::re_detail::format_functor3986    format_functor3(Base b) : func(b) {}
987    template <class OutputIter>
operator ()boost::re_detail::format_functor3988    OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f)
989    {
990       return boost::unwrap_ref(func)(m, i, f);
991    }
992    template <class OutputIter, class Traits>
993    OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits&)
994    {
995       return (*this)(m, i, f);
996    }
997 private:
998    Base func;
999    format_functor3(const format_functor3&);
1000    format_functor3& operator=(const format_functor3&);
1001 };
1002 
1003 template <class Base, class Match>
1004 struct format_functor2
1005 {
format_functor2boost::re_detail::format_functor21006    format_functor2(Base b) : func(b) {}
1007    template <class OutputIter>
operator ()boost::re_detail::format_functor21008    OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type /*f*/)
1009    {
1010       return boost::unwrap_ref(func)(m, i);
1011    }
1012    template <class OutputIter, class Traits>
1013    OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits&)
1014    {
1015       return (*this)(m, i, f);
1016    }
1017 private:
1018    Base func;
1019    format_functor2(const format_functor2&);
1020    format_functor2& operator=(const format_functor2&);
1021 };
1022 
1023 template <class Base, class Match>
1024 struct format_functor1
1025 {
format_functor1boost::re_detail::format_functor11026    format_functor1(Base b) : func(b) {}
1027 
1028    template <class S, class OutputIter>
do_format_stringboost::re_detail::format_functor11029    OutputIter do_format_string(const S& s, OutputIter i)
1030    {
1031       return re_detail::copy(s.begin(), s.end(), i);
1032    }
1033    template <class S, class OutputIter>
do_format_stringboost::re_detail::format_functor11034    inline OutputIter do_format_string(const S* s, OutputIter i)
1035    {
1036       while(s && *s)
1037       {
1038          *i = *s;
1039          ++i;
1040          ++s;
1041       }
1042       return i;
1043    }
1044    template <class OutputIter>
operator ()boost::re_detail::format_functor11045    OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type /*f*/)
1046    {
1047       return do_format_string(boost::unwrap_ref(func)(m), i);
1048    }
1049    template <class OutputIter, class Traits>
1050    OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits&)
1051    {
1052       return (*this)(m, i, f);
1053    }
1054 private:
1055    Base func;
1056    format_functor1(const format_functor1&);
1057    format_functor1& operator=(const format_functor1&);
1058 };
1059 
1060 template <class charT, class Match, class Traits>
1061 struct format_functor_c_string
1062 {
format_functor_c_stringboost::re_detail::format_functor_c_string1063    format_functor_c_string(const charT* ps) : func(ps) {}
1064 
1065    template <class OutputIter>
operator ()boost::re_detail::format_functor_c_string1066    OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits& t = Traits())
1067    {
1068       //typedef typename Match::char_type char_type;
1069       const charT* end = func;
1070       while(*end) ++end;
1071       return regex_format_imp(i, m, func, end, f, t);
1072    }
1073 private:
1074    const charT* func;
1075    format_functor_c_string(const format_functor_c_string&);
1076    format_functor_c_string& operator=(const format_functor_c_string&);
1077 };
1078 
1079 template <class Container, class Match, class Traits>
1080 struct format_functor_container
1081 {
format_functor_containerboost::re_detail::format_functor_container1082    format_functor_container(const Container& c) : func(c) {}
1083 
1084    template <class OutputIter>
operator ()boost::re_detail::format_functor_container1085    OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits& t = Traits())
1086    {
1087       //typedef typename Match::char_type char_type;
1088       return re_detail::regex_format_imp(i, m, func.begin(), func.end(), f, t);
1089    }
1090 private:
1091    const Container& func;
1092    format_functor_container(const format_functor_container&);
1093    format_functor_container& operator=(const format_functor_container&);
1094 };
1095 
1096 template <class Func, class Match, class OutputIterator, class Traits = re_detail::trivial_format_traits<typename Match::char_type> >
1097 struct compute_functor_type
1098 {
1099    typedef typename format_traits<Func, Match, OutputIterator>::type tag;
1100    typedef typename boost::remove_cv< typename boost::remove_pointer<Func>::type>::type maybe_char_type;
1101 
1102    typedef typename mpl::if_<
1103       ::boost::is_same<tag, mpl::int_<0> >, format_functor_c_string<maybe_char_type, Match, Traits>,
1104       typename mpl::if_<
1105          ::boost::is_same<tag, mpl::int_<1> >, format_functor_container<Func, Match, Traits>,
1106          typename mpl::if_<
1107             ::boost::is_same<tag, mpl::int_<2> >, format_functor1<Func, Match>,
1108             typename mpl::if_<
1109                ::boost::is_same<tag, mpl::int_<3> >, format_functor2<Func, Match>,
1110                format_functor3<Func, Match>
1111             >::type
1112          >::type
1113       >::type
1114    >::type type;
1115 };
1116 
1117 } // namespace re_detail
1118 
1119 template <class OutputIterator, class Iterator, class Allocator, class Functor>
regex_format(OutputIterator out,const match_results<Iterator,Allocator> & m,Functor fmt,match_flag_type flags=format_all)1120 inline OutputIterator regex_format(OutputIterator out,
1121                           const match_results<Iterator, Allocator>& m,
1122                           Functor fmt,
1123                           match_flag_type flags = format_all
1124                          )
1125 {
1126    return m.format(out, fmt, flags);
1127 }
1128 
1129 template <class Iterator, class Allocator, class Functor>
regex_format(const match_results<Iterator,Allocator> & m,Functor fmt,match_flag_type flags=format_all)1130 inline std::basic_string<typename match_results<Iterator, Allocator>::char_type> regex_format(const match_results<Iterator, Allocator>& m,
1131                                       Functor fmt,
1132                                       match_flag_type flags = format_all)
1133 {
1134    return m.format(fmt, flags);
1135 }
1136 
1137 #ifdef BOOST_MSVC
1138 #pragma warning(push)
1139 #pragma warning(disable: 4103)
1140 #endif
1141 #ifdef BOOST_HAS_ABI_HEADERS
1142 #  include BOOST_ABI_SUFFIX
1143 #endif
1144 #ifdef BOOST_MSVC
1145 #pragma warning(pop)
1146 #endif
1147 
1148 } // namespace boost
1149 
1150 #endif  // BOOST_REGEX_FORMAT_HPP
1151 
1152 
1153 
1154 
1155 
1156 
1157