]> git.lyx.org Git - lyx.git/blob - boost/boost/regex/detail/regex_format.hpp
major boost update
[lyx.git] / boost / boost / regex / detail / regex_format.hpp
1 /*
2  *
3  * Copyright (c) 1998-2002
4  * Dr John Maddock
5  *
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.
13  *
14  */
15
16  /*
17   *   LOCATION:    see http://www.boost.org for most recent version.
18   *   FILE         regex_format.hpp
19   *   VERSION      see <boost/version.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.
23   */
24
25 #ifndef BOOST_REGEX_FORMAT_HPP
26 #define BOOST_REGEX_FORMAT_HPP
27
28
29 namespace boost{
30
31 enum format_flags_t{
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_first_only = format_no_copy << 1,   // Only replace first occurance.
37    format_is_if = format_first_only << 1   // internal use only.
38 };
39
40 namespace re_detail{
41
42 #ifdef __BORLANDC__
43    #pragma option push -a4 -b -Ve -pc -w-8037
44 #endif
45
46 template <class O, class I>
47 O BOOST_REGEX_CALL re_copy_out(O out, I first, I last)
48 {
49    while(first != last)
50    {
51       *out = *first;
52       ++out;
53       ++first;
54    }
55    return out;
56 }
57
58 template <class charT, class traits_type>
59 void BOOST_REGEX_CALL re_skip_format(const charT*& fmt, const traits_type& traits_inst)
60 {
61    // dwa 9/13/00 - suppress incorrect unused parameter warning for MSVC
62    (void)traits_inst;
63
64    typedef typename traits_type::size_type traits_size_type;
65    typedef typename traits_type::uchar_type traits_uchar_type;
66    typedef typename traits_type::string_type traits_string_type;
67
68    unsigned int parens = 0;
69    unsigned int c;
70    while(*fmt)
71    {
72       c = traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt));
73       if((c == traits_type::syntax_colon) && (parens == 0))
74       {
75          ++fmt;
76          return;
77       }
78       else if(c == traits_type::syntax_close_bracket)
79       {
80          if(parens == 0)
81          {
82             ++fmt;
83             return;
84          }
85          --parens;
86       }
87       else if(c == traits_type::syntax_open_bracket)
88          ++parens;
89       else if(c == traits_type::syntax_slash)
90       {
91          ++fmt;
92          if(*fmt == 0)
93             return;
94       }
95       ++fmt;
96    }
97 }
98
99 #ifdef BOOST_NO_STD_OUTPUT_ITERATOR_ASSIGN
100
101 //
102 // ugly hack for buggy output iterators
103
104 template <class T>
105 inline void oi_assign(T* p, T v)
106 {
107    ::boost::re_detail::pointer_destroy(p);
108    pointer_construct(p, v);
109 }
110
111 #else
112
113 template <class T>
114 inline void oi_assign(T* p, T v)
115 {
116    //
117    // if you get a compile time error in here then you either
118    // need to rewrite your output iterator to make it assignable
119    // (as is required by the standard), or define
120    // BOOST_NO_STD_OUTPUT_ITERATOR_ASSIGN to use the ugly hack above
121    *p = v;
122 }
123
124 #endif
125
126
127 #if defined(BOOST_REGEX_NO_TEMPLATE_SWITCH_MERGE)
128 //
129 // Ugly ugly hack,
130 // template don't merge if they contain switch statements so declare these
131 // templates in unnamed namespace (ie with internal linkage), each translation
132 // unit then gets its own local copy, it works seemlessly but bloats the app.
133 namespace{
134 #endif
135
136 //
137 // algorithm reg_format:
138 // takes the result of a match and a format string
139 // and merges them to produce a new string which
140 // is sent to an OutputIterator,
141 // _reg_format_aux does the actual work:
142 //
143 template <class OutputIterator, class iterator, class Allocator, class charT, class traits_type>
144 OutputIterator BOOST_REGEX_CALL _reg_format_aux(OutputIterator out, 
145                           const match_results<iterator, Allocator>& m, 
146                           const charT*& fmt,
147                           unsigned flags, const traits_type& traits_inst)
148 {
149    const charT* fmt_end = fmt;
150    while(*fmt_end) ++ fmt_end;
151
152    typedef typename traits_type::size_type traits_size_type;
153    typedef typename traits_type::uchar_type traits_uchar_type;
154    typedef typename traits_type::string_type traits_string_type;
155
156    while(*fmt)
157    {
158       switch(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)))
159       {
160       case traits_type::syntax_dollar:
161          if(flags & format_sed)
162          {
163             // no perl style replacement,
164             // $ is an ordinary character:
165             goto default_opt;
166          }
167          ++fmt;
168          if(*fmt == 0) // oops trailing $
169          {
170             --fmt;
171             *out = *fmt;
172             ++out;
173             return out;
174          }
175          switch(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)))
176          {
177          case traits_type::syntax_start_buffer:
178             oi_assign(&out, re_copy_out(out, iterator(m[-1].first), iterator(m[-1].second)));
179             ++fmt;
180             continue;
181          case traits_type::syntax_end_buffer:
182             oi_assign(&out, re_copy_out(out, iterator(m[-2].first), iterator(m[-2].second)));
183             ++fmt;
184             continue;
185          case traits_type::syntax_digit:
186          {
187 expand_sub:
188             unsigned int index = traits_inst.toi(fmt, fmt_end, 10);
189             oi_assign(&out, re_copy_out(out, iterator(m[index].first), iterator(m[index].second)));
190             continue;
191          }
192          }
193          // anything else:
194          if(*fmt == '&')
195          {
196             oi_assign(&out, re_copy_out(out, iterator(m[0].first), iterator(m[0].second)));
197             ++fmt;
198          }
199          else
200          {
201             // probably an error, treat as a literal '$'
202             --fmt;
203             *out = *fmt;
204             ++out;
205             ++fmt;
206          }
207          continue;
208       case traits_type::syntax_slash:
209       {
210          // escape sequence:
211          ++fmt;
212          charT c(*fmt);
213          if(*fmt == 0)
214          {
215             --fmt;
216             *out = *fmt;
217             ++out;
218             ++fmt;
219             return out;
220          }
221          switch(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)))
222          {
223          case traits_type::syntax_a:
224             c = '\a';
225             ++fmt;
226             break;
227          case traits_type::syntax_f:
228             c = '\f';
229             ++fmt;
230             break;
231          case traits_type::syntax_n:
232             c = '\n';
233             ++fmt;
234             break;
235          case traits_type::syntax_r:
236             c = '\r';
237             ++fmt;
238             break;
239          case traits_type::syntax_t:
240             c = '\t';
241             ++fmt;
242             break;
243          case traits_type::syntax_v:
244             c = '\v';
245             ++fmt;
246             break;
247          case traits_type::syntax_x:
248             ++fmt;
249             if(fmt == fmt_end)
250             {
251                *out = *--fmt;
252                ++out;
253                return out;
254             }
255             // maybe have \x{ddd}
256             if(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)) == traits_type::syntax_open_brace)
257             {
258                ++fmt;
259                if(fmt == fmt_end)
260                {
261                   fmt -= 2;
262                   *out = *fmt;
263                   ++out;
264                   ++fmt;
265                   continue;
266                }
267                if(traits_inst.is_class(*fmt, traits_type::char_class_xdigit) == false)
268                {
269                   fmt -= 2;
270                   *out = *fmt;
271                   ++out;
272                   ++fmt;
273                   continue;
274                }
275                c = (charT)traits_inst.toi(fmt, fmt_end, -16);
276                if(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)) != traits_type::syntax_close_brace)
277                {
278                   while(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)) != traits_type::syntax_slash)
279                      --fmt;
280                   ++fmt;
281                   *out = *fmt;
282                   ++out;
283                   ++fmt;
284                   continue;
285                }
286                ++fmt;
287                break;
288             }
289             else
290             {
291                if(traits_inst.is_class(*fmt, traits_type::char_class_xdigit) == false)
292                {
293                   --fmt;
294                   *out = *fmt;
295                   ++out;
296                   ++fmt;
297                   continue;
298                }
299                c = (charT)traits_inst.toi(fmt, fmt_end, -16);
300             }
301             break;
302          case traits_type::syntax_c:
303             ++fmt;
304             if(fmt == fmt_end)
305             {
306                --fmt;
307                *out = *fmt;
308                ++out;
309                return out;
310             }
311             if(((typename traits_type::uchar_type)(*fmt) < (typename traits_type::uchar_type)'@')
312                   || ((typename traits_type::uchar_type)(*fmt) > (typename traits_type::uchar_type)127) )
313             {
314                --fmt;
315                *out = *fmt;
316                ++out;
317                ++fmt;
318                break;
319             }
320             c = (charT)((typename traits_type::uchar_type)(*fmt) - (typename traits_type::uchar_type)'@');
321             ++fmt;
322             break;
323          case traits_type::syntax_e:
324             c = (charT)27;
325             ++fmt;
326             break;
327          case traits_type::syntax_digit:
328             if(flags & format_sed)
329                goto expand_sub;
330             else
331                c = (charT)traits_inst.toi(fmt, fmt_end, -8);
332             break;
333          default:
334             //c = *fmt;
335             ++fmt;
336          }
337          *out = c;
338          ++out;
339          continue;
340       }
341       case traits_type::syntax_open_bracket:
342          if(flags & (format_sed|format_perl))
343          {
344             *out = *fmt;
345             ++out;
346             ++fmt;
347             continue;
348          }
349          else
350          {
351             ++fmt;  // recurse
352             oi_assign(&out, _reg_format_aux(out, m, fmt, flags, traits_inst));
353             continue;
354          }
355       case traits_type::syntax_close_bracket:
356          if(flags & (format_sed|format_perl))
357          {
358             *out = *fmt;
359             ++out;
360             ++fmt;
361             continue;
362          }
363          else
364          {
365             ++fmt;  // return from recursion
366             return out;
367          }
368       case traits_type::syntax_colon:
369          if(flags & format_is_if)
370          {
371             ++fmt;
372             return out;
373          }
374          *out = *fmt;
375          ++out;
376          ++fmt;
377          continue;
378       case traits_type::syntax_question:
379       {
380          if(flags & (format_sed|format_perl))
381          {
382             *out = *fmt;
383             ++out;
384             ++fmt;
385             continue;
386          }
387          else
388          {
389             ++fmt;
390             if(*fmt == 0)
391             {
392                --fmt;
393                *out = *fmt;
394                ++out;
395                ++fmt;
396                return out;
397             }
398             unsigned int id = traits_inst.toi(fmt, fmt_end, 10);
399             if(m[id].matched)
400             {
401                oi_assign(&out, _reg_format_aux(out, m, fmt, flags | format_is_if, traits_inst));
402                if(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*(fmt-1))) == traits_type::syntax_colon)
403                   re_skip_format(fmt, traits_inst);
404             }
405             else
406             {
407                re_skip_format(fmt, traits_inst);
408                if(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*(fmt-1))) == traits_type::syntax_colon)
409                   oi_assign(&out, _reg_format_aux(out, m, fmt, flags | format_is_if, traits_inst));
410             }
411             return out;
412          }
413       }
414       default:
415 default_opt:
416          if((flags & format_sed) && (*fmt == '&'))
417          {
418             oi_assign(&out, re_copy_out(out, iterator(m[0].first), iterator(m[0].second)));
419             ++fmt;
420             continue;
421          }
422          *out = *fmt;
423          ++out;
424          ++fmt;
425       }
426    }
427
428    return out;
429 }
430
431 #if defined(BOOST_REGEX_NO_TEMPLATE_SWITCH_MERGE)
432 } // namespace
433 #endif
434
435 template <class S>
436 class string_out_iterator
437 {
438    S* out;
439 public:
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) 
445    { 
446       out->append(1, v); 
447       return *this; 
448    }
449 };
450
451 template <class OutputIterator, class iterator, class charT, class Allocator, class traits_type>
452 class merge_out_predicate
453 {
454    OutputIterator* out;
455    iterator* last;
456    const charT* fmt;
457    unsigned flags;
458    const traits_type* pt;
459
460 public:
461    merge_out_predicate(OutputIterator& o, iterator& pi, const charT* f, unsigned format_flags, const traits_type& p)
462       : out(&o), last(&pi), fmt(f), flags(format_flags), pt(&p){}
463
464    ~merge_out_predicate() {}
465    bool BOOST_REGEX_CALL operator()(const boost::match_results<iterator, Allocator>& m)
466    {
467       const charT* f = fmt;
468       if(0 == (flags & format_no_copy))
469          oi_assign(out, re_copy_out(*out, iterator(m[-1].first), iterator(m[-1].second)));
470       oi_assign(out, _reg_format_aux(*out, m, f, flags, *pt));
471       *last = m[-2].first;
472       return flags & format_first_only ? false : true;
473    }
474 };
475
476 } // namespace re_detail
477
478 template <class OutputIterator, class iterator, class Allocator, class charT>
479 OutputIterator regex_format(OutputIterator out,
480                           const match_results<iterator, Allocator>& m,
481                           const charT* fmt,
482                           unsigned flags = 0
483                          )
484 {
485    regex_traits<charT> t;
486    return re_detail::_reg_format_aux(out, m, fmt, flags, t);
487 }
488
489 template <class OutputIterator, class iterator, class Allocator, class charT>
490 OutputIterator regex_format(OutputIterator out,
491                           const match_results<iterator, Allocator>& m,
492                           const std::basic_string<charT>& fmt,
493                           unsigned flags = 0
494                          )
495 {
496    regex_traits<charT> t;
497    const charT* start = fmt.c_str();
498    return re_detail::_reg_format_aux(out, m, start, flags, t);
499 }  
500
501 template <class iterator, class Allocator, class charT>
502 std::basic_string<charT> regex_format(const match_results<iterator, Allocator>& m, const charT* fmt, unsigned flags = 0)
503 {
504    std::basic_string<charT> result;
505    re_detail::string_out_iterator<std::basic_string<charT> > i(result);
506    regex_format(i, m, fmt, flags);
507    return result;
508 }
509
510 template <class iterator, class Allocator, class charT>
511 std::basic_string<charT> regex_format(const match_results<iterator, Allocator>& m, const std::basic_string<charT>& fmt, unsigned flags = 0)
512 {
513    std::basic_string<charT> result;
514    re_detail::string_out_iterator<std::basic_string<charT> > i(result);
515    regex_format(i, m, fmt.c_str(), flags);
516    return result;
517 }
518
519 template <class OutputIterator, class iterator, class traits, class Allocator, class charT>
520 OutputIterator regex_merge(OutputIterator out,
521                          iterator first,
522                          iterator last,
523                          const reg_expression<charT, traits, Allocator>& e, 
524                          const charT* fmt, 
525                          unsigned int flags = match_default)
526 {
527    iterator l = first;
528    re_detail::merge_out_predicate<OutputIterator, iterator, charT, Allocator, traits> oi(out, l, fmt, flags, e.get_traits());
529    regex_grep(oi, first, last, e, flags);
530    return (flags & format_no_copy) ? out : re_detail::re_copy_out(out, l, last);
531 }
532
533 template <class OutputIterator, class iterator, class traits, class Allocator, class charT>
534 inline OutputIterator regex_merge(OutputIterator out,
535                          iterator first,
536                          iterator last,
537                          const reg_expression<charT, traits, Allocator>& e, 
538                          const std::basic_string<charT>& fmt,
539                          unsigned int flags = match_default)
540 {
541    return regex_merge(out, first, last, e, fmt.c_str(), flags);
542 }
543
544 template <class traits, class Allocator, class charT>
545 std::basic_string<charT> regex_merge(const std::basic_string<charT>& s,
546                          const reg_expression<charT, traits, Allocator>& e, 
547                          const charT* fmt,
548                          unsigned int flags = match_default)
549 {
550    std::basic_string<charT> result;
551    re_detail::string_out_iterator<std::basic_string<charT> > i(result);
552    regex_merge(i, s.begin(), s.end(), e, fmt, flags);
553    return result;
554 }
555
556 template <class traits, class Allocator, class charT>
557 std::basic_string<charT> regex_merge(const std::basic_string<charT>& s,
558                          const reg_expression<charT, traits, Allocator>& e, 
559                          const std::basic_string<charT>& fmt,
560                          unsigned int flags = match_default)
561 {
562    std::basic_string<charT> result;
563    re_detail::string_out_iterator<std::basic_string<charT> > i(result);
564    regex_merge(i, s.begin(), s.end(), e, fmt.c_str(), flags);
565    return result;
566 }
567
568 #ifdef __BORLANDC__
569   #pragma option pop
570 #endif
571
572 } // namespace boost
573
574 #endif  // BOOST_REGEX_FORMAT_HPP
575
576
577
578
579