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 RandomAccessIterator, class Allocator>
39 template <class O, class I>
40 O BOOST_REGEX_CALL re_copy_out(O out, I first, I last)
51 template <class charT, class traits_type>
52 void BOOST_REGEX_CALL re_skip_format(const charT*& fmt, const traits_type& traits_inst)
54 // dwa 9/13/00 - suppress incorrect unused parameter warning for MSVC
57 typedef typename traits_type::size_type traits_size_type;
58 typedef typename traits_type::uchar_type traits_uchar_type;
59 typedef typename traits_type::string_type traits_string_type;
61 unsigned int parens = 0;
65 c = traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt));
66 if((c == traits_type::syntax_colon) && (parens == 0))
71 else if(c == traits_type::syntax_close_bracket)
80 else if(c == traits_type::syntax_open_bracket)
82 else if(c == traits_type::syntax_slash)
92 #ifdef BOOST_NO_STD_OUTPUT_ITERATOR_ASSIGN
95 // ugly hack for buggy output iterators
98 inline void oi_assign(T* p, T v)
100 ::boost::re_detail::pointer_destroy(p);
101 pointer_construct(p, v);
107 inline void oi_assign(T* p, T v)
110 // if you get a compile time error in here then you either
111 // need to rewrite your output iterator to make it assignable
112 // (as is required by the standard), or define
113 // BOOST_NO_STD_OUTPUT_ITERATOR_ASSIGN to use the ugly hack above
120 #if defined(BOOST_REGEX_NO_TEMPLATE_SWITCH_MERGE)
123 // template don't merge if they contain switch statements so declare these
124 // templates in unnamed namespace (ie with internal linkage), each translation
125 // unit then gets its own local copy, it works seemlessly but bloats the app.
130 // algorithm reg_format:
131 // takes the result of a match and a format string
132 // and merges them to produce a new string which
133 // is sent to an OutputIterator,
134 // _reg_format_aux does the actual work:
136 template <class OutputIterator, class Iterator, class Allocator, class charT, class traits_type>
137 OutputIterator BOOST_REGEX_CALL _reg_format_aux(OutputIterator out,
138 const match_results<Iterator, Allocator>& m,
140 match_flag_type flags, const traits_type& traits_inst)
143 #pragma option push -w-8037
145 const charT* fmt_end = fmt;
146 while(*fmt_end) ++ fmt_end;
148 typedef typename traits_type::size_type traits_size_type;
149 typedef typename traits_type::uchar_type traits_uchar_type;
150 typedef typename traits_type::string_type traits_string_type;
154 switch(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)))
156 case traits_type::syntax_dollar:
157 if(flags & format_sed)
159 // no perl style replacement,
160 // $ is an ordinary character:
164 if(*fmt == 0) // oops trailing $
171 switch(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)))
173 case traits_type::syntax_start_buffer:
174 oi_assign(&out, re_copy_out(out, Iterator(m[-1].first), Iterator(m[-1].second)));
177 case traits_type::syntax_end_buffer:
178 oi_assign(&out, re_copy_out(out, Iterator(m[-2].first), Iterator(m[-2].second)));
181 case traits_type::syntax_digit:
184 unsigned int index = traits_inst.toi(fmt, fmt_end, 10);
186 oi_assign(&out, re_copy_out(out, Iterator(m[index].first), Iterator(m[index].second)));
193 oi_assign(&out, re_copy_out(out, Iterator(m[0].first), Iterator(m[0].second)));
198 // probably an error, treat as a literal '$'
205 case traits_type::syntax_slash:
218 switch(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)))
220 case traits_type::syntax_a:
224 case traits_type::syntax_f:
228 case traits_type::syntax_n:
232 case traits_type::syntax_r:
236 case traits_type::syntax_t:
240 case traits_type::syntax_v:
244 case traits_type::syntax_x:
252 // maybe have \x{ddd}
253 if(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)) == traits_type::syntax_open_brace)
264 if(traits_inst.is_class(*fmt, traits_type::char_class_xdigit) == false)
272 c = (charT)traits_inst.toi(fmt, fmt_end, -16);
273 if(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)) != traits_type::syntax_close_brace)
275 while(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)) != traits_type::syntax_slash)
288 if(traits_inst.is_class(*fmt, traits_type::char_class_xdigit) == false)
296 c = (charT)traits_inst.toi(fmt, fmt_end, -16);
299 case traits_type::syntax_c:
308 if(((typename traits_type::uchar_type)(*fmt) < (typename traits_type::uchar_type)'@')
309 || ((typename traits_type::uchar_type)(*fmt) > (typename traits_type::uchar_type)127) )
317 c = (charT)((typename traits_type::uchar_type)(*fmt) - (typename traits_type::uchar_type)'@');
320 case traits_type::syntax_e:
324 case traits_type::syntax_digit:
325 if(flags & format_sed)
328 c = (charT)traits_inst.toi(fmt, fmt_end, -8);
338 case traits_type::syntax_open_bracket:
339 if(0 == (flags & format_all))
349 oi_assign(&out, _reg_format_aux(out, m, fmt, flags, traits_inst));
352 case traits_type::syntax_close_bracket:
353 if(0 == (flags & format_all))
362 ++fmt; // return from recursion
365 case traits_type::syntax_colon:
366 if(flags & regex_constants::format_is_if)
375 case traits_type::syntax_question:
377 if(0 == (flags & format_all))
395 unsigned int id = traits_inst.toi(fmt, fmt_end, 10);
398 oi_assign(&out, _reg_format_aux(out, m, fmt, flags | regex_constants::format_is_if, traits_inst));
399 if(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*(fmt-1))) == traits_type::syntax_colon)
400 re_skip_format(fmt, traits_inst);
404 re_skip_format(fmt, traits_inst);
405 if(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*(fmt-1))) == traits_type::syntax_colon)
406 oi_assign(&out, _reg_format_aux(out, m, fmt, flags | regex_constants::format_is_if, traits_inst));
413 if((flags & format_sed) && (*fmt == '&'))
415 oi_assign(&out, re_copy_out(out, Iterator(m[0].first), Iterator(m[0].second)));
431 #if defined(BOOST_REGEX_NO_TEMPLATE_SWITCH_MERGE)
436 class string_out_iterator
440 string_out_iterator(S& s) : out(&s) {}
441 string_out_iterator& operator++() { return *this; }
442 string_out_iterator& operator++(int) { return *this; }
443 string_out_iterator& operator*() { return *this; }
444 string_out_iterator& operator=(typename S::value_type v)
451 template <class OutputIterator, class Iterator, class charT, class Allocator, class traits_type>
452 class merge_out_predicate
457 match_flag_type flags;
458 const traits_type* pt;
459 // rebind allocator to correct type:
460 typedef typename detail::rebind_allocator<sub_match<Iterator>, Allocator>::type alloc_type;
463 merge_out_predicate(OutputIterator& o, Iterator& pi, const charT* f, match_flag_type format_flags, const traits_type& p)
464 : out(&o), last(&pi), fmt(f), flags(format_flags), pt(&p){}
466 ~merge_out_predicate() {}
467 bool BOOST_REGEX_CALL operator()(const boost::match_results<Iterator, alloc_type>& m)
469 const charT* f = fmt;
470 if(0 == (flags & format_no_copy))
471 oi_assign(out, re_copy_out(*out, Iterator(m[-1].first), Iterator(m[-1].second)));
472 oi_assign(out, _reg_format_aux(*out, m, f, flags, *pt));
474 return flags & format_first_only ? false : true;
478 } // namespace re_detail
480 template <class OutputIterator, class Iterator, class Allocator, class charT>
481 OutputIterator regex_format(OutputIterator out,
482 const match_results<Iterator, Allocator>& m,
484 match_flag_type flags = format_all
487 regex_traits<charT> t;
488 return re_detail::_reg_format_aux(out, m, fmt, flags, t);
491 template <class OutputIterator, class Iterator, class Allocator, class charT>
492 OutputIterator regex_format(OutputIterator out,
493 const match_results<Iterator, Allocator>& m,
494 const std::basic_string<charT>& fmt,
495 match_flag_type flags = format_all
498 regex_traits<charT> t;
499 const charT* start = fmt.c_str();
500 return re_detail::_reg_format_aux(out, m, start, flags, t);
503 template <class Iterator, class Allocator, class charT>
504 std::basic_string<charT> regex_format(const match_results<Iterator, Allocator>& m,
506 match_flag_type flags = format_all)
508 std::basic_string<charT> result;
509 re_detail::string_out_iterator<std::basic_string<charT> > i(result);
510 regex_format(i, m, fmt, flags);
514 template <class Iterator, class Allocator, class charT>
515 std::basic_string<charT> regex_format(const match_results<Iterator, Allocator>& m,
516 const std::basic_string<charT>& fmt,
517 match_flag_type flags = format_all)
519 std::basic_string<charT> result;
520 re_detail::string_out_iterator<std::basic_string<charT> > i(result);
521 regex_format(i, m, fmt.c_str(), flags);
525 #ifdef BOOST_HAS_ABI_HEADERS
526 # include BOOST_ABI_SUFFIX
531 #endif // BOOST_REGEX_FORMAT_HPP