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