]> git.lyx.org Git - lyx.git/blob - boost/boost/re_detail/regex_format.hpp
cvsignore ++
[lyx.git] / boost / boost / re_detail / regex_format.hpp
1 /*
2  *
3  * Copyright (c) 1998-2000
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      3.03
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_is_if = format_no_copy << 1   // internal use only.
37 };
38
39 namespace re_detail{
40
41 #ifdef __BORLANDC__
42    #if __BORLANDC__ == 0x530
43     #pragma option push -a4 -b -Ve
44    #elif __BORLANDC__ > 0x530
45     #pragma option push -a8 -b -Ve -w-8037
46    #endif
47 #endif
48
49 template <class O, class I>
50 O BOOST_RE_CALL re_copy_out(O out, I first, I last)
51 {
52    while(first != last)
53    {
54       *out = *first;
55       ++out;
56       ++first;
57    }
58    return out;
59 }
60
61 template <class charT, class traits_type>
62 void BOOST_RE_CALL re_skip_format(const charT*& fmt, const traits_type& traits_inst)
63 {
64    // dwa 9/13/00 - suppress incorrect unused parameter warning for MSVC
65    (void)traits_inst;
66
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;
70
71    unsigned int parens = 0;
72    unsigned int c;
73    while(*fmt)
74    {
75       c = traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt));
76       if((c == traits_type::syntax_colon) && (parens == 0))
77       {
78          ++fmt;
79          return;
80       }
81       else if(c == traits_type::syntax_close_bracket)
82       {
83          if(parens == 0)
84          {
85             ++fmt;
86             return;
87          }
88          --parens;
89       }
90       else if(c == traits_type::syntax_open_bracket)
91          ++parens;
92       else if(c == traits_type::syntax_slash)
93       {
94          ++fmt;
95          if(*fmt == 0)
96             return;
97       }
98       ++fmt;
99    }
100 }
101
102 #ifdef BOOST_RE_NO_OI_ASSIGN
103
104 //
105 // ugly hack for buggy output iterators
106
107 template <class T>
108 inline void oi_assign(T* p, T v)
109 {
110    jm_destroy(p);
111    jm_construct(p, v);
112 }
113
114 #else
115
116 template <class T>
117 inline void oi_assign(T* p, T v)
118 {
119    //
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
124    *p = v;
125 }
126
127 #endif
128
129
130 #if defined(BOOST_RE_NO_TEMPLATE_SWITCH_MERGE) && !defined(BOOST_RE_NO_NAMESPACES)
131 //
132 // Ugly ugly hack,
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.
136 namespace{
137 #endif
138
139 //
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:
145 //
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, 
149                           const charT*& fmt,
150                           unsigned flags, const traits_type& traits_inst)
151 {
152    const charT* fmt_end = fmt;
153    while(*fmt_end) ++ fmt_end;
154
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;
158
159    while(*fmt)
160    {
161       switch(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)))
162       {
163       case traits_type::syntax_dollar:
164          if(flags & format_sed)
165          {
166             // no perl style replacement,
167             // $ is an ordinary character:
168             goto default_opt;
169          }
170          ++fmt;
171          if(*fmt == 0) // oops trailing $
172          {
173             --fmt;
174             *out = *fmt;
175             ++out;
176             return out;
177          }
178          switch(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)))
179          {
180          case traits_type::syntax_start_buffer:
181             oi_assign(&out, re_copy_out(out, iterator(m[-1].first), iterator(m[-1].second)));
182             ++fmt;
183             continue;
184          case traits_type::syntax_end_buffer:
185             oi_assign(&out, re_copy_out(out, iterator(m[-2].first), iterator(m[-2].second)));
186             ++fmt;
187             continue;
188          case traits_type::syntax_digit:
189          {
190 expand_sub:
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)));
193             continue;
194          }
195          }
196          // anything else:
197          if(*fmt == '&')
198          {
199             oi_assign(&out, re_copy_out(out, iterator(m[0].first), iterator(m[0].second)));
200             ++fmt;
201          }
202          else
203          {
204             // probably an error, treat as a literal '$'
205             --fmt;
206             *out = *fmt;
207             ++out;
208             ++fmt;
209          }
210          continue;
211       case traits_type::syntax_slash:
212       {
213          // escape sequence:
214          ++fmt;
215          charT c(*fmt);
216          if(*fmt == 0)
217          {
218             --fmt;
219             *out = *fmt;
220             ++out;
221             ++fmt;
222             return out;
223          }
224          switch(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)))
225          {
226          case traits_type::syntax_a:
227             c = '\a';
228             ++fmt;
229             break;
230          case traits_type::syntax_f:
231             c = '\f';
232             ++fmt;
233             break;
234          case traits_type::syntax_n:
235             c = '\n';
236             ++fmt;
237             break;
238          case traits_type::syntax_r:
239             c = '\r';
240             ++fmt;
241             break;
242          case traits_type::syntax_t:
243             c = '\t';
244             ++fmt;
245             break;
246          case traits_type::syntax_v:
247             c = '\v';
248             ++fmt;
249             break;
250          case traits_type::syntax_x:
251             ++fmt;
252             if(fmt == fmt_end)
253             {
254                *out = *--fmt;
255                ++out;
256                return out;
257             }
258             // maybe have \x{ddd}
259             if(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)) == traits_type::syntax_open_brace)
260             {
261                ++fmt;
262                if(fmt == fmt_end)
263                {
264                   fmt -= 2;
265                   *out = *fmt;
266                   ++out;
267                   ++fmt;
268                   continue;
269                }
270                if(traits_inst.is_class(*fmt, traits_type::char_class_xdigit) == false)
271                {
272                   fmt -= 2;
273                   *out = *fmt;
274                   ++out;
275                   ++fmt;
276                   continue;
277                }
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)
280                {
281                   while(traits_inst.syntax_type((traits_size_type)(traits_uchar_type)(*fmt)) != traits_type::syntax_slash)
282                      --fmt;
283                   ++fmt;
284                   *out = *fmt;
285                   ++out;
286                   ++fmt;
287                   continue;
288                }
289                ++fmt;
290                break;
291             }
292             else
293             {
294                if(traits_inst.is_class(*fmt, traits_type::char_class_xdigit) == false)
295                {
296                   --fmt;
297                   *out = *fmt;
298                   ++out;
299                   ++fmt;
300                   continue;
301                }
302                c = (charT)traits_inst.toi(fmt, fmt_end, -16);
303             }
304             break;
305          case traits_type::syntax_c:
306             ++fmt;
307             if(fmt == fmt_end)
308             {
309                --fmt;
310                *out = *fmt;
311                ++out;
312                return out;
313             }
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) )
316             {
317                --fmt;
318                *out = *fmt;
319                ++out;
320                ++fmt;
321                break;
322             }
323             c = (charT)((typename traits_type::uchar_type)(*fmt) - (typename traits_type::uchar_type)'@');
324             ++fmt;
325             break;
326          case traits_type::syntax_e:
327             c = (charT)27;
328             ++fmt;
329             break;
330          case traits_type::syntax_digit:
331             if(flags & format_sed)
332                goto expand_sub;
333             else
334                c = (charT)traits_inst.toi(fmt, fmt_end, -8);
335             break;
336          default:
337             //c = *fmt;
338             ++fmt;
339          }
340          *out = c;
341          ++out;
342          continue;
343       }
344       case traits_type::syntax_open_bracket:
345          if(flags & (format_sed|format_perl))
346          {
347             *out = *fmt;
348             ++out;
349             ++fmt;
350             continue;
351          }
352          else
353          {
354             ++fmt;  // recurse
355             oi_assign(&out, _reg_format_aux(out, m, fmt, flags, traits_inst));
356             continue;
357          }
358       case traits_type::syntax_close_bracket:
359          if(flags & (format_sed|format_perl))
360          {
361             *out = *fmt;
362             ++out;
363             ++fmt;
364             continue;
365          }
366          else
367          {
368             ++fmt;  // return from recursion
369             return out;
370          }
371       case traits_type::syntax_colon:
372          if(flags & format_is_if)
373          {
374             ++fmt;
375             return out;
376          }
377          *out = *fmt;
378          ++out;
379          ++fmt;
380          continue;
381       case traits_type::syntax_question:
382       {
383          if(flags & (format_sed|format_perl))
384          {
385             *out = *fmt;
386             ++out;
387             ++fmt;
388             continue;
389          }
390          else
391          {
392             ++fmt;
393             if(*fmt == 0)
394             {
395                --fmt;
396                *out = *fmt;
397                ++out;
398                ++fmt;
399                return out;
400             }
401             unsigned int id = traits_inst.toi(fmt, fmt_end, 10);
402             if(m[id].matched)
403             {
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);
407             }
408             else
409             {
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));
413             }
414             return out;
415          }
416       }
417       default:
418 default_opt:
419          if((flags & format_sed) && (*fmt == '&'))
420          {
421             oi_assign(&out, re_copy_out(out, iterator(m[0].first), iterator(m[0].second)));
422             ++fmt;
423             continue;
424          }
425          *out = *fmt;
426          ++out;
427          ++fmt;
428       }
429    }
430
431    return out;
432 }
433
434 #if defined(BOOST_RE_NO_TEMPLATE_SWITCH_MERGE) && !defined(BOOST_RE_NO_NAMESPACES)
435 } // namespace
436 #endif
437
438 template <class S>
439 class string_out_iterator
440 {
441    S* out;
442 public:
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) 
448    { 
449       out->append(1, v); 
450       return *this; 
451    }
452 };
453
454 template <class OutputIterator, class iterator, class charT, class Allocator, class traits_type>
455 class merge_out_predicate
456 {
457    OutputIterator* out;
458    iterator* last;
459    const charT* fmt;
460    unsigned flags;
461    const traits_type* pt;
462
463 public:
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){}
466
467    ~merge_out_predicate() {}
468    bool BOOST_RE_CALL operator()(const boost::match_results<iterator, Allocator>& m)
469    {
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));
474       *last = m[-2].first;
475       return true;
476    }
477 };
478
479 } // namespace re_detail
480
481 template <class OutputIterator, class iterator, class Allocator, class charT>
482 OutputIterator regex_format(OutputIterator out,
483                           const match_results<iterator, Allocator>& m,
484                           const charT* fmt,
485                           unsigned flags = 0
486                          )
487 {
488    regex_traits<charT> t;
489    return re_detail::_reg_format_aux(out, m, fmt, flags, t);
490 }
491
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,
496                           unsigned flags = 0
497                          )
498 {
499    regex_traits<charT> t;
500    const charT* start = fmt.c_str();
501    return re_detail::_reg_format_aux(out, m, start, flags, t);
502 }  
503
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)
506 {
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);
510    return result;
511 }
512
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)
515 {
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);
519    return result;
520 }
521
522 template <class OutputIterator, class iterator, class traits, class Allocator, class charT>
523 OutputIterator regex_merge(OutputIterator out,
524                          iterator first,
525                          iterator last,
526                          const reg_expression<charT, traits, Allocator>& e, 
527                          const charT* fmt, 
528                          unsigned int flags = match_default)
529 {
530    iterator l = first;
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);
534 }
535
536 template <class OutputIterator, class iterator, class traits, class Allocator, class charT>
537 inline OutputIterator regex_merge(OutputIterator out,
538                          iterator first,
539                          iterator last,
540                          const reg_expression<charT, traits, Allocator>& e, 
541                          const std::basic_string<charT>& fmt,
542                          unsigned int flags = match_default)
543 {
544    return regex_merge(out, first, last, e, fmt.c_str(), flags);
545 }
546
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, 
550                          const charT* fmt,
551                          unsigned int flags = match_default)
552 {
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);
556    return result;
557 }
558
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)
564 {
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);
568    return result;
569 }
570
571 #ifdef __BORLANDC__
572  #if __BORLANDC__ > 0x520
573   #pragma option pop
574  #endif
575 #endif
576
577 } // namespace boost
578
579 #endif  // BOOST_REGEX_FORMAT_HPP
580
581
582
583