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
lengthboost::BOOST_REGEX_DETAIL_NS::trivial_format_traits70 static std::ptrdiff_t length(const charT* p)
71 {
72 return global_length(p);
73 }
tolowerboost::BOOST_REGEX_DETAIL_NS::trivial_format_traits74 static charT tolower(charT c)
75 {
76 return ::boost::BOOST_REGEX_DETAIL_NS::global_lower(c);
77 }
toupperboost::BOOST_REGEX_DETAIL_NS::trivial_format_traits78 static charT toupper(charT c)
79 {
80 return ::boost::BOOST_REGEX_DETAIL_NS::global_upper(c);
81 }
valueboost::BOOST_REGEX_DETAIL_NS::trivial_format_traits82 static int value(const charT c, int radix)
83 {
84 int result = global_value(c);
85 return result >= radix ? -1 : result;
86 }
toiboost::BOOST_REGEX_DETAIL_NS::trivial_format_traits87 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;
basic_regex_formatter(OutputIterator o,const Results & r,const traits & t)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);
format(ForwardIter p1,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
get_named_sub(ForwardIter i,ForwardIter j,const mpl::false_ &)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 }
get_named_sub(ForwardIter i,ForwardIter j,const mpl::true_ &)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 }
get_named_sub(ForwardIter i,ForwardIter j)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 }
get_named_sub_index(ForwardIter i,ForwardIter j,const mpl::false_ &)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 }
get_named_sub_index(ForwardIter i,ForwardIter j,const mpl::true_ &)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 }
get_named_sub_index(ForwardIter i,ForwardIter j)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
toi(ForwardIter & i,ForwardIter j,int base,const boost::mpl::false_ &)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
toi(ForwardIter & i,ForwardIter j,int base,const boost::mpl::true_ &)181 inline int toi(ForwardIter& i, ForwardIter j, int base, const boost::mpl::true_&)
182 {
183 return m_traits.toi(i, j, base);
184 }
toi(ForwardIter & i,ForwardIter j,int base)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>
format(ForwardIter p1,ForwardIter p2,match_flag_type f)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>
format_all()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>
format_perl()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>
handle_perl_verb(bool have_brace)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>
format_escape()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>
format_conditional()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>
format_until_scope_end()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>
put(char_type c)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>
put(const sub_match_type & sub)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:
string_out_iterator(S & s)813 string_out_iterator(S& s) : out(&s) {}
operator ++()814 string_out_iterator& operator++() { return *this; }
operator ++(int)815 string_out_iterator& operator++(int) { return *this; }
operator *()816 string_out_iterator& operator*() { return *this; }
operator =(typename S::value_type v)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>
regex_format_imp(OutputIterator out,const match_results<Iterator,Alloc> & m,ForwardIter p1,ForwardIter p2,match_flag_type flags,const traits & t)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 {
formatter_wrapperboost::BOOST_REGEX_DETAIL_NS::formatter_wrapper899 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 {
format_functor3boost::BOOST_REGEX_DETAIL_NS::format_functor3988 format_functor3(Base b) : func(b) {}
989 template <class OutputIter>
operator ()boost::BOOST_REGEX_DETAIL_NS::format_functor3990 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>
operator ()boost::BOOST_REGEX_DETAIL_NS::format_functor3995 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 {
format_functor2boost::BOOST_REGEX_DETAIL_NS::format_functor21008 format_functor2(Base b) : func(b) {}
1009 template <class OutputIter>
operator ()boost::BOOST_REGEX_DETAIL_NS::format_functor21010 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>
operator ()boost::BOOST_REGEX_DETAIL_NS::format_functor21015 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 {
format_functor1boost::BOOST_REGEX_DETAIL_NS::format_functor11028 format_functor1(Base b) : func(b) {}
1029
1030 template <class S, class OutputIter>
do_format_stringboost::BOOST_REGEX_DETAIL_NS::format_functor11031 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>
do_format_stringboost::BOOST_REGEX_DETAIL_NS::format_functor11036 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>
operator ()boost::BOOST_REGEX_DETAIL_NS::format_functor11047 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>
operator ()boost::BOOST_REGEX_DETAIL_NS::format_functor11052 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 {
format_functor_c_stringboost::BOOST_REGEX_DETAIL_NS::format_functor_c_string1065 format_functor_c_string(const charT* ps) : func(ps) {}
1066
1067 template <class OutputIter>
operator ()boost::BOOST_REGEX_DETAIL_NS::format_functor_c_string1068 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 {
format_functor_containerboost::BOOST_REGEX_DETAIL_NS::format_functor_container1084 format_functor_container(const Container& c) : func(c) {}
1085
1086 template <class OutputIter>
operator ()boost::BOOST_REGEX_DETAIL_NS::format_functor_container1087 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>
regex_format(OutputIterator out,const match_results<Iterator,Allocator> & m,Functor fmt,match_flag_type flags=format_all)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>
regex_format(const match_results<Iterator,Allocator> & m,Functor fmt,match_flag_type flags=format_all)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