Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/boost/regex/v4/regex_format.hpp @ 29

Last change on this file since 29 was 29, checked in by landauf, 17 years ago

updated boost from 1_33_1 to 1_34_1

File size: 17.3 KB
Line 
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
25namespace 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 >
35class match_results;
36
37namespace 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//
44template <class charT>
45struct 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
72template <class OutputIterator, class Results, class traits>
73class basic_regex_formatter
74{
75public:
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   }
84private:
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
112private:
113   basic_regex_formatter(const basic_regex_formatter&);
114   basic_regex_formatter& operator=(const basic_regex_formatter&);
115};
116
117template <class OutputIterator, class Results, class traits>
118OutputIterator 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
127template <class OutputIterator, class Results, class traits>
128void 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
205template <class OutputIterator, class Results, class traits>
206void 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
263template <class OutputIterator, class Results, class traits>
264void 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
416template <class OutputIterator, class Results, class traits>
417void 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
475template <class OutputIterator, class Results, class traits>
476void 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
487template <class OutputIterator, class Results, class traits>
488void 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
517template <class OutputIterator, class Results, class traits>
518void 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
529template <class S>
530class 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;
536public:
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
556template <class OutputIterator, class Iterator, class Alloc, class charT, class traits>
557OutputIterator 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
579template <class OutputIterator, class Iterator, class charT>
580OutputIterator 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
590template <class OutputIterator, class Iterator, class charT>
591OutputIterator 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
601template <class Iterator, class charT>
602std::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
613template <class Iterator, class charT>
614std::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
Note: See TracBrowser for help on using the repository browser.