]> git.lyx.org Git - lyx.git/blob - boost/boost/regex/v4/regex_format.hpp
update to boost 1.34
[lyx.git] / boost / boost / regex / v4 / regex_format.hpp
1 /*
2  *
3  * Copyright (c) 1998-2002
4  * 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 BidiIterator, class Allocator = BOOST_DEDUCED_TYPENAME std::vector<sub_match<BidiIterator> >::allocator_type >
35 class match_results;
36
37 namespace re_detail{
38
39 //
40 // struct trivial_format_traits:
41 // defines minimum localisation support for formatting
42 // in the case that the actual regex traits is unavailable.
43 //
44 template <class charT>
45 struct trivial_format_traits
46 {
47    typedef charT char_type;
48
49    static std::ptrdiff_t length(const charT* p)
50    {
51       return global_length(p);
52    }
53    static charT tolower(charT c)
54    {
55       return ::boost::re_detail::global_lower(c);
56    }
57    static charT toupper(charT c)
58    {
59       return ::boost::re_detail::global_upper(c);
60    }
61    static int value(const charT c, int radix)
62    {
63       int result = global_value(c);
64       return result >= radix ? -1 : result;
65    }
66    int toi(const charT*& p1, const charT* p2, int radix)const
67    {
68       return global_toi(p1, p2, radix, *this);
69    }
70 };
71
72 template <class OutputIterator, class Results, class traits>
73 class basic_regex_formatter
74 {
75 public:
76    typedef typename traits::char_type char_type;
77    basic_regex_formatter(OutputIterator o, const Results& r, const traits& t)
78       : m_traits(t), m_results(r), m_out(o), m_state(output_copy), m_have_conditional(false) {}
79    OutputIterator format(const char_type* p1, const char_type* p2, match_flag_type f);
80    OutputIterator format(const char_type* p1, match_flag_type f)
81    {
82       return format(p1, p1 + m_traits.length(p1), f);
83    }
84 private:
85    typedef typename Results::value_type sub_match_type;
86    enum output_state
87    {
88       output_copy,
89       output_next_lower,
90       output_next_upper,
91       output_lower,
92       output_upper,
93       output_none
94    };
95
96    void put(char_type c);
97    void put(const sub_match_type& sub);
98    void format_all();
99    void format_perl();
100    void format_escape();
101    void format_conditional();
102    void format_until_scope_end();
103
104    const traits& m_traits;       // the traits class for localised formatting operations
105    const Results& m_results;     // the match_results being used.
106    OutputIterator m_out;         // where to send output.
107    const char_type* m_position;  // format string, current position
108    const char_type* m_end;       // format string end
109    match_flag_type m_flags;      // format flags to use
110    output_state    m_state;      // what to do with the next character
111    bool            m_have_conditional; // we are parsing a conditional
112 private:
113    basic_regex_formatter(const basic_regex_formatter&);
114    basic_regex_formatter& operator=(const basic_regex_formatter&);
115 };
116
117 template <class OutputIterator, class Results, class traits>
118 OutputIterator basic_regex_formatter<OutputIterator, Results, traits>::format(const char_type* p1, const char_type* p2, match_flag_type f)
119 {
120    m_position = p1;
121    m_end = p2;
122    m_flags = f;
123    format_all();
124    return m_out;
125 }
126
127 template <class OutputIterator, class Results, class traits>
128 void basic_regex_formatter<OutputIterator, Results, traits>::format_all()
129 {
130    // over and over:
131    while(m_position != m_end)
132    {
133       switch(*m_position)
134       {
135       case '&':
136          if(m_flags & ::boost::regex_constants::format_sed)
137          {
138             ++m_position;
139             put(m_results[0]);
140             break;
141          }
142          put(*m_position++);
143          break;
144       case '\\':
145          format_escape();
146          break;
147       case '(':
148          if(m_flags & boost::regex_constants::format_all)
149          {
150             ++m_position;
151             bool have_conditional = m_have_conditional;
152             m_have_conditional = false;
153             format_until_scope_end();
154             m_have_conditional = have_conditional;
155             if(m_position == m_end)
156                return;
157             BOOST_ASSERT(*m_position == static_cast<char_type>(')'));
158             ++m_position;  // skip the closing ')'
159             break;
160          }
161          put(*m_position);
162          ++m_position;
163          break;
164       case ')':
165          if(m_flags & boost::regex_constants::format_all)
166          {
167             return;
168          }
169          put(*m_position);
170          ++m_position;
171          break;
172       case ':':
173          if((m_flags & boost::regex_constants::format_all) && m_have_conditional)
174          {
175             return;
176          }
177          put(*m_position);
178          ++m_position;
179          break;
180       case '?':
181          if(m_flags & boost::regex_constants::format_all)
182          {
183             ++m_position;
184             format_conditional();
185             break;
186          }
187          put(*m_position);
188          ++m_position;
189          break;
190       case '$':
191          if((m_flags & format_sed) == 0)
192          {
193             format_perl();
194             break;
195          }
196          // fall through, not a special character:
197       default:
198          put(*m_position);
199          ++m_position;
200          break;
201       }
202    }
203 }
204
205 template <class OutputIterator, class Results, class traits>
206 void basic_regex_formatter<OutputIterator, Results, traits>::format_perl()
207 {
208    //
209    // On entry *m_position points to a '$' character
210    // output the information that goes with it:
211    //
212    BOOST_ASSERT(*m_position == '$');
213    //
214    // see if this is a trailing '$':
215    //
216    if(++m_position == m_end)
217    {
218       --m_position;
219       put(*m_position);
220       ++m_position;
221       return;
222    }
223    //
224    // OK find out what kind it is:
225    //
226    switch(*m_position)
227    {
228    case '&':
229       ++m_position;
230       put(this->m_results[0]);
231       break;
232    case '`':
233       ++m_position;
234       put(this->m_results.prefix());
235       break;
236    case '\'':
237       ++m_position;
238       put(this->m_results.suffix());
239       break;
240    case '$':
241       put(*m_position++);
242       break;
243    default:
244       // see if we have a number:
245       {
246          std::ptrdiff_t len = ::boost::re_detail::distance(m_position, m_end);
247          len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
248          int v = m_traits.toi(m_position, m_position + len, 10);
249          if(v < 0)
250          {
251             // leave the $ as is, and carry on:
252             --m_position;
253             put(*m_position);
254             ++m_position;
255             break;
256          }
257          // otherwise output sub v:
258          put(this->m_results[v]);
259       }
260    }
261 }
262
263 template <class OutputIterator, class Results, class traits>
264 void basic_regex_formatter<OutputIterator, Results, traits>::format_escape()
265 {
266    // skip the escape and check for trailing escape:
267    if(++m_position == m_end)
268    {
269       put(static_cast<char_type>('\\'));
270       return;
271    }
272    // now switch on the escape type:
273    switch(*m_position)
274    {
275    case 'a':
276       put(static_cast<char_type>('\a'));
277       ++m_position;
278       break;
279    case 'f':
280       put(static_cast<char_type>('\f'));
281       ++m_position;
282       break;
283    case 'n':
284       put(static_cast<char_type>('\n'));
285       ++m_position;
286       break;
287    case 'r':
288       put(static_cast<char_type>('\r'));
289       ++m_position;
290       break;
291    case 't':
292       put(static_cast<char_type>('\t'));
293       ++m_position;
294       break;
295    case 'v':
296       put(static_cast<char_type>('\v'));
297       ++m_position;
298       break;
299    case 'x':
300       if(++m_position == m_end)
301       {
302          put(static_cast<char_type>('x'));
303          return;
304       }
305       // maybe have \x{ddd}
306       if(*m_position == static_cast<char_type>('{'))
307       {
308          ++m_position;
309          int val = m_traits.toi(m_position, m_end, 16);
310          if(val < 0)
311          {
312             // invalid value treat everything as literals:
313             put(static_cast<char_type>('x'));
314             put(static_cast<char_type>('{'));
315             return;
316          }
317          if(*m_position != static_cast<char_type>('}'))
318          {
319             while(*m_position != static_cast<char_type>('\\'))
320                --m_position;
321             ++m_position;
322             put(*m_position++);
323             return;
324          }
325          ++m_position;
326          put(static_cast<char_type>(val));
327          return;
328       }
329       else
330       {
331          std::ptrdiff_t len = ::boost::re_detail::distance(m_position, m_end);
332          len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
333          int val = m_traits.toi(m_position, m_position + len, 16);
334          if(val < 0)
335          {
336             --m_position;
337             put(*m_position++);
338             return;
339          }
340          put(static_cast<char_type>(val));
341       }
342       break;
343    case 'c':
344       if(++m_position == m_end)
345       {
346          --m_position;
347          put(*m_position++);
348          return;
349       }
350       put(static_cast<char_type>(*m_position++ % 32));
351       break;
352    case 'e':
353       put(static_cast<char_type>(27));
354       ++m_position;
355       break;
356    default:
357       // see if we have a perl specific escape:
358       if((m_flags & boost::regex_constants::format_sed) == 0)
359       {
360          bool breakout = false;
361          switch(*m_position)
362          {
363          case 'l':
364             ++m_position;
365             m_state = output_next_lower;
366             breakout = true;
367             break;
368          case 'L':
369             ++m_position;
370             m_state = output_lower;
371             breakout = true;
372             break;
373          case 'u':
374             ++m_position;
375             m_state = output_next_upper;
376             breakout = true;
377             break;
378          case 'U':
379             ++m_position;
380             m_state = output_upper;
381             breakout = true;
382             break;
383          case 'E':
384             ++m_position;
385             m_state = output_copy;
386             breakout = true;
387             break;
388          }
389          if(breakout)
390             break;
391       }
392       // see if we have a \n sed style backreference:
393       int v = m_traits.toi(m_position, m_position+1, 10);
394       if((v > 0) || ((v == 0) && (m_flags & ::boost::regex_constants::format_sed)))
395       {
396          put(m_results[v]);
397          break;
398       }
399       else if(v == 0)
400       {
401          // octal ecape sequence:
402          --m_position;
403          std::ptrdiff_t len = ::boost::re_detail::distance(m_position, m_end);
404          len = (std::min)(static_cast<std::ptrdiff_t>(4), len);
405          v = m_traits.toi(m_position, m_position + len, 8);
406          BOOST_ASSERT(v >= 0);
407          put(static_cast<char_type>(v));
408          break;
409       }
410       // Otherwise output the character "as is":
411       put(*m_position++);
412       break;
413    }
414 }
415
416 template <class OutputIterator, class Results, class traits>
417 void basic_regex_formatter<OutputIterator, Results, traits>::format_conditional()
418 {
419    if(m_position == m_end)
420    {
421       // oops trailing '?':
422       put(static_cast<char_type>('?'));
423       return;
424    }
425    std::ptrdiff_t len = ::boost::re_detail::distance(m_position, m_end);
426    len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
427    int v = m_traits.toi(m_position, m_position + len, 10);
428    if(v < 0)
429    {
430       // oops not a number:
431       put(static_cast<char_type>('?'));
432       return;
433    }
434
435    // output varies depending upon whether sub-expression v matched or not:
436    if(m_results[v].matched)
437    {
438       m_have_conditional = true;
439       format_all();
440       m_have_conditional = false;
441       if((m_position != m_end) && (*m_position == static_cast<char_type>(':')))
442       {
443          // skip the ':':
444          ++m_position;
445          // save output state, then turn it off:
446          output_state saved_state = m_state;
447          m_state = output_none;
448          // format the rest of this scope:
449          format_until_scope_end();
450          // restore output state:
451          m_state = saved_state;
452       }
453    }
454    else
455    {
456       // save output state, then turn it off:
457       output_state saved_state = m_state;
458       m_state = output_none;
459       // format until ':' or ')':
460       m_have_conditional = true;
461       format_all();
462       m_have_conditional = false;
463       // restore state:
464       m_state = saved_state;
465       if((m_position != m_end) && (*m_position == static_cast<char_type>(':')))
466       {
467          // skip the ':':
468          ++m_position;
469          // format the rest of this scope:
470          format_until_scope_end();
471       }
472    }
473 }
474
475 template <class OutputIterator, class Results, class traits>
476 void basic_regex_formatter<OutputIterator, Results, traits>::format_until_scope_end()
477 {
478    do
479    {
480       format_all();
481       if((m_position == m_end) || (*m_position == static_cast<char_type>(')')))
482          return;
483       put(*m_position++);
484    }while(m_position != m_end);
485 }
486
487 template <class OutputIterator, class Results, class traits>
488 void basic_regex_formatter<OutputIterator, Results, traits>::put(char_type c)
489 {
490    // write a single character to output
491    // according to which case translation mode we are in:
492    switch(this->m_state)
493    {
494    case output_none:
495       return;
496    case output_next_lower:
497       c = m_traits.tolower(c);
498       this->m_state = output_copy;
499       break;
500    case output_next_upper:
501       c = m_traits.toupper(c);
502       this->m_state = output_copy;
503       break;
504    case output_lower:
505       c = m_traits.tolower(c);
506       break;
507    case output_upper:
508       c = m_traits.toupper(c);
509       break;
510    default:
511       break;
512    }
513    *m_out = c;
514    ++m_out;
515 }
516
517 template <class OutputIterator, class Results, class traits>
518 void basic_regex_formatter<OutputIterator, Results, traits>::put(const sub_match_type& sub)
519 {
520    typedef typename sub_match_type::iterator iterator_type;
521    iterator_type i = sub.first;
522    while(i != sub.second)
523    {
524       put(*i);
525       ++i;
526    }
527 }
528
529 template <class S>
530 class string_out_iterator
531 #ifndef BOOST_NO_STD_ITERATOR
532    : public std::iterator<std::output_iterator_tag, typename S::value_type>
533 #endif
534 {
535    S* out;
536 public:
537    string_out_iterator(S& s) : out(&s) {}
538    string_out_iterator& operator++() { return *this; }
539    string_out_iterator& operator++(int) { return *this; }
540    string_out_iterator& operator*() { return *this; }
541    string_out_iterator& operator=(typename S::value_type v) 
542    { 
543       out->append(1, v); 
544       return *this; 
545    }
546
547 #ifdef BOOST_NO_STD_ITERATOR
548    typedef std::ptrdiff_t difference_type;
549    typedef typename S::value_type value_type;
550    typedef value_type* pointer;
551    typedef value_type& reference;
552    typedef std::output_iterator_tag iterator_category;
553 #endif
554 };
555
556 template <class OutputIterator, class Iterator, class Alloc, class charT, class traits>
557 OutputIterator regex_format_imp(OutputIterator out,
558                           const match_results<Iterator, Alloc>& m,
559                           const charT* p1, const charT* p2,
560                           match_flag_type flags,
561                           const traits& t
562                          )
563 {
564    if(flags & regex_constants::format_literal)
565    {
566       return re_detail::copy(p1, p2, out);
567    }
568
569    re_detail::basic_regex_formatter<
570       OutputIterator, 
571       match_results<Iterator, Alloc>, 
572       traits > f(out, m, t);
573    return f.format(p1, p2, flags);
574 }
575
576
577 } // namespace re_detail
578
579 template <class OutputIterator, class Iterator, class charT>
580 OutputIterator regex_format(OutputIterator out,
581                           const match_results<Iterator>& m,
582                           const charT* fmt,
583                           match_flag_type flags = format_all
584                          )
585 {
586    re_detail::trivial_format_traits<charT> traits;
587    return re_detail::regex_format_imp(out, m, fmt, fmt + traits.length(fmt), flags, traits);
588 }
589
590 template <class OutputIterator, class Iterator, class charT>
591 OutputIterator regex_format(OutputIterator out,
592                           const match_results<Iterator>& m,
593                           const std::basic_string<charT>& fmt,
594                           match_flag_type flags = format_all
595                          )
596 {
597    re_detail::trivial_format_traits<charT> traits;
598    return re_detail::regex_format_imp(out, m, fmt.data(), fmt.data() + fmt.size(), flags, traits);
599 }  
600
601 template <class Iterator, class charT>
602 std::basic_string<charT> regex_format(const match_results<Iterator>& m, 
603                                       const charT* fmt, 
604                                       match_flag_type flags = format_all)
605 {
606    std::basic_string<charT> result;
607    re_detail::string_out_iterator<std::basic_string<charT> > i(result);
608    re_detail::trivial_format_traits<charT> traits;
609    re_detail::regex_format_imp(i, m, fmt, fmt + traits.length(fmt), flags, traits);
610    return result;
611 }
612
613 template <class Iterator, class charT>
614 std::basic_string<charT> regex_format(const match_results<Iterator>& m, 
615                                       const std::basic_string<charT>& fmt, 
616                                       match_flag_type flags = format_all)
617 {
618    std::basic_string<charT> result;
619    re_detail::string_out_iterator<std::basic_string<charT> > i(result);
620    re_detail::trivial_format_traits<charT> traits;
621    re_detail::regex_format_imp(i, m, fmt.data(), fmt.data() + fmt.size(), flags, traits);
622    return result;
623 }
624
625 #ifdef BOOST_HAS_ABI_HEADERS
626 #  include BOOST_ABI_SUFFIX
627 #endif
628
629 } // namespace boost
630
631 #endif  // BOOST_REGEX_FORMAT_HPP
632
633
634
635
636
637