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