3 * Copyright (c) 1998-2000
6 * Permission to use, copy, modify, distribute and sell this software
7 * and its documentation for any purpose is hereby granted without fee,
8 * provided that the above copyright notice appear in all copies and
9 * that both that copyright notice and this permission notice appear
10 * in supporting documentation. Dr John Maddock makes no representations
11 * about the suitability of this software for any purpose.
12 * It is provided "as is" without express or implied warranty.
17 * LOCATION: see http://www.boost.org for most recent version.
18 * FILE regex_format.hpp
20 * DESCRIPTION: Provides formatting output routines for search and replace
21 * operations. Note this is an internal header file included
22 * by regex.hpp, do not include on its own.
25 #ifndef BOOST_REGEX_FORMAT_HPP
26 #define BOOST_REGEX_FORMAT_HPP
32 format_all = 0, // enable all extentions to sytax
33 format_sed = match_max << 1, // sed style replacement.
34 format_perl = format_sed << 1, // perl style replacement.
35 format_no_copy = format_perl << 1, // don't copy non-matching segments.
36 format_is_if = format_no_copy << 1 // internal use only.
42 #if __BORLANDC__ == 0x530
43 #pragma option push -a4 -b -Ve
44 #elif __BORLANDC__ > 0x530
45 #pragma option push -a8 -b -Ve -w-8037
49 template <class O, class I>
50 O BOOST_RE_CALL re_copy_out(O out, I first, I last)
61 template <class charT, class traits_type>
62 void BOOST_RE_CALL re_skip_format(const charT*& fmt, const traits_type& traits_inst)
64 // dwa 9/13/00 - suppress incorrect unused parameter warning for MSVC
67 typedef typename traits_type::size_type traits_size_type;
68 typedef typename traits_type::uchar_type traits_uchar_type;
69 typedef typename traits_type::string_type traits_string_type;
71 unsigned int parens = 0;
75 c = traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt));
76 if((c == traits_type::syntax_colon) && (parens == 0))
81 else if(c == traits_type::syntax_close_bracket)
90 else if(c == traits_type::syntax_open_bracket)
92 else if(c == traits_type::syntax_slash)
102 #ifdef BOOST_RE_NO_OI_ASSIGN
105 // ugly hack for buggy output iterators
108 inline void oi_assign(T* p, T v)
117 inline void oi_assign(T* p, T v)
120 // if you get a compile time error in here then you either
121 // need to rewrite your output iterator to make it assignable
122 // (as is required by the standard), or define BOOST_RE_NO_OI_ASSIGN
123 // to use the ugly hack above
130 #if defined(BOOST_RE_NO_TEMPLATE_SWITCH_MERGE) && !defined(BOOST_RE_NO_NAMESPACES)
133 // template don't merge if they contain switch statements so declare these
134 // templates in unnamed namespace (ie with internal linkage), each translation
135 // unit then gets its own local copy, it works seemlessly but bloats the app.
140 // algorithm reg_format:
141 // takes the result of a match and a format string
142 // and merges them to produce a new string which
143 // is sent to an OutputIterator,
144 // _reg_format_aux does the actual work:
146 template <class OutputIterator, class iterator, class Allocator, class charT, class traits_type>
147 OutputIterator BOOST_RE_CALL _reg_format_aux(OutputIterator out,
148 const match_results<iterator, Allocator>& m,
150 unsigned flags, const traits_type& traits_inst)
152 const charT* fmt_end = fmt;
153 while(*fmt_end) ++ fmt_end;
155 typedef typename traits_type::size_type traits_size_type;
156 typedef typename traits_type::uchar_type traits_uchar_type;
157 typedef typename traits_type::string_type traits_string_type;
161 switch(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)))
163 case traits_type::syntax_dollar:
164 if(flags & format_sed)
166 // no perl style replacement,
167 // $ is an ordinary character:
171 if(*fmt == 0) // oops trailing $
178 switch(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)))
180 case traits_type::syntax_start_buffer:
181 oi_assign(&out, re_copy_out(out, iterator(m[-1].first), iterator(m[-1].second)));
184 case traits_type::syntax_end_buffer:
185 oi_assign(&out, re_copy_out(out, iterator(m[-2].first), iterator(m[-2].second)));
188 case traits_type::syntax_digit:
191 unsigned int index = traits_inst.toi(fmt, fmt_end, 10);
192 oi_assign(&out, re_copy_out(out, iterator(m[index].first), iterator(m[index].second)));
199 oi_assign(&out, re_copy_out(out, iterator(m[0].first), iterator(m[0].second)));
204 // probably an error, treat as a literal '$'
211 case traits_type::syntax_slash:
224 switch(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)))
226 case traits_type::syntax_a:
230 case traits_type::syntax_f:
234 case traits_type::syntax_n:
238 case traits_type::syntax_r:
242 case traits_type::syntax_t:
246 case traits_type::syntax_v:
250 case traits_type::syntax_x:
258 // maybe have \x{ddd}
259 if(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)) == traits_type::syntax_open_brace)
270 if(traits_inst.is_class(*fmt, traits_type::char_class_xdigit) == false)
278 c = (charT)traits_inst.toi(fmt, fmt_end, -16);
279 if(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)) != traits_type::syntax_close_brace)
281 while(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)) != traits_type::syntax_slash)
294 if(traits_inst.is_class(*fmt, traits_type::char_class_xdigit) == false)
302 c = (charT)traits_inst.toi(fmt, fmt_end, -16);
305 case traits_type::syntax_c:
314 if(((typename traits_type::uchar_type)(*fmt) < (typename traits_type::uchar_type)'@')
315 || ((typename traits_type::uchar_type)(*fmt) > (typename traits_type::uchar_type)127) )
323 c = (charT)((typename traits_type::uchar_type)(*fmt) - (typename traits_type::uchar_type)'@');
326 case traits_type::syntax_e:
330 case traits_type::syntax_digit:
331 if(flags & format_sed)
334 c = (charT)traits_inst.toi(fmt, fmt_end, -8);
344 case traits_type::syntax_open_bracket:
345 if(flags & (format_sed|format_perl))
355 oi_assign(&out, _reg_format_aux(out, m, fmt, flags, traits_inst));
358 case traits_type::syntax_close_bracket:
359 if(flags & (format_sed|format_perl))
368 ++fmt; // return from recursion
371 case traits_type::syntax_colon:
372 if(flags & format_is_if)
381 case traits_type::syntax_question:
383 if(flags & (format_sed|format_perl))
401 unsigned int id = traits_inst.toi(fmt, fmt_end, 10);
404 oi_assign(&out, _reg_format_aux(out, m, fmt, flags | format_is_if, traits_inst));
405 if(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*(fmt-1))) == traits_type::syntax_colon)
406 re_skip_format(fmt, traits_inst);
410 re_skip_format(fmt, traits_inst);
411 if(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*(fmt-1))) == traits_type::syntax_colon)
412 oi_assign(&out, _reg_format_aux(out, m, fmt, flags | format_is_if, traits_inst));
419 if((flags & format_sed) && (*fmt == '&'))
421 oi_assign(&out, re_copy_out(out, iterator(m[0].first), iterator(m[0].second)));
434 #if defined(BOOST_RE_NO_TEMPLATE_SWITCH_MERGE) && !defined(BOOST_RE_NO_NAMESPACES)
439 class string_out_iterator
443 string_out_iterator(S& s) : out(&s) {}
444 string_out_iterator& operator++() { return *this; }
445 string_out_iterator& operator++(int) { return *this; }
446 string_out_iterator& operator*() { return *this; }
447 string_out_iterator& operator=(typename S::value_type v)
454 template <class OutputIterator, class iterator, class charT, class Allocator, class traits_type>
455 class merge_out_predicate
461 const traits_type* pt;
464 merge_out_predicate(OutputIterator& o, iterator& pi, const charT* f, unsigned format_flags, const traits_type& p)
465 : out(&o), last(&pi), fmt(f), flags(format_flags), pt(&p){}
467 ~merge_out_predicate() {}
468 bool BOOST_RE_CALL operator()(const boost::match_results<iterator, Allocator>& m)
470 const charT* f = fmt;
471 if(0 == (flags & format_no_copy))
472 oi_assign(out, re_copy_out(*out, iterator(m[-1].first), iterator(m[-1].second)));
473 oi_assign(out, _reg_format_aux(*out, m, f, flags, *pt));
479 } // namespace re_detail
481 template <class OutputIterator, class iterator, class Allocator, class charT>
482 OutputIterator regex_format(OutputIterator out,
483 const match_results<iterator, Allocator>& m,
488 regex_traits<charT> t;
489 return re_detail::_reg_format_aux(out, m, fmt, flags, t);
492 template <class OutputIterator, class iterator, class Allocator, class charT>
493 OutputIterator regex_format(OutputIterator out,
494 const match_results<iterator, Allocator>& m,
495 const std::basic_string<charT>& fmt,
499 regex_traits<charT> t;
500 const charT* start = fmt.c_str();
501 return re_detail::_reg_format_aux(out, m, start, flags, t);
504 template <class iterator, class Allocator, class charT>
505 std::basic_string<charT> regex_format(const match_results<iterator, Allocator>& m, const charT* fmt, unsigned flags = 0)
507 std::basic_string<charT> result;
508 re_detail::string_out_iterator<std::basic_string<charT> > i(result);
509 regex_format(i, m, fmt, flags);
513 template <class iterator, class Allocator, class charT>
514 std::basic_string<charT> regex_format(const match_results<iterator, Allocator>& m, const std::basic_string<charT>& fmt, unsigned flags = 0)
516 std::basic_string<charT> result;
517 re_detail::string_out_iterator<std::basic_string<charT> > i(result);
518 regex_format(i, m, fmt.c_str(), flags);
522 template <class OutputIterator, class iterator, class traits, class Allocator, class charT>
523 OutputIterator regex_merge(OutputIterator out,
526 const reg_expression<charT, traits, Allocator>& e,
528 unsigned int flags = match_default)
531 re_detail::merge_out_predicate<OutputIterator, iterator, charT, Allocator, traits> oi(out, l, fmt, flags, e.get_traits());
532 regex_grep(oi, first, last, e, flags);
533 return (flags & format_no_copy) ? out : re_detail::re_copy_out(out, l, last);
536 template <class OutputIterator, class iterator, class traits, class Allocator, class charT>
537 inline OutputIterator regex_merge(OutputIterator out,
540 const reg_expression<charT, traits, Allocator>& e,
541 const std::basic_string<charT>& fmt,
542 unsigned int flags = match_default)
544 return regex_merge(out, first, last, e, fmt.c_str(), flags);
547 template <class traits, class Allocator, class charT>
548 std::basic_string<charT> regex_merge(const std::basic_string<charT>& s,
549 const reg_expression<charT, traits, Allocator>& e,
551 unsigned int flags = match_default)
553 std::basic_string<charT> result;
554 re_detail::string_out_iterator<std::basic_string<charT> > i(result);
555 regex_merge(i, s.begin(), s.end(), e, fmt, flags);
559 template <class traits, class Allocator, class charT>
560 std::basic_string<charT> regex_merge(const std::basic_string<charT>& s,
561 const reg_expression<charT, traits, Allocator>& e,
562 const std::basic_string<charT>& fmt,
563 unsigned int flags = match_default)
565 std::basic_string<charT> result;
566 re_detail::string_out_iterator<std::basic_string<charT> > i(result);
567 regex_merge(i, s.begin(), s.end(), e, fmt.c_str(), flags);
572 #if __BORLANDC__ > 0x520
579 #endif // BOOST_REGEX_FORMAT_HPP