]> git.lyx.org Git - lyx.git/blob - boost/boost/regex/v4/regex_format.hpp
boost: update to version 1.40
[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_MSVC
28 #pragma warning(push)
29 #pragma warning(disable: 4103)
30 #endif
31 #ifdef BOOST_HAS_ABI_HEADERS
32 #  include BOOST_ABI_PREFIX
33 #endif
34 #ifdef BOOST_MSVC
35 #pragma warning(pop)
36 #endif
37
38 //
39 // Forward declaration:
40 //
41    template <class BidiIterator, class Allocator = BOOST_DEDUCED_TYPENAME std::vector<sub_match<BidiIterator> >::allocator_type >
42 class match_results;
43
44 namespace re_detail{
45
46 //
47 // struct trivial_format_traits:
48 // defines minimum localisation support for formatting
49 // in the case that the actual regex traits is unavailable.
50 //
51 template <class charT>
52 struct trivial_format_traits
53 {
54    typedef charT char_type;
55
56    static std::ptrdiff_t length(const charT* p)
57    {
58       return global_length(p);
59    }
60    static charT tolower(charT c)
61    {
62       return ::boost::re_detail::global_lower(c);
63    }
64    static charT toupper(charT c)
65    {
66       return ::boost::re_detail::global_upper(c);
67    }
68    static int value(const charT c, int radix)
69    {
70       int result = global_value(c);
71       return result >= radix ? -1 : result;
72    }
73    int toi(const charT*& p1, const charT* p2, int radix)const
74    {
75       return global_toi(p1, p2, radix, *this);
76    }
77 };
78
79 template <class OutputIterator, class Results, class traits>
80 class basic_regex_formatter
81 {
82 public:
83    typedef typename traits::char_type char_type;
84    basic_regex_formatter(OutputIterator o, const Results& r, const traits& t)
85       : m_traits(t), m_results(r), m_out(o), m_state(output_copy), m_restore_state(output_copy), m_have_conditional(false) {}
86    OutputIterator format(const char_type* p1, const char_type* p2, match_flag_type f);
87    OutputIterator format(const char_type* p1, match_flag_type f)
88    {
89       return format(p1, p1 + m_traits.length(p1), f);
90    }
91 private:
92    typedef typename Results::value_type sub_match_type;
93    enum output_state
94    {
95       output_copy,
96       output_next_lower,
97       output_next_upper,
98       output_lower,
99       output_upper,
100       output_none
101    };
102
103    void put(char_type c);
104    void put(const sub_match_type& sub);
105    void format_all();
106    void format_perl();
107    void format_escape();
108    void format_conditional();
109    void format_until_scope_end();
110    bool handle_perl_verb(bool have_brace);
111
112    const traits& m_traits;       // the traits class for localised formatting operations
113    const Results& m_results;     // the match_results being used.
114    OutputIterator m_out;         // where to send output.
115    const char_type* m_position;  // format string, current position
116    const char_type* m_end;       // format string end
117    match_flag_type m_flags;      // format flags to use
118    output_state    m_state;      // what to do with the next character
119    output_state    m_restore_state;  // what state to restore to.
120    bool            m_have_conditional; // we are parsing a conditional
121 private:
122    basic_regex_formatter(const basic_regex_formatter&);
123    basic_regex_formatter& operator=(const basic_regex_formatter&);
124 };
125
126 template <class OutputIterator, class Results, class traits>
127 OutputIterator basic_regex_formatter<OutputIterator, Results, traits>::format(const char_type* p1, const char_type* p2, match_flag_type f)
128 {
129    m_position = p1;
130    m_end = p2;
131    m_flags = f;
132    format_all();
133    return m_out;
134 }
135
136 template <class OutputIterator, class Results, class traits>
137 void basic_regex_formatter<OutputIterator, Results, traits>::format_all()
138 {
139    // over and over:
140    while(m_position != m_end)
141    {
142       switch(*m_position)
143       {
144       case '&':
145          if(m_flags & ::boost::regex_constants::format_sed)
146          {
147             ++m_position;
148             put(m_results[0]);
149             break;
150          }
151          put(*m_position++);
152          break;
153       case '\\':
154          format_escape();
155          break;
156       case '(':
157          if(m_flags & boost::regex_constants::format_all)
158          {
159             ++m_position;
160             bool have_conditional = m_have_conditional;
161             m_have_conditional = false;
162             format_until_scope_end();
163             m_have_conditional = have_conditional;
164             if(m_position == m_end)
165                return;
166             BOOST_ASSERT(*m_position == static_cast<char_type>(')'));
167             ++m_position;  // skip the closing ')'
168             break;
169          }
170          put(*m_position);
171          ++m_position;
172          break;
173       case ')':
174          if(m_flags & boost::regex_constants::format_all)
175          {
176             return;
177          }
178          put(*m_position);
179          ++m_position;
180          break;
181       case ':':
182          if((m_flags & boost::regex_constants::format_all) && m_have_conditional)
183          {
184             return;
185          }
186          put(*m_position);
187          ++m_position;
188          break;
189       case '?':
190          if(m_flags & boost::regex_constants::format_all)
191          {
192             ++m_position;
193             format_conditional();
194             break;
195          }
196          put(*m_position);
197          ++m_position;
198          break;
199       case '$':
200          if((m_flags & format_sed) == 0)
201          {
202             format_perl();
203             break;
204          }
205          // fall through, not a special character:
206       default:
207          put(*m_position);
208          ++m_position;
209          break;
210       }
211    }
212 }
213
214 template <class OutputIterator, class Results, class traits>
215 void basic_regex_formatter<OutputIterator, Results, traits>::format_perl()
216 {
217    //
218    // On entry *m_position points to a '$' character
219    // output the information that goes with it:
220    //
221    BOOST_ASSERT(*m_position == '$');
222    //
223    // see if this is a trailing '$':
224    //
225    if(++m_position == m_end)
226    {
227       --m_position;
228       put(*m_position);
229       ++m_position;
230       return;
231    }
232    //
233    // OK find out what kind it is:
234    //
235    bool have_brace = false;
236    const char_type* save_position = m_position;
237    switch(*m_position)
238    {
239    case '&':
240       ++m_position;
241       put(this->m_results[0]);
242       break;
243    case '`':
244       ++m_position;
245       put(this->m_results.prefix());
246       break;
247    case '\'':
248       ++m_position;
249       put(this->m_results.suffix());
250       break;
251    case '$':
252       put(*m_position++);
253       break;
254    case '+':
255       if((++m_position != m_end) && (*m_position == '{'))
256       {
257          const char_type* base = ++m_position;
258          while((m_position != m_end) && (*m_position != '}')) ++m_position;
259          if(m_position != m_end)
260          {
261             // Named sub-expression:
262             put(this->m_results.named_subexpression(base, m_position));
263             ++m_position;
264             break;
265          }
266          else
267          {
268             m_position = --base;
269          }
270       }
271       put((this->m_results)[this->m_results.size() > 1 ? this->m_results.size() - 1 : 1]);
272       break;
273    case '{':
274       have_brace = true;
275       ++m_position;
276       // fall through....
277    default:
278       // see if we have a number:
279       {
280          std::ptrdiff_t len = ::boost::re_detail::distance(m_position, m_end);
281          //len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
282          int v = m_traits.toi(m_position, m_position + len, 10);
283          if((v < 0) || (have_brace && ((m_position == m_end) || (*m_position != '}'))))
284          {
285             // Look for a Perl-5.10 verb:
286             if(!handle_perl_verb(have_brace))
287             {
288                // leave the $ as is, and carry on:
289                m_position = --save_position;
290                put(*m_position);
291                ++m_position;
292             }
293             break;
294          }
295          // otherwise output sub v:
296          put(this->m_results[v]);
297          if(have_brace)
298             ++m_position;
299       }
300    }
301 }
302
303 template <class OutputIterator, class Results, class traits>
304 bool basic_regex_formatter<OutputIterator, Results, traits>::handle_perl_verb(bool have_brace)
305 {
306    // 
307    // We may have a capitalised string containing a Perl action:
308    //
309    static const char_type MATCH[] = { 'M', 'A', 'T', 'C', 'H' };
310    static const char_type PREMATCH[] = { 'P', 'R', 'E', 'M', 'A', 'T', 'C', 'H' };
311    static const char_type POSTMATCH[] = { 'P', 'O', 'S', 'T', 'M', 'A', 'T', 'C', 'H' };
312    static const char_type LAST_PAREN_MATCH[] = { 'L', 'A', 'S', 'T', '_', 'P', 'A', 'R', 'E', 'N', '_', 'M', 'A', 'T', 'C', 'H' };
313    static const char_type LAST_SUBMATCH_RESULT[] = { 'L', 'A', 'S', 'T', '_', 'S', 'U', 'B', 'M', 'A', 'T', 'C', 'H', '_', 'R', 'E', 'S', 'U', 'L', 'T' };
314    static const char_type LAST_SUBMATCH_RESULT_ALT[] = { '^', 'N' };
315
316    if(have_brace && (*m_position == '^'))
317       ++m_position;
318
319    int max_len = m_end - m_position;
320
321    if((max_len >= 5) && std::equal(m_position, m_position + 5, MATCH))
322    {
323       m_position += 5;
324       if(have_brace)
325       {
326          if(*m_position == '}')
327             ++m_position;
328          else
329          {
330             m_position -= 5;
331             return false;
332          }
333       }
334       put(this->m_results[0]);
335       return true;
336    }
337    if((max_len >= 8) && std::equal(m_position, m_position + 8, PREMATCH))
338    {
339       m_position += 8;
340       if(have_brace)
341       {
342          if(*m_position == '}')
343             ++m_position;
344          else
345          {
346             m_position -= 8;
347             return false;
348          }
349       }
350       put(this->m_results.prefix());
351       return true;
352    }
353    if((max_len >= 9) && std::equal(m_position, m_position + 9, POSTMATCH))
354    {
355       m_position += 9;
356       if(have_brace)
357       {
358          if(*m_position == '}')
359             ++m_position;
360          else
361          {
362             m_position -= 9;
363             return false;
364          }
365       }
366       put(this->m_results.suffix());
367       return true;
368    }
369    if((max_len >= 16) && std::equal(m_position, m_position + 16, LAST_PAREN_MATCH))
370    {
371       m_position += 16;
372       if(have_brace)
373       {
374          if(*m_position == '}')
375             ++m_position;
376          else
377          {
378             m_position -= 16;
379             return false;
380          }
381       }
382       put((this->m_results)[this->m_results.size() > 1 ? this->m_results.size() - 1 : 1]);
383       return true;
384    }
385    if((max_len >= 20) && std::equal(m_position, m_position + 20, LAST_SUBMATCH_RESULT))
386    {
387       m_position += 20;
388       if(have_brace)
389       {
390          if(*m_position == '}')
391             ++m_position;
392          else
393          {
394             m_position -= 20;
395             return false;
396          }
397       }
398       put(this->m_results.get_last_closed_paren());
399       return true;
400    }
401    if((max_len >= 2) && std::equal(m_position, m_position + 2, LAST_SUBMATCH_RESULT_ALT))
402    {
403       m_position += 2;
404       if(have_brace)
405       {
406          if(*m_position == '}')
407             ++m_position;
408          else
409          {
410             m_position -= 2;
411             return false;
412          }
413       }
414       put(this->m_results.get_last_closed_paren());
415       return true;
416    }
417    return false;
418 }
419
420 template <class OutputIterator, class Results, class traits>
421 void basic_regex_formatter<OutputIterator, Results, traits>::format_escape()
422 {
423    // skip the escape and check for trailing escape:
424    if(++m_position == m_end)
425    {
426       put(static_cast<char_type>('\\'));
427       return;
428    }
429    // now switch on the escape type:
430    switch(*m_position)
431    {
432    case 'a':
433       put(static_cast<char_type>('\a'));
434       ++m_position;
435       break;
436    case 'f':
437       put(static_cast<char_type>('\f'));
438       ++m_position;
439       break;
440    case 'n':
441       put(static_cast<char_type>('\n'));
442       ++m_position;
443       break;
444    case 'r':
445       put(static_cast<char_type>('\r'));
446       ++m_position;
447       break;
448    case 't':
449       put(static_cast<char_type>('\t'));
450       ++m_position;
451       break;
452    case 'v':
453       put(static_cast<char_type>('\v'));
454       ++m_position;
455       break;
456    case 'x':
457       if(++m_position == m_end)
458       {
459          put(static_cast<char_type>('x'));
460          return;
461       }
462       // maybe have \x{ddd}
463       if(*m_position == static_cast<char_type>('{'))
464       {
465          ++m_position;
466          int val = m_traits.toi(m_position, m_end, 16);
467          if(val < 0)
468          {
469             // invalid value treat everything as literals:
470             put(static_cast<char_type>('x'));
471             put(static_cast<char_type>('{'));
472             return;
473          }
474          if(*m_position != static_cast<char_type>('}'))
475          {
476             while(*m_position != static_cast<char_type>('\\'))
477                --m_position;
478             ++m_position;
479             put(*m_position++);
480             return;
481          }
482          ++m_position;
483          put(static_cast<char_type>(val));
484          return;
485       }
486       else
487       {
488          std::ptrdiff_t len = ::boost::re_detail::distance(m_position, m_end);
489          len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
490          int val = m_traits.toi(m_position, m_position + len, 16);
491          if(val < 0)
492          {
493             --m_position;
494             put(*m_position++);
495             return;
496          }
497          put(static_cast<char_type>(val));
498       }
499       break;
500    case 'c':
501       if(++m_position == m_end)
502       {
503          --m_position;
504          put(*m_position++);
505          return;
506       }
507       put(static_cast<char_type>(*m_position++ % 32));
508       break;
509    case 'e':
510       put(static_cast<char_type>(27));
511       ++m_position;
512       break;
513    default:
514       // see if we have a perl specific escape:
515       if((m_flags & boost::regex_constants::format_sed) == 0)
516       {
517          bool breakout = false;
518          switch(*m_position)
519          {
520          case 'l':
521             ++m_position;
522             m_restore_state = m_state;
523             m_state = output_next_lower;
524             breakout = true;
525             break;
526          case 'L':
527             ++m_position;
528             m_state = output_lower;
529             breakout = true;
530             break;
531          case 'u':
532             ++m_position;
533             m_restore_state = m_state;
534             m_state = output_next_upper;
535             breakout = true;
536             break;
537          case 'U':
538             ++m_position;
539             m_state = output_upper;
540             breakout = true;
541             break;
542          case 'E':
543             ++m_position;
544             m_state = output_copy;
545             breakout = true;
546             break;
547          }
548          if(breakout)
549             break;
550       }
551       // see if we have a \n sed style backreference:
552       int v = m_traits.toi(m_position, m_position+1, 10);
553       if((v > 0) || ((v == 0) && (m_flags & ::boost::regex_constants::format_sed)))
554       {
555          put(m_results[v]);
556          break;
557       }
558       else if(v == 0)
559       {
560          // octal ecape sequence:
561          --m_position;
562          std::ptrdiff_t len = ::boost::re_detail::distance(m_position, m_end);
563          len = (std::min)(static_cast<std::ptrdiff_t>(4), len);
564          v = m_traits.toi(m_position, m_position + len, 8);
565          BOOST_ASSERT(v >= 0);
566          put(static_cast<char_type>(v));
567          break;
568       }
569       // Otherwise output the character "as is":
570       put(*m_position++);
571       break;
572    }
573 }
574
575 template <class OutputIterator, class Results, class traits>
576 void basic_regex_formatter<OutputIterator, Results, traits>::format_conditional()
577 {
578    if(m_position == m_end)
579    {
580       // oops trailing '?':
581       put(static_cast<char_type>('?'));
582       return;
583    }
584    int v;
585    if(*m_position == '{')
586    {
587       const char_type* base = m_position;
588       ++m_position;
589       v = m_traits.toi(m_position, m_end, 10);
590       if(v < 0)
591       {
592          // Try a named subexpression:
593          while((m_position != m_end) && (*m_position != '}'))
594             ++m_position;
595          v = m_results.named_subexpression_index(base + 1, m_position);
596       }
597       if((v < 0) || (*m_position != '}'))
598       {
599          m_position = base;
600          // oops trailing '?':
601          put(static_cast<char_type>('?'));
602          return;
603       }
604       // Skip trailing '}':
605       ++m_position;
606    }
607    else
608    {
609       std::ptrdiff_t len = ::boost::re_detail::distance(m_position, m_end);
610       len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
611       v = m_traits.toi(m_position, m_position + len, 10);
612    }
613    if(v < 0)
614    {
615       // oops not a number:
616       put(static_cast<char_type>('?'));
617       return;
618    }
619
620    // output varies depending upon whether sub-expression v matched or not:
621    if(m_results[v].matched)
622    {
623       m_have_conditional = true;
624       format_all();
625       m_have_conditional = false;
626       if((m_position != m_end) && (*m_position == static_cast<char_type>(':')))
627       {
628          // skip the ':':
629          ++m_position;
630          // save output state, then turn it off:
631          output_state saved_state = m_state;
632          m_state = output_none;
633          // format the rest of this scope:
634          format_until_scope_end();
635          // restore output state:
636          m_state = saved_state;
637       }
638    }
639    else
640    {
641       // save output state, then turn it off:
642       output_state saved_state = m_state;
643       m_state = output_none;
644       // format until ':' or ')':
645       m_have_conditional = true;
646       format_all();
647       m_have_conditional = false;
648       // restore state:
649       m_state = saved_state;
650       if((m_position != m_end) && (*m_position == static_cast<char_type>(':')))
651       {
652          // skip the ':':
653          ++m_position;
654          // format the rest of this scope:
655          format_until_scope_end();
656       }
657    }
658 }
659
660 template <class OutputIterator, class Results, class traits>
661 void basic_regex_formatter<OutputIterator, Results, traits>::format_until_scope_end()
662 {
663    do
664    {
665       format_all();
666       if((m_position == m_end) || (*m_position == static_cast<char_type>(')')))
667          return;
668       put(*m_position++);
669    }while(m_position != m_end);
670 }
671
672 template <class OutputIterator, class Results, class traits>
673 void basic_regex_formatter<OutputIterator, Results, traits>::put(char_type c)
674 {
675    // write a single character to output
676    // according to which case translation mode we are in:
677    switch(this->m_state)
678    {
679    case output_none:
680       return;
681    case output_next_lower:
682       c = m_traits.tolower(c);
683       this->m_state = m_restore_state;
684       break;
685    case output_next_upper:
686       c = m_traits.toupper(c);
687       this->m_state = m_restore_state;
688       break;
689    case output_lower:
690       c = m_traits.tolower(c);
691       break;
692    case output_upper:
693       c = m_traits.toupper(c);
694       break;
695    default:
696       break;
697    }
698    *m_out = c;
699    ++m_out;
700 }
701
702 template <class OutputIterator, class Results, class traits>
703 void basic_regex_formatter<OutputIterator, Results, traits>::put(const sub_match_type& sub)
704 {
705    typedef typename sub_match_type::iterator iterator_type;
706    iterator_type i = sub.first;
707    while(i != sub.second)
708    {
709       put(*i);
710       ++i;
711    }
712 }
713
714 template <class S>
715 class string_out_iterator
716 #ifndef BOOST_NO_STD_ITERATOR
717    : public std::iterator<std::output_iterator_tag, typename S::value_type>
718 #endif
719 {
720    S* out;
721 public:
722    string_out_iterator(S& s) : out(&s) {}
723    string_out_iterator& operator++() { return *this; }
724    string_out_iterator& operator++(int) { return *this; }
725    string_out_iterator& operator*() { return *this; }
726    string_out_iterator& operator=(typename S::value_type v) 
727    { 
728       out->append(1, v); 
729       return *this; 
730    }
731
732 #ifdef BOOST_NO_STD_ITERATOR
733    typedef std::ptrdiff_t difference_type;
734    typedef typename S::value_type value_type;
735    typedef value_type* pointer;
736    typedef value_type& reference;
737    typedef std::output_iterator_tag iterator_category;
738 #endif
739 };
740
741 template <class OutputIterator, class Iterator, class Alloc, class charT, class traits>
742 OutputIterator regex_format_imp(OutputIterator out,
743                           const match_results<Iterator, Alloc>& m,
744                           const charT* p1, const charT* p2,
745                           match_flag_type flags,
746                           const traits& t
747                          )
748 {
749    if(flags & regex_constants::format_literal)
750    {
751       return re_detail::copy(p1, p2, out);
752    }
753
754    re_detail::basic_regex_formatter<
755       OutputIterator, 
756       match_results<Iterator, Alloc>, 
757       traits > f(out, m, t);
758    return f.format(p1, p2, flags);
759 }
760
761
762 } // namespace re_detail
763
764 template <class OutputIterator, class Iterator, class charT>
765 OutputIterator regex_format(OutputIterator out,
766                           const match_results<Iterator>& m,
767                           const charT* fmt,
768                           match_flag_type flags = format_all
769                          )
770 {
771    re_detail::trivial_format_traits<charT> traits;
772    return re_detail::regex_format_imp(out, m, fmt, fmt + traits.length(fmt), flags, traits);
773 }
774
775 template <class OutputIterator, class Iterator, class charT>
776 OutputIterator regex_format(OutputIterator out,
777                           const match_results<Iterator>& m,
778                           const std::basic_string<charT>& fmt,
779                           match_flag_type flags = format_all
780                          )
781 {
782    re_detail::trivial_format_traits<charT> traits;
783    return re_detail::regex_format_imp(out, m, fmt.data(), fmt.data() + fmt.size(), flags, traits);
784 }  
785
786 template <class Iterator, class charT>
787 std::basic_string<charT> regex_format(const match_results<Iterator>& m, 
788                                       const charT* fmt, 
789                                       match_flag_type flags = format_all)
790 {
791    std::basic_string<charT> result;
792    re_detail::string_out_iterator<std::basic_string<charT> > i(result);
793    re_detail::trivial_format_traits<charT> traits;
794    re_detail::regex_format_imp(i, m, fmt, fmt + traits.length(fmt), flags, traits);
795    return result;
796 }
797
798 template <class Iterator, class charT>
799 std::basic_string<charT> regex_format(const match_results<Iterator>& m, 
800                                       const std::basic_string<charT>& fmt, 
801                                       match_flag_type flags = format_all)
802 {
803    std::basic_string<charT> result;
804    re_detail::string_out_iterator<std::basic_string<charT> > i(result);
805    re_detail::trivial_format_traits<charT> traits;
806    re_detail::regex_format_imp(i, m, fmt.data(), fmt.data() + fmt.size(), flags, traits);
807    return result;
808 }
809
810 #ifdef BOOST_MSVC
811 #pragma warning(push)
812 #pragma warning(disable: 4103)
813 #endif
814 #ifdef BOOST_HAS_ABI_HEADERS
815 #  include BOOST_ABI_SUFFIX
816 #endif
817 #ifdef BOOST_MSVC
818 #pragma warning(pop)
819 #endif
820
821 } // namespace boost
822
823 #endif  // BOOST_REGEX_FORMAT_HPP
824
825
826
827
828
829