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