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
39namespace 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 >
56class match_results;
57
58namespace 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//
65template <class charT>
66struct 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 global_toi(p1, p2, radix, *this);
90 }
91};
92
93template <class OutputIterator, class Results, class traits, class ForwardIter>
94class basic_regex_formatter
95{
96public:
97 typedef typename traits::char_type char_type;
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);
101 OutputIterator format(ForwardIter p1, match_flag_type f)
102 {
103 return format(p1, p1 + m_traits.length(p1), f);
104 }
105private:
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
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 }
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 }
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 }
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 }
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 }
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
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
177 inline int toi(ForwardIter& i, ForwardIter j, int base, const boost::mpl::true_&)
178 {
179 return m_traits.toi(i, j, base);
180 }
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
202private:
203 basic_regex_formatter(const basic_regex_formatter&);
204 basic_regex_formatter& operator=(const basic_regex_formatter&);
205};
206
207template <class OutputIterator, class Results, class traits, class ForwardIter>
208OutputIterator 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
217template <class OutputIterator, class Results, class traits, class ForwardIter>
218void 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
296template <class OutputIterator, class Results, class traits, class ForwardIter>
297void 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::BOOST_REGEX_DETAIL_NS::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
385template <class OutputIterator, class Results, class traits, class ForwardIter>
386bool 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
504template <class OutputIterator, class Results, class traits, class ForwardIter>
505void 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::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end);
574 len = (std::min)(a: static_cast<std::ptrdiff_t>(2), b: 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::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end);
638 len = (std::min)(a: static_cast<std::ptrdiff_t>(1), b: 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::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end);
650 len = (std::min)(a: static_cast<std::ptrdiff_t>(4), b: 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
662template <class OutputIterator, class Results, class traits, class ForwardIter>
663void 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::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end);
697 len = (std::min)(a: static_cast<std::ptrdiff_t>(2), b: 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
747template <class OutputIterator, class Results, class traits, class ForwardIter>
748void 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
759template <class OutputIterator, class Results, class traits, class ForwardIter>
760void 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
789template <class OutputIterator, class Results, class traits, class ForwardIter>
790void 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
801template <class S>
802class 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;
808public:
809 string_out_iterator(S& s) : out(&s) {}
810 string_out_iterator& operator++() { return *this; }
811 string_out_iterator& operator++(int) { return *this; }
812 string_out_iterator& operator*() { return *this; }
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
828template <class OutputIterator, class Iterator, class Alloc, class ForwardIter, class traits>
829OutputIterator 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 BOOST_REGEX_DETAIL_NS::copy(p1, p2, out);
839 }
840
841 BOOST_REGEX_DETAIL_NS::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
850BOOST_MPL_HAS_XXX_TRAIT_DEF(const_iterator)
851
852struct 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};
861typedef char no_type;
862typedef char (&unary_type)[2];
863typedef char (&binary_type)[3];
864typedef char (&ternary_type)[4];
865
866no_type check_is_formatter(unary_type, binary_type, ternary_type);
867template<typename T>
868unary_type check_is_formatter(T const &, binary_type, ternary_type);
869template<typename T>
870binary_type check_is_formatter(unary_type, T const &, ternary_type);
871template<typename T, typename U>
872binary_type check_is_formatter(T const &, U const &, ternary_type);
873template<typename T>
874ternary_type check_is_formatter(unary_type, binary_type, T const &);
875template<typename T, typename U>
876ternary_type check_is_formatter(T const &, binary_type, U const &);
877template<typename T, typename U>
878ternary_type check_is_formatter(unary_type, T const &, U const &);
879template<typename T, typename U, typename V>
880ternary_type check_is_formatter(T const &, U const &, V const &);
881
882struct 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
892template<typename Formatter, bool IsFunction = boost::is_function<Formatter>::value>
893struct formatter_wrapper
894 : Formatter
895 , unary_binary_ternary
896{
897 formatter_wrapper(){}
898};
899
900template<typename Formatter>
901struct formatter_wrapper<Formatter, true>
902 : unary_binary_ternary
903{
904 operator Formatter *();
905};
906
907template<typename Formatter>
908struct formatter_wrapper<Formatter *, false>
909 : unary_binary_ternary
910{
911 operator Formatter *();
912};
913
914template <class F, class M, class O>
915struct format_traits_imp
916{
917private:
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;
926public:
927 BOOST_STATIC_CONSTANT(int, value = sizeof(check_is_formatter(f(m), f(m, out), f(m, out, flags))));
928};
929
930template <class F, class M, class O>
931struct format_traits
932{
933public:
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
961template <class F, class M, class O>
962struct format_traits
963{
964public:
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
983template <class Base, class Match>
984struct format_functor3
985{
986 format_functor3(Base b) : func(b) {}
987 template <class OutputIter>
988 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 }
997private:
998 Base func;
999 format_functor3(const format_functor3&);
1000 format_functor3& operator=(const format_functor3&);
1001};
1002
1003template <class Base, class Match>
1004struct format_functor2
1005{
1006 format_functor2(Base b) : func(b) {}
1007 template <class OutputIter>
1008 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 }
1017private:
1018 Base func;
1019 format_functor2(const format_functor2&);
1020 format_functor2& operator=(const format_functor2&);
1021};
1022
1023template <class Base, class Match>
1024struct format_functor1
1025{
1026 format_functor1(Base b) : func(b) {}
1027
1028 template <class S, class OutputIter>
1029 OutputIter do_format_string(const S& s, OutputIter i)
1030 {
1031 return BOOST_REGEX_DETAIL_NS::copy(s.begin(), s.end(), i);
1032 }
1033 template <class S, class OutputIter>
1034 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>
1045 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 }
1054private:
1055 Base func;
1056 format_functor1(const format_functor1&);
1057 format_functor1& operator=(const format_functor1&);
1058};
1059
1060template <class charT, class Match, class Traits>
1061struct format_functor_c_string
1062{
1063 format_functor_c_string(const charT* ps) : func(ps) {}
1064
1065 template <class OutputIter>
1066 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 }
1073private:
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
1079template <class Container, class Match, class Traits>
1080struct format_functor_container
1081{
1082 format_functor_container(const Container& c) : func(c) {}
1083
1084 template <class OutputIter>
1085 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 BOOST_REGEX_DETAIL_NS::regex_format_imp(i, m, func.begin(), func.end(), f, t);
1089 }
1090private:
1091 const Container& func;
1092 format_functor_container(const format_functor_container&);
1093 format_functor_container& operator=(const format_functor_container&);
1094};
1095
1096template <class Func, class Match, class OutputIterator, class Traits = BOOST_REGEX_DETAIL_NS::trivial_format_traits<typename Match::char_type> >
1097struct 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 BOOST_REGEX_DETAIL_NS
1118
1119template <class OutputIterator, class Iterator, class Allocator, class Functor>
1120inline 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
1129template <class Iterator, class Allocator, class Functor>
1130inline 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

source code of boost/boost/regex/v4/regex_format.hpp