3 * Copyright (c) 1998-2002
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)
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.
21 #ifndef BOOST_REGEX_FORMAT_HPP
22 #define BOOST_REGEX_FORMAT_HPP
27 #ifdef BOOST_HAS_ABI_HEADERS
28 # include BOOST_ABI_PREFIX
32 // Forward declaration:
34 template <class BidiIterator, class Allocator = BOOST_DEDUCED_TYPENAME std::vector<sub_match<BidiIterator> >::allocator_type >
40 // struct trivial_format_traits:
41 // defines minimum localisation support for formatting
42 // in the case that the actual regex traits is unavailable.
44 template <class charT>
45 struct trivial_format_traits
47 typedef charT char_type;
49 static std::ptrdiff_t length(const charT* p)
51 return global_length(p);
53 static charT tolower(charT c)
55 return ::boost::re_detail::global_lower(c);
57 static charT toupper(charT c)
59 return ::boost::re_detail::global_upper(c);
61 static int value(const charT c, int radix)
63 int result = global_value(c);
64 return result >= radix ? -1 : result;
66 int toi(const charT*& p1, const charT* p2, int radix)const
68 return global_toi(p1, p2, radix, *this);
72 template <class OutputIterator, class Results, class traits>
73 class basic_regex_formatter
76 typedef typename traits::char_type char_type;
77 basic_regex_formatter(OutputIterator o, const Results& r, const traits& t)
78 : m_traits(t), m_results(r), m_out(o), m_state(output_copy), m_have_conditional(false) {}
79 OutputIterator format(const char_type* p1, const char_type* p2, match_flag_type f);
80 OutputIterator format(const char_type* p1, match_flag_type f)
82 return format(p1, p1 + m_traits.length(p1), f);
85 typedef typename Results::value_type sub_match_type;
96 void put(char_type c);
97 void put(const sub_match_type& sub);
100 void format_escape();
101 void format_conditional();
102 void format_until_scope_end();
104 const traits& m_traits; // the traits class for localised formatting operations
105 const Results& m_results; // the match_results being used.
106 OutputIterator m_out; // where to send output.
107 const char_type* m_position; // format string, current position
108 const char_type* m_end; // format string end
109 match_flag_type m_flags; // format flags to use
110 output_state m_state; // what to do with the next character
111 bool m_have_conditional; // we are parsing a conditional
113 basic_regex_formatter(const basic_regex_formatter&);
114 basic_regex_formatter& operator=(const basic_regex_formatter&);
117 template <class OutputIterator, class Results, class traits>
118 OutputIterator basic_regex_formatter<OutputIterator, Results, traits>::format(const char_type* p1, const char_type* p2, match_flag_type f)
127 template <class OutputIterator, class Results, class traits>
128 void basic_regex_formatter<OutputIterator, Results, traits>::format_all()
131 while(m_position != m_end)
136 if(m_flags & ::boost::regex_constants::format_sed)
148 if(m_flags & boost::regex_constants::format_all)
151 bool have_conditional = m_have_conditional;
152 m_have_conditional = false;
153 format_until_scope_end();
154 m_have_conditional = have_conditional;
155 if(m_position == m_end)
157 BOOST_ASSERT(*m_position == static_cast<char_type>(')'));
158 ++m_position; // skip the closing ')'
165 if(m_flags & boost::regex_constants::format_all)
173 if((m_flags & boost::regex_constants::format_all) && m_have_conditional)
181 if(m_flags & boost::regex_constants::format_all)
184 format_conditional();
191 if((m_flags & format_sed) == 0)
196 // fall through, not a special character:
205 template <class OutputIterator, class Results, class traits>
206 void basic_regex_formatter<OutputIterator, Results, traits>::format_perl()
209 // On entry *m_position points to a '$' character
210 // output the information that goes with it:
212 BOOST_ASSERT(*m_position == '$');
214 // see if this is a trailing '$':
216 if(++m_position == m_end)
224 // OK find out what kind it is:
230 put(this->m_results[0]);
234 put(this->m_results.prefix());
238 put(this->m_results.suffix());
244 // see if we have a number:
246 std::ptrdiff_t len = ::boost::re_detail::distance(m_position, m_end);
247 len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
248 int v = m_traits.toi(m_position, m_position + len, 10);
251 // leave the $ as is, and carry on:
257 // otherwise output sub v:
258 put(this->m_results[v]);
263 template <class OutputIterator, class Results, class traits>
264 void basic_regex_formatter<OutputIterator, Results, traits>::format_escape()
266 // skip the escape and check for trailing escape:
267 if(++m_position == m_end)
269 put(static_cast<char_type>('\\'));
272 // now switch on the escape type:
276 put(static_cast<char_type>('\a'));
280 put(static_cast<char_type>('\f'));
284 put(static_cast<char_type>('\n'));
288 put(static_cast<char_type>('\r'));
292 put(static_cast<char_type>('\t'));
296 put(static_cast<char_type>('\v'));
300 if(++m_position == m_end)
302 put(static_cast<char_type>('x'));
305 // maybe have \x{ddd}
306 if(*m_position == static_cast<char_type>('{'))
309 int val = m_traits.toi(m_position, m_end, 16);
312 // invalid value treat everything as literals:
313 put(static_cast<char_type>('x'));
314 put(static_cast<char_type>('{'));
317 if(*m_position != static_cast<char_type>('}'))
319 while(*m_position != static_cast<char_type>('\\'))
326 put(static_cast<char_type>(val));
331 std::ptrdiff_t len = ::boost::re_detail::distance(m_position, m_end);
332 len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
333 int val = m_traits.toi(m_position, m_position + len, 16);
340 put(static_cast<char_type>(val));
344 if(++m_position == m_end)
350 put(static_cast<char_type>(*m_position++ % 32));
353 put(static_cast<char_type>(27));
357 // see if we have a perl specific escape:
358 if((m_flags & boost::regex_constants::format_sed) == 0)
360 bool breakout = false;
365 m_state = output_next_lower;
370 m_state = output_lower;
375 m_state = output_next_upper;
380 m_state = output_upper;
385 m_state = output_copy;
392 // see if we have a \n sed style backreference:
393 int v = m_traits.toi(m_position, m_position+1, 10);
394 if((v > 0) || ((v == 0) && (m_flags & ::boost::regex_constants::format_sed)))
401 // octal ecape sequence:
403 std::ptrdiff_t len = ::boost::re_detail::distance(m_position, m_end);
404 len = (std::min)(static_cast<std::ptrdiff_t>(4), len);
405 v = m_traits.toi(m_position, m_position + len, 8);
406 BOOST_ASSERT(v >= 0);
407 put(static_cast<char_type>(v));
410 // Otherwise output the character "as is":
416 template <class OutputIterator, class Results, class traits>
417 void basic_regex_formatter<OutputIterator, Results, traits>::format_conditional()
419 if(m_position == m_end)
421 // oops trailing '?':
422 put(static_cast<char_type>('?'));
425 std::ptrdiff_t len = ::boost::re_detail::distance(m_position, m_end);
426 len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
427 int v = m_traits.toi(m_position, m_position + len, 10);
430 // oops not a number:
431 put(static_cast<char_type>('?'));
435 // output varies depending upon whether sub-expression v matched or not:
436 if(m_results[v].matched)
438 m_have_conditional = true;
440 m_have_conditional = false;
441 if((m_position != m_end) && (*m_position == static_cast<char_type>(':')))
445 // save output state, then turn it off:
446 output_state saved_state = m_state;
447 m_state = output_none;
448 // format the rest of this scope:
449 format_until_scope_end();
450 // restore output state:
451 m_state = saved_state;
456 // save output state, then turn it off:
457 output_state saved_state = m_state;
458 m_state = output_none;
459 // format until ':' or ')':
460 m_have_conditional = true;
462 m_have_conditional = false;
464 m_state = saved_state;
465 if((m_position != m_end) && (*m_position == static_cast<char_type>(':')))
469 // format the rest of this scope:
470 format_until_scope_end();
475 template <class OutputIterator, class Results, class traits>
476 void basic_regex_formatter<OutputIterator, Results, traits>::format_until_scope_end()
481 if((m_position == m_end) || (*m_position == static_cast<char_type>(')')))
484 }while(m_position != m_end);
487 template <class OutputIterator, class Results, class traits>
488 void basic_regex_formatter<OutputIterator, Results, traits>::put(char_type c)
490 // write a single character to output
491 // according to which case translation mode we are in:
492 switch(this->m_state)
496 case output_next_lower:
497 c = m_traits.tolower(c);
498 this->m_state = output_copy;
500 case output_next_upper:
501 c = m_traits.toupper(c);
502 this->m_state = output_copy;
505 c = m_traits.tolower(c);
508 c = m_traits.toupper(c);
517 template <class OutputIterator, class Results, class traits>
518 void basic_regex_formatter<OutputIterator, Results, traits>::put(const sub_match_type& sub)
520 typedef typename sub_match_type::iterator iterator_type;
521 iterator_type i = sub.first;
522 while(i != sub.second)
530 class string_out_iterator
531 #ifndef BOOST_NO_STD_ITERATOR
532 : public std::iterator<std::output_iterator_tag, typename S::value_type>
537 string_out_iterator(S& s) : out(&s) {}
538 string_out_iterator& operator++() { return *this; }
539 string_out_iterator& operator++(int) { return *this; }
540 string_out_iterator& operator*() { return *this; }
541 string_out_iterator& operator=(typename S::value_type v)
547 #ifdef BOOST_NO_STD_ITERATOR
548 typedef std::ptrdiff_t difference_type;
549 typedef typename S::value_type value_type;
550 typedef value_type* pointer;
551 typedef value_type& reference;
552 typedef std::output_iterator_tag iterator_category;
556 template <class OutputIterator, class Iterator, class Alloc, class charT, class traits>
557 OutputIterator regex_format_imp(OutputIterator out,
558 const match_results<Iterator, Alloc>& m,
559 const charT* p1, const charT* p2,
560 match_flag_type flags,
564 if(flags & regex_constants::format_literal)
566 return re_detail::copy(p1, p2, out);
569 re_detail::basic_regex_formatter<
571 match_results<Iterator, Alloc>,
572 traits > f(out, m, t);
573 return f.format(p1, p2, flags);
577 } // namespace re_detail
579 template <class OutputIterator, class Iterator, class charT>
580 OutputIterator regex_format(OutputIterator out,
581 const match_results<Iterator>& m,
583 match_flag_type flags = format_all
586 re_detail::trivial_format_traits<charT> traits;
587 return re_detail::regex_format_imp(out, m, fmt, fmt + traits.length(fmt), flags, traits);
590 template <class OutputIterator, class Iterator, class charT>
591 OutputIterator regex_format(OutputIterator out,
592 const match_results<Iterator>& m,
593 const std::basic_string<charT>& fmt,
594 match_flag_type flags = format_all
597 re_detail::trivial_format_traits<charT> traits;
598 return re_detail::regex_format_imp(out, m, fmt.data(), fmt.data() + fmt.size(), flags, traits);
601 template <class Iterator, class charT>
602 std::basic_string<charT> regex_format(const match_results<Iterator>& m,
604 match_flag_type flags = format_all)
606 std::basic_string<charT> result;
607 re_detail::string_out_iterator<std::basic_string<charT> > i(result);
608 re_detail::trivial_format_traits<charT> traits;
609 re_detail::regex_format_imp(i, m, fmt, fmt + traits.length(fmt), flags, traits);
613 template <class Iterator, class charT>
614 std::basic_string<charT> regex_format(const match_results<Iterator>& m,
615 const std::basic_string<charT>& fmt,
616 match_flag_type flags = format_all)
618 std::basic_string<charT> result;
619 re_detail::string_out_iterator<std::basic_string<charT> > i(result);
620 re_detail::trivial_format_traits<charT> traits;
621 re_detail::regex_format_imp(i, m, fmt.data(), fmt.data() + fmt.size(), flags, traits);
625 #ifdef BOOST_HAS_ABI_HEADERS
626 # include BOOST_ABI_SUFFIX
631 #endif // BOOST_REGEX_FORMAT_HPP