]> git.lyx.org Git - features.git/blob - boost/boost/regex/v4/cpp_regex_traits.hpp
update to boost 1.34
[features.git] / boost / boost / regex / v4 / cpp_regex_traits.hpp
1 /*
2  *
3  * Copyright (c) 2004
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         cpp_regex_traits.hpp
15   *   VERSION      see <boost/version.hpp>
16   *   DESCRIPTION: Declares regular expression traits class cpp_regex_traits.
17   */
18
19 #ifndef BOOST_CPP_REGEX_TRAITS_HPP_INCLUDED
20 #define BOOST_CPP_REGEX_TRAITS_HPP_INCLUDED
21
22 #include <boost/config.hpp>
23
24 #ifndef BOOST_NO_STD_LOCALE
25
26 #ifndef BOOST_RE_PAT_EXCEPT_HPP
27 #include <boost/regex/pattern_except.hpp>
28 #endif
29 #ifndef BOOST_REGEX_TRAITS_DEFAULTS_HPP_INCLUDED
30 #include <boost/regex/v4/regex_traits_defaults.hpp>
31 #endif
32 #ifdef BOOST_HAS_THREADS
33 #include <boost/regex/pending/static_mutex.hpp>
34 #endif
35 #ifndef BOOST_REGEX_PRIMARY_TRANSFORM
36 #include <boost/regex/v4/primary_transform.hpp>
37 #endif
38 #ifndef BOOST_REGEX_OBJECT_CACHE_HPP
39 #include <boost/regex/pending/object_cache.hpp>
40 #endif
41
42 #include <istream>
43 #include <ios>
44
45 #ifdef BOOST_HAS_ABI_HEADERS
46 #  include BOOST_ABI_PREFIX
47 #endif
48
49 #ifdef BOOST_MSVC
50 #pragma warning(push)
51 #pragma warning(disable:4786)
52 #endif
53
54 namespace boost{ 
55
56 //
57 // forward declaration is needed by some compilers:
58 //
59 template <class charT>
60 class cpp_regex_traits;
61    
62 namespace re_detail{
63
64 //
65 // class parser_buf:
66 // acts as a stream buffer which wraps around a pair of pointers:
67 //
68 template <class charT,
69           class traits = ::std::char_traits<charT> >
70 class parser_buf : public ::std::basic_streambuf<charT, traits>
71 {
72    typedef ::std::basic_streambuf<charT, traits> base_type;
73    typedef typename base_type::int_type int_type;
74    typedef typename base_type::char_type char_type;
75    typedef typename base_type::pos_type pos_type;
76    typedef ::std::streamsize streamsize;
77    typedef typename base_type::off_type off_type;
78 public:
79    parser_buf() : base_type() { setbuf(0, 0); }
80    const charT* getnext() { return this->gptr(); }
81 protected:
82    std::basic_streambuf<charT, traits>* setbuf(char_type* s, streamsize n);
83    typename parser_buf<charT, traits>::pos_type seekpos(pos_type sp, ::std::ios_base::openmode which);
84    typename parser_buf<charT, traits>::pos_type seekoff(off_type off, ::std::ios_base::seekdir way, ::std::ios_base::openmode which);
85 private:
86    parser_buf& operator=(const parser_buf&);
87    parser_buf(const parser_buf&);
88 };
89
90 template<class charT, class traits>
91 std::basic_streambuf<charT, traits>*
92 parser_buf<charT, traits>::setbuf(char_type* s, streamsize n)
93 {
94    this->setg(s, s, s + n);
95    return this;
96 }
97
98 template<class charT, class traits>
99 typename parser_buf<charT, traits>::pos_type
100 parser_buf<charT, traits>::seekoff(off_type off, ::std::ios_base::seekdir way, ::std::ios_base::openmode which)
101 {
102    if(which & ::std::ios_base::out)
103       return pos_type(off_type(-1));
104    std::ptrdiff_t size = this->egptr() - this->eback();
105    std::ptrdiff_t pos = this->gptr() - this->eback();
106    charT* g = this->eback();
107    switch(way)
108    {
109    case ::std::ios_base::beg:
110       if((off < 0) || (off > size))
111          return pos_type(off_type(-1));
112       else
113          this->setg(g, g + off, g + size);
114       break;
115    case ::std::ios_base::end:
116       if((off < 0) || (off > size))
117          return pos_type(off_type(-1));
118       else
119          this->setg(g, g + size - off, g + size);
120       break;
121    case ::std::ios_base::cur:
122    {
123       std::ptrdiff_t newpos = pos + off;
124       if((newpos < 0) || (newpos > size))
125          return pos_type(off_type(-1));
126       else
127          this->setg(g, g + newpos, g + size);
128       break;
129    }
130    default: ;
131    }
132 #ifdef BOOST_MSVC
133 #pragma warning(push)
134 #pragma warning(disable:4244)
135 #endif
136    return static_cast<pos_type>(this->gptr() - this->eback());
137 #ifdef BOOST_MSVC
138 #pragma warning(pop)
139 #endif
140 }
141
142 template<class charT, class traits>
143 typename parser_buf<charT, traits>::pos_type
144 parser_buf<charT, traits>::seekpos(pos_type sp, ::std::ios_base::openmode which)
145 {
146    if(which & ::std::ios_base::out)
147       return pos_type(off_type(-1));
148    off_type size = static_cast<off_type>(this->egptr() - this->eback());
149    charT* g = this->eback();
150    if(off_type(sp) <= size)
151    {
152       this->setg(g, g + off_type(sp), g + size);
153    }
154    return pos_type(off_type(-1));
155 }
156
157 //
158 // class cpp_regex_traits_base:
159 // acts as a container for locale and the facets we are using.
160 //
161 template <class charT>
162 struct cpp_regex_traits_base
163 {
164    cpp_regex_traits_base(const std::locale& l)
165    { imbue(l); }
166    std::locale imbue(const std::locale& l);
167
168    std::locale m_locale;
169    std::ctype<charT> const* m_pctype;
170 #ifndef BOOST_NO_STD_MESSAGES
171    std::messages<charT> const* m_pmessages;
172 #endif
173    std::collate<charT> const* m_pcollate;
174
175    bool operator<(const cpp_regex_traits_base& b)const
176    {
177       if(m_pctype == b.m_pctype)
178       {
179 #ifndef BOOST_NO_STD_MESSAGES
180          if(m_pmessages == b.m_pmessages)
181          {
182          }
183          return m_pmessages < b.m_pmessages;
184 #else
185          return m_pcollate < b.m_pcollate;
186 #endif
187       }
188       return m_pctype < b.m_pctype;
189    }
190    bool operator==(const cpp_regex_traits_base& b)const
191    {
192       return (m_pctype == b.m_pctype) 
193 #ifndef BOOST_NO_STD_MESSAGES
194          && (m_pmessages == b.m_pmessages) 
195 #endif
196          && (m_pcollate == b.m_pcollate);
197    }
198 };
199
200 template <class charT>
201 std::locale cpp_regex_traits_base<charT>::imbue(const std::locale& l)
202 {
203    std::locale result(m_locale);
204    m_locale = l;
205    m_pctype = &BOOST_USE_FACET(std::ctype<charT>, l);
206 #ifndef BOOST_NO_STD_MESSAGES
207    m_pmessages = &BOOST_USE_FACET(std::messages<charT>, l);
208 #endif
209    m_pcollate = &BOOST_USE_FACET(std::collate<charT>, l);
210    return result;
211 }
212
213 //
214 // class cpp_regex_traits_char_layer:
215 // implements methods that require specialisation for narrow characters:
216 //
217 template <class charT>
218 class cpp_regex_traits_char_layer : public cpp_regex_traits_base<charT>
219 {
220    typedef std::basic_string<charT> string_type;
221    typedef std::map<charT, regex_constants::syntax_type> map_type;
222    typedef typename map_type::const_iterator map_iterator_type;
223 public:
224    cpp_regex_traits_char_layer(const std::locale& l)
225       : cpp_regex_traits_base<charT>(l)
226    {
227       init();
228    }
229    cpp_regex_traits_char_layer(const cpp_regex_traits_base<charT>& b)
230       : cpp_regex_traits_base<charT>(b)
231    {
232       init();
233    }
234    void init();
235
236    regex_constants::syntax_type syntax_type(charT c)const
237    {
238       map_iterator_type i = m_char_map.find(c);
239       return ((i == m_char_map.end()) ? 0 : i->second);
240    }
241    regex_constants::escape_syntax_type escape_syntax_type(charT c) const
242    {
243       map_iterator_type i = m_char_map.find(c);
244       if(i == m_char_map.end())
245       {
246          if(this->m_pctype->is(std::ctype_base::lower, c)) return regex_constants::escape_type_class;
247          if(this->m_pctype->is(std::ctype_base::upper, c)) return regex_constants::escape_type_not_class;
248          return 0;
249       }
250       return i->second;
251    }
252
253 private:
254    string_type get_default_message(regex_constants::syntax_type);
255    // TODO: use a hash table when available!
256    map_type m_char_map;
257 };
258
259 template <class charT>
260 void cpp_regex_traits_char_layer<charT>::init()
261 {
262    // we need to start by initialising our syntax map so we know which
263    // character is used for which purpose:
264 #ifndef BOOST_NO_STD_MESSAGES
265 #ifndef __IBMCPP__
266    typename std::messages<charT>::catalog cat = static_cast<std::messages<char>::catalog>(-1);
267 #else
268    typename std::messages<charT>::catalog cat = reinterpret_cast<std::messages<char>::catalog>(-1);
269 #endif
270    std::string cat_name(cpp_regex_traits<charT>::get_catalog_name());
271    if(cat_name.size())
272    {
273       cat = this->m_pmessages->open(
274          cat_name, 
275          this->m_locale);
276       if((int)cat < 0)
277       {
278          std::string m("Unable to open message catalog: ");
279          std::runtime_error err(m + cat_name);
280          boost::re_detail::raise_runtime_error(err);
281       }
282    }
283    //
284    // if we have a valid catalog then load our messages:
285    //
286    if((int)cat >= 0)
287    {
288       try{
289          for(regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i)
290          {
291             string_type mss = this->m_pmessages->get(cat, 0, i, get_default_message(i));
292             for(typename string_type::size_type j = 0; j < mss.size(); ++j)
293             {
294                m_char_map[mss[j]] = i;
295             }
296          }
297          this->m_pmessages->close(cat);
298       }
299       catch(...)
300       {
301          this->m_pmessages->close(cat);
302          throw;
303       }
304    }
305    else
306    {
307 #endif
308       for(regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i)
309       {
310          const char* ptr = get_default_syntax(i);
311          while(ptr && *ptr)
312          {
313             m_char_map[this->m_pctype->widen(*ptr)] = i;
314             ++ptr;
315          }
316       }
317 #ifndef BOOST_NO_STD_MESSAGES
318    }
319 #endif
320 }
321
322 template <class charT>
323 typename cpp_regex_traits_char_layer<charT>::string_type 
324    cpp_regex_traits_char_layer<charT>::get_default_message(regex_constants::syntax_type i)
325 {
326    const char* ptr = get_default_syntax(i);
327    string_type result;
328    while(ptr && *ptr)
329    {
330       result.append(1, this->m_pctype->widen(*ptr));
331       ++ptr;
332    }
333    return result;
334 }
335
336 //
337 // specialised version for narrow characters:
338 //
339 template <>
340 class BOOST_REGEX_DECL cpp_regex_traits_char_layer<char> : public cpp_regex_traits_base<char>
341 {
342    typedef std::string string_type;
343 public:
344    cpp_regex_traits_char_layer(const std::locale& l)
345    : cpp_regex_traits_base<char>(l)
346    {
347       init();
348    }
349    cpp_regex_traits_char_layer(const cpp_regex_traits_base<char>& l)
350    : cpp_regex_traits_base<char>(l)
351    {
352       init();
353    }
354
355    regex_constants::syntax_type syntax_type(char c)const
356    {
357       return m_char_map[static_cast<unsigned char>(c)];
358    }
359    regex_constants::escape_syntax_type escape_syntax_type(char c) const
360    {
361       return m_char_map[static_cast<unsigned char>(c)];
362    }
363
364 private:
365    regex_constants::syntax_type m_char_map[1u << CHAR_BIT];
366    void init();
367 };
368
369 #ifdef BOOST_REGEX_BUGGY_CTYPE_FACET
370 enum
371 {
372    char_class_space=1<<0, 
373    char_class_print=1<<1, 
374    char_class_cntrl=1<<2, 
375    char_class_upper=1<<3, 
376    char_class_lower=1<<4,
377    char_class_alpha=1<<5, 
378    char_class_digit=1<<6, 
379    char_class_punct=1<<7, 
380    char_class_xdigit=1<<8,
381    char_class_alnum=char_class_alpha|char_class_digit, 
382    char_class_graph=char_class_alnum|char_class_punct,
383    char_class_blank=1<<9,
384    char_class_word=1<<10,
385    char_class_unicode=1<<11
386 };
387
388 #endif
389
390 //
391 // class cpp_regex_traits_implementation:
392 // provides pimpl implementation for cpp_regex_traits.
393 //
394 template <class charT>
395 class cpp_regex_traits_implementation : public cpp_regex_traits_char_layer<charT>
396 {
397 public:
398    typedef typename cpp_regex_traits<charT>::char_class_type char_class_type;
399    typedef typename std::ctype<charT>::mask                  native_mask_type;
400 #ifndef BOOST_REGEX_BUGGY_CTYPE_FACET
401    BOOST_STATIC_CONSTANT(char_class_type, mask_blank = 1u << 24);
402    BOOST_STATIC_CONSTANT(char_class_type, mask_word = 1u << 25);
403    BOOST_STATIC_CONSTANT(char_class_type, mask_unicode = 1u << 26);
404 #endif
405
406    typedef std::basic_string<charT> string_type;
407    typedef charT char_type;
408    //cpp_regex_traits_implementation();
409    cpp_regex_traits_implementation(const std::locale& l)
410       : cpp_regex_traits_char_layer<charT>(l)
411    {
412       init();
413    }
414    cpp_regex_traits_implementation(const cpp_regex_traits_base<charT>& l)
415       : cpp_regex_traits_char_layer<charT>(l)
416    {
417       init();
418    }
419    std::string error_string(regex_constants::error_type n) const
420    {
421       if(!m_error_strings.empty())
422       {
423          std::map<int, std::string>::const_iterator p = m_error_strings.find(n);
424          return (p == m_error_strings.end()) ? std::string(get_default_error_string(n)) : p->second;
425       }
426       return get_default_error_string(n);
427    }
428    char_class_type lookup_classname(const charT* p1, const charT* p2) const
429    {
430       char_class_type result = lookup_classname_imp(p1, p2);
431       if(result == 0)
432       {
433          string_type temp(p1, p2);
434          this->m_pctype->tolower(&*temp.begin(), &*temp.begin() + temp.size());
435          result = lookup_classname_imp(&*temp.begin(), &*temp.begin() + temp.size());
436       }
437       return result;
438    }
439    string_type lookup_collatename(const charT* p1, const charT* p2) const;
440    string_type transform_primary(const charT* p1, const charT* p2) const;
441    string_type transform(const charT* p1, const charT* p2) const;
442 private:
443    std::map<int, std::string>     m_error_strings;   // error messages indexed by numberic ID
444    std::map<string_type, char_class_type>  m_custom_class_names; // character class names
445    std::map<string_type, string_type>      m_custom_collate_names; // collating element names
446    unsigned                       m_collate_type;    // the form of the collation string
447    charT                          m_collate_delim;   // the collation group delimiter
448    //
449    // helpers:
450    //
451    char_class_type lookup_classname_imp(const charT* p1, const charT* p2) const;
452    void init();
453 #ifdef BOOST_REGEX_BUGGY_CTYPE_FACET
454 public:
455    bool isctype(charT c, char_class_type m)const;
456 #endif
457 };
458
459 #ifndef BOOST_REGEX_BUGGY_CTYPE_FACET
460 #if !defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION)
461
462 template <class charT>
463 typename cpp_regex_traits_implementation<charT>::char_class_type const cpp_regex_traits_implementation<charT>::mask_blank;
464 template <class charT>
465 typename cpp_regex_traits_implementation<charT>::char_class_type const cpp_regex_traits_implementation<charT>::mask_word;
466 template <class charT>
467 typename cpp_regex_traits_implementation<charT>::char_class_type const cpp_regex_traits_implementation<charT>::mask_unicode;
468
469 #endif
470 #endif
471
472 template <class charT>
473 typename cpp_regex_traits_implementation<charT>::string_type 
474    cpp_regex_traits_implementation<charT>::transform_primary(const charT* p1, const charT* p2) const
475 {
476    //
477    // PRECONDITIONS:
478    //
479    // A bug in gcc 3.2 (and maybe other versions as well) treats
480    // p1 as a null terminated string, for efficiency reasons 
481    // we work around this elsewhere, but just assert here that
482    // we adhere to gcc's (buggy) preconditions...
483    //
484    BOOST_ASSERT(*p2 == 0);
485
486    string_type result;
487    //
488    // swallowing all exceptions here is a bad idea
489    // however at least one std lib will always throw
490    // std::bad_alloc for certain arguments...
491    //
492    try{
493       //
494       // What we do here depends upon the format of the sort key returned by
495       // sort key returned by this->transform:
496       //
497       switch(m_collate_type)
498       {
499       case sort_C:
500       case sort_unknown:
501          // the best we can do is translate to lower case, then get a regular sort key:
502          {
503             result.assign(p1, p2);
504             this->m_pctype->tolower(&*result.begin(), &*result.begin() + result.size());
505             result = this->m_pcollate->transform(&*result.begin(), &*result.begin() + result.size());
506             break;
507          }
508       case sort_fixed:
509          {
510             // get a regular sort key, and then truncate it:
511             result.assign(this->m_pcollate->transform(p1, p2));
512             result.erase(this->m_collate_delim);
513             break;
514          }
515       case sort_delim:
516             // get a regular sort key, and then truncate everything after the delim:
517             result.assign(this->m_pcollate->transform(p1, p2));
518             std::size_t i;
519             for(i = 0; i < result.size(); ++i)
520             {
521                if(result[i] == m_collate_delim)
522                   break;
523             }
524             result.erase(i);
525             break;
526       }
527    }catch(...){}
528    while(result.size() && (charT(0) == *result.rbegin()))
529       result.erase(result.size() - 1);
530    if(result.empty())
531    {
532       // character is ignorable at the primary level:
533       result = string_type(1, charT(0));
534    }
535    return result;
536 }
537
538 template <class charT>
539 typename cpp_regex_traits_implementation<charT>::string_type 
540    cpp_regex_traits_implementation<charT>::transform(const charT* p1, const charT* p2) const
541 {
542    //
543    // PRECONDITIONS:
544    //
545    // A bug in gcc 3.2 (and maybe other versions as well) treats
546    // p1 as a null terminated string, for efficiency reasons 
547    // we work around this elsewhere, but just assert here that
548    // we adhere to gcc's (buggy) preconditions...
549    //
550    BOOST_ASSERT(*p2 == 0);
551    //
552    // swallowing all exceptions here is a bad idea
553    // however at least one std lib will always throw
554    // std::bad_alloc for certain arguments...
555    //
556    string_type result;
557    try{
558       result = this->m_pcollate->transform(p1, p2);
559       //
560       // Borland's STLPort version returns a NULL-terminated
561       // string that has garbage at the end - each call to
562       // std::collate<wchar_t>::transform returns a different string!
563       // So as a workaround, we'll truncate the string at the first NULL
564       // which _seems_ to work....
565 #if BOOST_WORKAROUND(__BORLANDC__, < 0x580)
566       result.erase(result.find(charT(0)));
567 #else
568       //
569       // some implementations (Dinkumware) append unnecessary trailing \0's:
570       while(result.size() && (charT(0) == *result.rbegin()))
571          result.erase(result.size() - 1);
572 #endif
573       BOOST_ASSERT(std::find(result.begin(), result.end(), charT(0)) == result.end());
574    }
575    catch(...)
576    {
577    }
578    return result;
579 }
580
581
582 template <class charT>
583 typename cpp_regex_traits_implementation<charT>::string_type 
584    cpp_regex_traits_implementation<charT>::lookup_collatename(const charT* p1, const charT* p2) const
585 {
586    typedef typename std::map<string_type, string_type>::const_iterator iter_type;
587    if(m_custom_collate_names.size())
588    {
589       iter_type pos = m_custom_collate_names.find(string_type(p1, p2));
590       if(pos != m_custom_collate_names.end())
591          return pos->second;
592    }
593 #if !defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)\
594                && !BOOST_WORKAROUND(BOOST_MSVC, < 1300)\
595                && !BOOST_WORKAROUND(__BORLANDC__, <= 0x0551)
596    std::string name(p1, p2);
597 #else
598    std::string name;
599    const charT* p0 = p1;
600    while(p0 != p2)
601       name.append(1, char(*p0++));
602 #endif
603    name = lookup_default_collate_name(name);
604 #if !defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)\
605                && !BOOST_WORKAROUND(BOOST_MSVC, < 1300)\
606                && !BOOST_WORKAROUND(__BORLANDC__, <= 0x0551)
607    if(name.size())
608       return string_type(name.begin(), name.end());
609 #else
610    if(name.size())
611    {
612       string_type result;
613       typedef std::string::const_iterator iter;
614       iter b = name.begin();
615       iter e = name.end();
616       while(b != e)
617          result.append(1, charT(*b++));
618       return result;
619    }
620 #endif
621    if(p2 - p1 == 1)
622       return string_type(1, *p1);
623    return string_type();
624 }
625
626 template <class charT>
627 void cpp_regex_traits_implementation<charT>::init()
628 {
629 #ifndef BOOST_NO_STD_MESSAGES
630 #ifndef __IBMCPP__
631    typename std::messages<charT>::catalog cat = static_cast<std::messages<char>::catalog>(-1);
632 #else
633    typename std::messages<charT>::catalog cat = reinterpret_cast<std::messages<char>::catalog>(-1);
634 #endif
635    std::string cat_name(cpp_regex_traits<charT>::get_catalog_name());
636    if(cat_name.size())
637    {
638       cat = this->m_pmessages->open(
639          cat_name, 
640          this->m_locale);
641       if((int)cat < 0)
642       {
643          std::string m("Unable to open message catalog: ");
644          std::runtime_error err(m + cat_name);
645          boost::re_detail::raise_runtime_error(err);
646       }
647    }
648    //
649    // if we have a valid catalog then load our messages:
650    //
651    if((int)cat >= 0)
652    {
653       //
654       // Error messages:
655       //
656       for(boost::regex_constants::error_type i = static_cast<boost::regex_constants::error_type>(0); 
657          i <= boost::regex_constants::error_unknown; 
658          i = static_cast<boost::regex_constants::error_type>(i + 1))
659       {
660          const char* p = get_default_error_string(i);
661          string_type default_message;
662          while(*p)
663          {
664             default_message.append(1, this->m_pctype->widen(*p));
665             ++p;
666          }
667          string_type s = this->m_pmessages->get(cat, 0, i+200, default_message);
668          std::string result;
669          for(std::string::size_type j = 0; j < s.size(); ++j)
670          {
671             result.append(1, this->m_pctype->narrow(s[j], 0));
672          }
673          m_error_strings[i] = result;
674       }
675       //
676       // Custom class names:
677       //
678 #ifndef BOOST_REGEX_BUGGY_CTYPE_FACET
679       static const char_class_type masks[14] = 
680       {
681          std::ctype<charT>::alnum,
682          std::ctype<charT>::alpha,
683          std::ctype<charT>::cntrl,
684          std::ctype<charT>::digit,
685          std::ctype<charT>::graph,
686          std::ctype<charT>::lower,
687          std::ctype<charT>::print,
688          std::ctype<charT>::punct,
689          std::ctype<charT>::space,
690          std::ctype<charT>::upper,
691          std::ctype<charT>::xdigit,
692          cpp_regex_traits_implementation<charT>::mask_blank,
693          cpp_regex_traits_implementation<charT>::mask_word,
694          cpp_regex_traits_implementation<charT>::mask_unicode,
695       };
696 #else
697       static const char_class_type masks[14] = 
698       {
699          ::boost::re_detail::char_class_alnum,
700          ::boost::re_detail::char_class_alpha,
701          ::boost::re_detail::char_class_cntrl,
702          ::boost::re_detail::char_class_digit,
703          ::boost::re_detail::char_class_graph,
704          ::boost::re_detail::char_class_lower,
705          ::boost::re_detail::char_class_print,
706          ::boost::re_detail::char_class_punct,
707          ::boost::re_detail::char_class_space,
708          ::boost::re_detail::char_class_upper,
709          ::boost::re_detail::char_class_xdigit,
710          ::boost::re_detail::char_class_blank,
711          ::boost::re_detail::char_class_word,
712          ::boost::re_detail::char_class_unicode,
713       };
714 #endif
715       static const string_type null_string;
716       for(unsigned int j = 0; j <= 13; ++j)
717       {
718          string_type s(this->m_pmessages->get(cat, 0, j+300, null_string));
719          if(s.size())
720             this->m_custom_class_names[s] = masks[j];
721       }
722    }
723 #endif
724    //
725    // get the collation format used by m_pcollate:
726    //
727    m_collate_type = re_detail::find_sort_syntax(this, &m_collate_delim);
728 }
729
730 template <class charT>
731 typename cpp_regex_traits_implementation<charT>::char_class_type 
732    cpp_regex_traits_implementation<charT>::lookup_classname_imp(const charT* p1, const charT* p2) const
733 {
734 #ifndef BOOST_REGEX_BUGGY_CTYPE_FACET
735    static const char_class_type masks[20] = 
736    {
737       0,
738       std::ctype<char>::alnum, 
739       std::ctype<char>::alpha,
740       cpp_regex_traits_implementation<charT>::mask_blank,
741       std::ctype<char>::cntrl,
742       std::ctype<char>::digit,
743       std::ctype<char>::digit,
744       std::ctype<char>::graph,
745       std::ctype<char>::lower,
746       std::ctype<char>::lower,
747       std::ctype<char>::print,
748       std::ctype<char>::punct,
749       std::ctype<char>::space,
750       std::ctype<char>::space,
751       std::ctype<char>::upper,
752       cpp_regex_traits_implementation<charT>::mask_unicode,
753       std::ctype<char>::upper,
754       std::ctype<char>::alnum | cpp_regex_traits_implementation<charT>::mask_word, 
755       std::ctype<char>::alnum | cpp_regex_traits_implementation<charT>::mask_word, 
756       std::ctype<char>::xdigit,
757    };
758 #else
759    static const char_class_type masks[20] = 
760    {
761       0,
762       ::boost::re_detail::char_class_alnum, 
763       ::boost::re_detail::char_class_alpha,
764       ::boost::re_detail::char_class_blank,
765       ::boost::re_detail::char_class_cntrl,
766       ::boost::re_detail::char_class_digit,
767       ::boost::re_detail::char_class_digit,
768       ::boost::re_detail::char_class_graph,
769       ::boost::re_detail::char_class_lower,
770       ::boost::re_detail::char_class_lower,
771       ::boost::re_detail::char_class_print,
772       ::boost::re_detail::char_class_punct,
773       ::boost::re_detail::char_class_space,
774       ::boost::re_detail::char_class_space,
775       ::boost::re_detail::char_class_upper,
776       ::boost::re_detail::char_class_unicode,
777       ::boost::re_detail::char_class_upper,
778       ::boost::re_detail::char_class_alnum | ::boost::re_detail::char_class_word, 
779       ::boost::re_detail::char_class_alnum | ::boost::re_detail::char_class_word, 
780       ::boost::re_detail::char_class_xdigit,
781    };
782 #endif
783    if(m_custom_class_names.size())
784    {
785       typedef typename std::map<std::basic_string<charT>, char_class_type>::const_iterator map_iter;
786       map_iter pos = m_custom_class_names.find(string_type(p1, p2));
787       if(pos != m_custom_class_names.end())
788          return pos->second;
789    }
790    std::size_t id = 1 + re_detail::get_default_class_id(p1, p2);
791    BOOST_ASSERT(id < sizeof(masks) / sizeof(masks[0]));
792    return masks[id];
793 }
794
795 #ifdef BOOST_REGEX_BUGGY_CTYPE_FACET
796 template <class charT>
797 bool cpp_regex_traits_implementation<charT>::isctype(const charT c, char_class_type mask) const
798 {
799    return
800       ((mask & ::boost::re_detail::char_class_space) && (m_pctype->is(std::ctype<charT>::space, c)))
801       || ((mask & ::boost::re_detail::char_class_print) && (m_pctype->is(std::ctype<charT>::print, c)))
802       || ((mask & ::boost::re_detail::char_class_cntrl) && (m_pctype->is(std::ctype<charT>::cntrl, c)))
803       || ((mask & ::boost::re_detail::char_class_upper) && (m_pctype->is(std::ctype<charT>::upper, c)))
804       || ((mask & ::boost::re_detail::char_class_lower) && (m_pctype->is(std::ctype<charT>::lower, c)))
805       || ((mask & ::boost::re_detail::char_class_alpha) && (m_pctype->is(std::ctype<charT>::alpha, c)))
806       || ((mask & ::boost::re_detail::char_class_digit) && (m_pctype->is(std::ctype<charT>::digit, c)))
807       || ((mask & ::boost::re_detail::char_class_punct) && (m_pctype->is(std::ctype<charT>::punct, c)))
808       || ((mask & ::boost::re_detail::char_class_xdigit) && (m_pctype->is(std::ctype<charT>::xdigit, c)))
809       || ((mask & ::boost::re_detail::char_class_blank) && (m_pctype->is(std::ctype<charT>::space, c)) && !::boost::re_detail::is_separator(c))
810       || ((mask & ::boost::re_detail::char_class_word) && (c == '_'))
811       || ((mask & ::boost::re_detail::char_class_unicode) && ::boost::re_detail::is_extended(c));
812 }
813 #endif
814
815
816 template <class charT>
817 inline boost::shared_ptr<const cpp_regex_traits_implementation<charT> > create_cpp_regex_traits(const std::locale& l BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(charT))
818 {
819    cpp_regex_traits_base<charT> key(l);
820    return ::boost::object_cache<cpp_regex_traits_base<charT>, cpp_regex_traits_implementation<charT> >::get(key, 5);
821 }
822
823 } // re_detail
824
825 template <class charT>
826 class cpp_regex_traits
827 {
828 private:
829    typedef std::ctype<charT>            ctype_type;
830 public:
831    typedef charT                        char_type;
832    typedef std::size_t                  size_type;
833    typedef std::basic_string<char_type> string_type;
834    typedef std::locale                  locale_type;
835    typedef boost::uint_least32_t        char_class_type;
836
837    struct boost_extensions_tag{};
838
839    cpp_regex_traits()
840       : m_pimpl(re_detail::create_cpp_regex_traits<charT>(std::locale()))
841    { }
842    static size_type length(const char_type* p)
843    {
844       return std::char_traits<charT>::length(p);
845    }
846    regex_constants::syntax_type syntax_type(charT c)const
847    {
848       return m_pimpl->syntax_type(c);
849    }
850    regex_constants::escape_syntax_type escape_syntax_type(charT c) const
851    {
852       return m_pimpl->escape_syntax_type(c);
853    }
854    charT translate(charT c) const
855    {
856       return c;
857    }
858    charT translate_nocase(charT c) const
859    {
860       return m_pimpl->m_pctype->tolower(c);
861    }
862    charT translate(charT c, bool icase) const
863    {
864       return icase ? m_pimpl->m_pctype->tolower(c) : c;
865    }
866    charT tolower(charT c) const
867    {
868       return m_pimpl->m_pctype->tolower(c);
869    }
870    charT toupper(charT c) const
871    {
872       return m_pimpl->m_pctype->toupper(c);
873    }
874    string_type transform(const charT* p1, const charT* p2) const
875    {
876       return m_pimpl->transform(p1, p2);
877    }
878    string_type transform_primary(const charT* p1, const charT* p2) const
879    {
880       return m_pimpl->transform_primary(p1, p2);
881    }
882    char_class_type lookup_classname(const charT* p1, const charT* p2) const
883    {
884       return m_pimpl->lookup_classname(p1, p2);
885    }
886    string_type lookup_collatename(const charT* p1, const charT* p2) const
887    {
888       return m_pimpl->lookup_collatename(p1, p2);
889    }
890    bool isctype(charT c, char_class_type f) const
891    {
892 #ifndef BOOST_REGEX_BUGGY_CTYPE_FACET
893       typedef typename std::ctype<charT>::mask ctype_mask;
894
895       static const ctype_mask mask_base = 
896          static_cast<ctype_mask>(
897             std::ctype<charT>::alnum 
898             | std::ctype<charT>::alpha
899             | std::ctype<charT>::cntrl
900             | std::ctype<charT>::digit
901             | std::ctype<charT>::graph
902             | std::ctype<charT>::lower
903             | std::ctype<charT>::print
904             | std::ctype<charT>::punct
905             | std::ctype<charT>::space
906             | std::ctype<charT>::upper
907             | std::ctype<charT>::xdigit);
908
909       if((f & mask_base) 
910          && (m_pimpl->m_pctype->is(
911             static_cast<ctype_mask>(f & mask_base), c)))
912          return true;
913       else if((f & re_detail::cpp_regex_traits_implementation<charT>::mask_unicode) && re_detail::is_extended(c))
914          return true;
915       else if((f & re_detail::cpp_regex_traits_implementation<charT>::mask_word) && (c == '_'))
916          return true;
917       else if((f & re_detail::cpp_regex_traits_implementation<charT>::mask_blank) 
918          && m_pimpl->m_pctype->is(std::ctype<charT>::space, c)
919          && !re_detail::is_separator(c))
920          return true;
921       return false;
922 #else
923       return m_pimpl->isctype(c, f);
924 #endif
925    }
926    int toi(const charT*& p1, const charT* p2, int radix)const;
927    int value(charT c, int radix)const
928    {
929       const charT* pc = &c;
930       return toi(pc, pc + 1, radix);
931    }
932    locale_type imbue(locale_type l)
933    {
934       std::locale result(getloc());
935       m_pimpl = re_detail::create_cpp_regex_traits<charT>(l);
936       return result;
937    }
938    locale_type getloc()const
939    {
940       return m_pimpl->m_locale;
941    }
942    std::string error_string(regex_constants::error_type n) const
943    {
944       return m_pimpl->error_string(n);
945    }
946
947    //
948    // extension:
949    // set the name of the message catalog in use (defaults to "boost_regex").
950    //
951    static std::string catalog_name(const std::string& name);
952    static std::string get_catalog_name();
953
954 private:
955    boost::shared_ptr<const re_detail::cpp_regex_traits_implementation<charT> > m_pimpl;
956    //
957    // catalog name handler:
958    //
959    static std::string& get_catalog_name_inst();
960
961 #ifdef BOOST_HAS_THREADS
962    static static_mutex& get_mutex_inst();
963 #endif
964 };
965
966
967 template <class charT>
968 int cpp_regex_traits<charT>::toi(const charT*& first, const charT* last, int radix)const
969 {
970    re_detail::parser_buf<charT>   sbuf;            // buffer for parsing numbers.
971    std::basic_istream<charT>      is(&sbuf);       // stream for parsing numbers.
972
973    // we do NOT want to parse any thousands separators inside the stream:
974    last = std::find(first, last, BOOST_USE_FACET(std::numpunct<charT>, is.getloc()).thousands_sep());
975
976    sbuf.pubsetbuf(const_cast<charT*>(static_cast<const charT*>(first)), static_cast<std::streamsize>(last-first));
977    is.clear();
978    if(std::abs(radix) == 16) is >> std::hex;
979    else if(std::abs(radix) == 8) is >> std::oct;
980    else is >> std::dec;
981    int val;
982    if(is >> val)
983    {
984       first = first + ((last - first) - sbuf.in_avail());
985       return val;
986    }
987    else
988       return -1;
989 }
990
991 template <class charT>
992 std::string cpp_regex_traits<charT>::catalog_name(const std::string& name)
993 {
994 #ifdef BOOST_HAS_THREADS
995    static_mutex::scoped_lock lk(get_mutex_inst());
996 #endif
997    std::string result(get_catalog_name_inst());
998    get_catalog_name_inst() = name;
999    return result;
1000 }
1001
1002 template <class charT>
1003 std::string& cpp_regex_traits<charT>::get_catalog_name_inst()
1004 {
1005    static std::string s_name;
1006    return s_name;
1007 }
1008
1009 template <class charT>
1010 std::string cpp_regex_traits<charT>::get_catalog_name()
1011 {
1012 #ifdef BOOST_HAS_THREADS
1013    static_mutex::scoped_lock lk(get_mutex_inst());
1014 #endif
1015    std::string result(get_catalog_name_inst());
1016    return result;
1017 }
1018
1019 #ifdef BOOST_HAS_THREADS
1020 template <class charT>
1021 static_mutex& cpp_regex_traits<charT>::get_mutex_inst()
1022 {
1023    static static_mutex s_mutex = BOOST_STATIC_MUTEX_INIT;
1024    return s_mutex;
1025 }
1026 #endif
1027
1028
1029 } // boost
1030
1031 #ifdef BOOST_MSVC
1032 #pragma warning(pop)
1033 #endif
1034
1035 #ifdef BOOST_HAS_ABI_HEADERS
1036 #  include BOOST_ABI_SUFFIX
1037 #endif
1038
1039 #endif
1040
1041 #endif