]> git.lyx.org Git - lyx.git/blob - boost/boost/regex/v4/regex_format.hpp
Boost 1.31.0
[lyx.git] / boost / boost / regex / v4 / regex_format.hpp
1 /*
2  *
3  * Copyright (c) 1998-2002
4  * Dr John Maddock
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
25 namespace boost{
26
27 #ifdef BOOST_HAS_ABI_HEADERS
28 #  include BOOST_ABI_PREFIX
29 #endif
30
31 //
32 // Forward declaration:
33 //
34 template <class RandomAccessIterator, class Allocator>
35 class match_results;
36
37 namespace re_detail{
38
39 template <class O, class I>
40 O BOOST_REGEX_CALL re_copy_out(O out, I first, I last)
41 {
42    while(first != last)
43    {
44       *out = *first;
45       ++out;
46       ++first;
47    }
48    return out;
49 }
50
51 template <class charT, class traits_type>
52 void BOOST_REGEX_CALL re_skip_format(const charT*& fmt, const traits_type& traits_inst)
53 {
54    // dwa 9/13/00 - suppress incorrect unused parameter warning for MSVC
55    (void)traits_inst;
56
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;
60
61    unsigned int parens = 0;
62    unsigned int c;
63    while(*fmt)
64    {
65       c = traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt));
66       if((c == traits_type::syntax_colon) && (parens == 0))
67       {
68          ++fmt;
69          return;
70       }
71       else if(c == traits_type::syntax_close_bracket)
72       {
73          if(parens == 0)
74          {
75             ++fmt;
76             return;
77          }
78          --parens;
79       }
80       else if(c == traits_type::syntax_open_bracket)
81          ++parens;
82       else if(c == traits_type::syntax_slash)
83       {
84          ++fmt;
85          if(*fmt == 0)
86             return;
87       }
88       ++fmt;
89    }
90 }
91
92 #ifdef BOOST_NO_STD_OUTPUT_ITERATOR_ASSIGN
93
94 //
95 // ugly hack for buggy output iterators
96
97 template <class T>
98 inline void oi_assign(T* p, T v)
99 {
100    ::boost::re_detail::pointer_destroy(p);
101    pointer_construct(p, v);
102 }
103
104 #else
105
106 template <class T>
107 inline void oi_assign(T* p, T v)
108 {
109    //
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
114    *p = v;
115 }
116
117 #endif
118
119
120 #if defined(BOOST_REGEX_NO_TEMPLATE_SWITCH_MERGE)
121 //
122 // Ugly ugly hack,
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.
126 namespace{
127 #endif
128
129 //
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:
135 //
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, 
139                           const charT*& fmt,
140                           match_flag_type flags, const traits_type& traits_inst)
141 {
142 #ifdef __BORLANDC__
143 #pragma option push -w-8037
144 #endif
145    const charT* fmt_end = fmt;
146    while(*fmt_end) ++ fmt_end;
147
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;
151
152    while(*fmt)
153    {
154       switch(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)))
155       {
156       case traits_type::syntax_dollar:
157          if(flags & format_sed)
158          {
159             // no perl style replacement,
160             // $ is an ordinary character:
161             goto default_opt;
162          }
163          ++fmt;
164          if(*fmt == 0) // oops trailing $
165          {
166             --fmt;
167             *out = *fmt;
168             ++out;
169             return out;
170          }
171          switch(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)))
172          {
173          case traits_type::syntax_start_buffer:
174             oi_assign(&out, re_copy_out(out, Iterator(m[-1].first), Iterator(m[-1].second)));
175             ++fmt;
176             continue;
177          case traits_type::syntax_end_buffer:
178             oi_assign(&out, re_copy_out(out, Iterator(m[-2].first), Iterator(m[-2].second)));
179             ++fmt;
180             continue;
181          case traits_type::syntax_digit:
182          {
183 expand_sub:
184             unsigned int index = traits_inst.toi(fmt, fmt_end, 10);
185             if(index < m.size())
186                oi_assign(&out, re_copy_out(out, Iterator(m[index].first), Iterator(m[index].second)));
187             continue;
188          }
189          }
190          // anything else:
191          if(*fmt == '&')
192          {
193             oi_assign(&out, re_copy_out(out, Iterator(m[0].first), Iterator(m[0].second)));
194             ++fmt;
195          }
196          else
197          {
198             // probably an error, treat as a literal '$'
199             --fmt;
200             *out = *fmt;
201             ++out;
202             ++fmt;
203          }
204          continue;
205       case traits_type::syntax_slash:
206       {
207          // escape sequence:
208          ++fmt;
209          charT c(*fmt);
210          if(*fmt == 0)
211          {
212             --fmt;
213             *out = *fmt;
214             ++out;
215             ++fmt;
216             return out;
217          }
218          switch(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)))
219          {
220          case traits_type::syntax_a:
221             c = '\a';
222             ++fmt;
223             break;
224          case traits_type::syntax_f:
225             c = '\f';
226             ++fmt;
227             break;
228          case traits_type::syntax_n:
229             c = '\n';
230             ++fmt;
231             break;
232          case traits_type::syntax_r:
233             c = '\r';
234             ++fmt;
235             break;
236          case traits_type::syntax_t:
237             c = '\t';
238             ++fmt;
239             break;
240          case traits_type::syntax_v:
241             c = '\v';
242             ++fmt;
243             break;
244          case traits_type::syntax_x:
245             ++fmt;
246             if(fmt == fmt_end)
247             {
248                *out = *--fmt;
249                ++out;
250                return out;
251             }
252             // maybe have \x{ddd}
253             if(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)) == traits_type::syntax_open_brace)
254             {
255                ++fmt;
256                if(fmt == fmt_end)
257                {
258                   fmt -= 2;
259                   *out = *fmt;
260                   ++out;
261                   ++fmt;
262                   continue;
263                }
264                if(traits_inst.is_class(*fmt, traits_type::char_class_xdigit) == false)
265                {
266                   fmt -= 2;
267                   *out = *fmt;
268                   ++out;
269                   ++fmt;
270                   continue;
271                }
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)
274                {
275                   while(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)) != traits_type::syntax_slash)
276                      --fmt;
277                   ++fmt;
278                   *out = *fmt;
279                   ++out;
280                   ++fmt;
281                   continue;
282                }
283                ++fmt;
284                break;
285             }
286             else
287             {
288                if(traits_inst.is_class(*fmt, traits_type::char_class_xdigit) == false)
289                {
290                   --fmt;
291                   *out = *fmt;
292                   ++out;
293                   ++fmt;
294                   continue;
295                }
296                c = (charT)traits_inst.toi(fmt, fmt_end, -16);
297             }
298             break;
299          case traits_type::syntax_c:
300             ++fmt;
301             if(fmt == fmt_end)
302             {
303                --fmt;
304                *out = *fmt;
305                ++out;
306                return out;
307             }
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) )
310             {
311                --fmt;
312                *out = *fmt;
313                ++out;
314                ++fmt;
315                break;
316             }
317             c = (charT)((typename traits_type::uchar_type)(*fmt) - (typename traits_type::uchar_type)'@');
318             ++fmt;
319             break;
320          case traits_type::syntax_e:
321             c = (charT)27;
322             ++fmt;
323             break;
324          case traits_type::syntax_digit:
325             if(flags & format_sed)
326                goto expand_sub;
327             else
328                c = (charT)traits_inst.toi(fmt, fmt_end, -8);
329             break;
330          default:
331             //c = *fmt;
332             ++fmt;
333          }
334          *out = c;
335          ++out;
336          continue;
337       }
338       case traits_type::syntax_open_bracket:
339          if(0 == (flags & format_all))
340          {
341             *out = *fmt;
342             ++out;
343             ++fmt;
344             continue;
345          }
346          else
347          {
348             ++fmt;  // recurse
349             oi_assign(&out, _reg_format_aux(out, m, fmt, flags, traits_inst));
350             continue;
351          }
352       case traits_type::syntax_close_bracket:
353          if(0 == (flags & format_all))
354          {
355             *out = *fmt;
356             ++out;
357             ++fmt;
358             continue;
359          }
360          else
361          {
362             ++fmt;  // return from recursion
363             return out;
364          }
365       case traits_type::syntax_colon:
366          if(flags & regex_constants::format_is_if)
367          {
368             ++fmt;
369             return out;
370          }
371          *out = *fmt;
372          ++out;
373          ++fmt;
374          continue;
375       case traits_type::syntax_question:
376       {
377          if(0 == (flags & format_all))
378          {
379             *out = *fmt;
380             ++out;
381             ++fmt;
382             continue;
383          }
384          else
385          {
386             ++fmt;
387             if(*fmt == 0)
388             {
389                --fmt;
390                *out = *fmt;
391                ++out;
392                ++fmt;
393                return out;
394             }
395             unsigned int id = traits_inst.toi(fmt, fmt_end, 10);
396             if(m[id].matched)
397             {
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);
401             }
402             else
403             {
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));
407             }
408             return out;
409          }
410       }
411       default:
412 default_opt:
413          if((flags & format_sed) && (*fmt == '&'))
414          {
415             oi_assign(&out, re_copy_out(out, Iterator(m[0].first), Iterator(m[0].second)));
416             ++fmt;
417             continue;
418          }
419          *out = *fmt;
420          ++out;
421          ++fmt;
422       }
423    }
424
425    return out;
426 #ifdef __BORLANDC__
427 #pragma option pop
428 #endif
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    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;
461
462 public:
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){}
465
466    ~merge_out_predicate() {}
467    bool BOOST_REGEX_CALL operator()(const boost::match_results<Iterator, alloc_type>& m)
468    {
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));
473       *last = m[-2].first;
474       return flags & format_first_only ? false : true;
475    }
476 };
477
478 } // namespace re_detail
479
480 template <class OutputIterator, class Iterator, class Allocator, class charT>
481 OutputIterator regex_format(OutputIterator out,
482                           const match_results<Iterator, Allocator>& m,
483                           const charT* fmt,
484                           match_flag_type flags = format_all
485                          )
486 {
487    regex_traits<charT> t;
488    return re_detail::_reg_format_aux(out, m, fmt, flags, t);
489 }
490
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
496                          )
497 {
498    regex_traits<charT> t;
499    const charT* start = fmt.c_str();
500    return re_detail::_reg_format_aux(out, m, start, flags, t);
501 }  
502
503 template <class Iterator, class Allocator, class charT>
504 std::basic_string<charT> regex_format(const match_results<Iterator, Allocator>& m, 
505                                       const charT* fmt, 
506                                       match_flag_type flags = format_all)
507 {
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);
511    return result;
512 }
513
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)
518 {
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);
522    return result;
523 }
524
525 #ifdef BOOST_HAS_ABI_HEADERS
526 #  include BOOST_ABI_SUFFIX
527 #endif
528
529 } // namespace boost
530
531 #endif  // BOOST_REGEX_FORMAT_HPP
532
533
534
535
536
537