]> git.lyx.org Git - lyx.git/blob - boost/libs/regex/src/c_regex_traits.cpp
add the boost signals librarys source files, and compile the libboostsignals.la library
[lyx.git] / boost / libs / regex / src / c_regex_traits.cpp
1 /*
2  *
3  * Copyright (c) 1998-2002
4  * Dr John Maddock
5  *
6  * Permission to use, copy, modify, distribute and sell this software
7  * and its documentation for any purpose is hereby granted without fee,
8  * provided that the above copyright notice appear in all copies and
9  * that both that copyright notice and this permission notice appear
10  * in supporting documentation.  Dr John Maddock makes no representations
11  * about the suitability of this software for any purpose.  
12  * It is provided "as is" without express or implied warranty.
13  *
14  */
15  
16  /*
17   *   LOCATION:    see http://www.boost.org for most recent version.
18   *   FILE         c_regex_traits.cpp
19   *   VERSION      see <boost/version.hpp>
20   *   DESCRIPTION: Implements the c_regex_traits<charT> traits class
21   */
22
23 #define BOOST_REGEX_SOURCE
24
25 #include <clocale>
26 #include <cstdio>
27 #include <list>
28 #include <cctype>
29 #include <cstdio>
30 #include <boost/cregex.hpp>
31 #include <boost/regex/regex_traits.hpp>
32 #include <boost/regex/detail/regex_synch.hpp>
33 #include <boost/regex/detail/regex_cstring.hpp>
34 #include <boost/scoped_array.hpp>
35
36 #include "primary_transform.hpp"
37
38
39 #if defined(BOOST_HAS_NL_TYPES_H)
40 #include <nl_types.h>
41 #endif
42
43 // Fixes a very strange bug in Comeau 4.2.45.2 that would otherwise result in
44 // an instantiation loop
45 #if defined(__COMO__) && __COMO_VERSION__ <= 4245
46 void c_regex_adopted_no_longer_needed_loop_shutter_upper() { }
47 #endif
48
49 namespace{
50
51 //
52 // character classes:
53 //
54 boost::uint_fast32_t re_char_class_id[] = {
55    boost::re_detail::c_traits_base::char_class_alnum,
56    boost::re_detail::c_traits_base::char_class_alpha,
57    boost::re_detail::c_traits_base::char_class_cntrl,
58    boost::re_detail::c_traits_base::char_class_digit,
59    boost::re_detail::c_traits_base::char_class_graph,
60    boost::re_detail::c_traits_base::char_class_lower,
61    boost::re_detail::c_traits_base::char_class_print,
62    boost::re_detail::c_traits_base::char_class_punct,
63    boost::re_detail::c_traits_base::char_class_space,
64    boost::re_detail::c_traits_base::char_class_upper,
65    boost::re_detail::c_traits_base::char_class_xdigit,
66    boost::re_detail::c_traits_base::char_class_blank,
67    boost::re_detail::c_traits_base::char_class_word,
68    boost::re_detail::c_traits_base::char_class_unicode,
69 };
70
71 const char* re_char_class_names[] = {
72 "alnum",
73 "alpha",
74 "cntrl",
75 "digit",
76 "graph",
77 "lower",
78 "print",
79 "punct",
80 "space",
81 "upper",
82 "xdigit",
83 "blank",
84 "word",
85 "unicode",
86 };
87
88 std::string* re_cls_name;
89 std::string* pclasses;
90 unsigned int classes_count = 0;
91 const unsigned int re_classes_max = 14;
92
93 //
94 // collate names:
95
96 struct collate_name_t
97 {
98    std::string name;
99    std::string value;
100    collate_name_t(const char* p1, const char* p2, const char* p3, const char* p4)
101       : name(p1, p2), value(p3, p4) {}
102 };
103
104 std::string* re_coll_name;
105 std::list<collate_name_t>* pcoll_names;
106 unsigned int collate_count = 0;
107
108 //
109 // message handling:
110 #ifndef BOOST_RE_MESSAGE_BASE
111 #define BOOST_RE_MESSAGE_BASE 0
112 #endif
113
114 #if defined(BOOST_HAS_NL_TYPES_H)
115 nl_catd message_cat = (nl_catd)-1;
116 #endif
117
118 unsigned int message_count = 0;
119 std::string* mess_locale;
120
121 BOOST_REGEX_DECL char* re_custom_error_messages[] = {
122    0,
123    0,
124    0,
125    0,
126    0,
127    0,
128    0,
129    0,
130    0,
131    0,
132    0,
133    0,
134    0,
135    0,
136    0,
137    0,
138    0,
139    0,
140    0,
141    0,
142    0,
143    0,
144    0,
145 };
146
147 #if !defined(LC_MESSAGES)
148 #define LC_MESSAGES LC_CTYPE
149 #endif
150
151 char re_zero;
152 char re_ten;
153
154 unsigned int entry_count = 0;
155
156 std::string* ctype_name;
157 std::string* collate_name;
158 enum syntax_map_size
159 {
160    map_size = UCHAR_MAX + 1
161 };
162
163 #ifndef BOOST_NO_WREGEX
164
165 BOOST_REGEX_DECL wchar_t re_zero_w;
166 BOOST_REGEX_DECL wchar_t re_ten_w;
167
168 unsigned int nlsw_count = 0;
169 std::string* wlocale_name = 0;
170
171 struct syntax_map_t
172 {
173    wchar_t c;
174    unsigned int type;
175 };
176
177 std::list<syntax_map_t>* syntax;
178
179 #endif
180
181
182 std::size_t BOOST_REGEX_CALL _re_get_message(char* buf, std::size_t len, std::size_t id);
183
184 template <class charT>
185 std::size_t BOOST_REGEX_CALL re_get_message(charT* buf, std::size_t len, std::size_t id)
186 {
187    std::size_t size = _re_get_message(static_cast<char*>(0), 0, id);
188    if(len < size)
189       return size;
190    boost::scoped_array<char> cb(new char[size]);
191    _re_get_message(cb.get(), size, id);
192    size = boost::c_regex_traits<wchar_t>::strwiden(buf, len, cb.get());
193    return size;
194 }
195
196 inline std::size_t BOOST_REGEX_CALL re_get_message(char* buf, std::size_t len, std::size_t id)
197 {
198    return _re_get_message(buf, len, id);
199 }
200
201 void BOOST_REGEX_CALL re_init_classes()
202 {
203    BOOST_RE_GUARD_STACK
204    if(classes_count == 0)
205    {
206       re_cls_name = new std::string("xxxxxxxx");
207 #ifndef BOOST_NO_EXCEPTIONS
208       try{
209 #endif
210          pclasses = new std::string[re_classes_max];
211          BOOST_REGEX_NOEH_ASSERT(pclasses)
212 #ifndef BOOST_NO_EXCEPTIONS
213       }
214       catch(...)
215       {
216          delete re_cls_name;
217          throw;
218       }
219 #endif
220    }
221    ++classes_count;
222 }
223
224 void BOOST_REGEX_CALL re_free_classes()
225 {
226    BOOST_RE_GUARD_STACK
227    if(--classes_count == 0)
228    {
229       delete re_cls_name;
230       delete[] pclasses;
231    }
232 }
233
234 void BOOST_REGEX_CALL re_update_classes()
235 {
236    BOOST_RE_GUARD_STACK
237    if(*re_cls_name != std::setlocale(LC_CTYPE, 0))
238    {
239       *re_cls_name = std::setlocale(LC_CTYPE, 0);
240       char buf[256];
241       unsigned int i;
242       for(i = 0; i < re_classes_max; ++i)
243       {
244          re_get_message(buf, 256, i+300);
245          pclasses[i] = buf;
246       }
247    }
248 }
249
250 void BOOST_REGEX_CALL re_init_collate()
251 {
252    BOOST_RE_GUARD_STACK
253    if(collate_count == 0)
254    {
255       re_coll_name = new std::string("xxxxxxxx");
256 #ifndef BOOST_NO_EXCEPTIONS
257       try{
258 #endif
259          pcoll_names = new std::list<collate_name_t>();
260          BOOST_REGEX_NOEH_ASSERT(pcoll_names)
261 #ifndef BOOST_NO_EXCEPTIONS
262       }
263       catch(...)
264       {
265          delete re_coll_name;
266          throw;
267       }
268 #endif
269    }
270    ++collate_count;
271 }
272
273 void BOOST_REGEX_CALL re_free_collate()
274 {
275    BOOST_RE_GUARD_STACK
276    if(--collate_count == 0)
277    {
278       delete re_coll_name;
279       delete pcoll_names;
280    }
281 }
282
283 void BOOST_REGEX_CALL re_update_collate()
284 {
285    BOOST_RE_GUARD_STACK
286    if(*re_coll_name != std::setlocale(LC_COLLATE, 0))
287    {
288       *re_coll_name = std::setlocale(LC_COLLATE, 0);
289       char buf[256];
290       unsigned int i = 400;
291       re_get_message(buf, 256, i);
292       while(*buf)
293       {
294          char* p1, *p2, *p3, *p4;;
295          p1 = buf;
296          while(*p1 && std::isspace((unsigned char)*p1))++p1;
297          p2 = p1;
298          while(*p2 && !std::isspace((unsigned char)*p2))++p2;
299          p3 = p2;
300          while(*p3 && std::isspace((unsigned char)*p3))++p3;
301          p4 = p3;
302          while(*p4 && !std::isspace((unsigned char)*p4))++p4;
303          pcoll_names->push_back(collate_name_t(p1, p2, p3, p4));
304          ++i;
305          re_get_message(buf, 256, i);
306       }
307    }
308 }
309
310 std::size_t BOOST_REGEX_CALL _re_get_message(char* buf, std::size_t len, std::size_t id)
311 {
312    BOOST_RE_GUARD_STACK
313    // get the customised message if any:
314    #if defined(BOOST_HAS_NL_TYPES_H)
315    if(message_cat != (nl_catd)-1)
316    {
317       const char* m = catgets(message_cat, 0, id, 0);
318       if(m)
319       {
320          std::size_t size = std::strlen(m) + 1;
321          if(size > len)
322             return size;
323          std::strcpy(buf, m);
324          return size;
325       }
326    }
327    #endif
328
329    //
330    // now get the default message if any:
331    return boost::re_detail::re_get_default_message(buf, len, id);
332 }
333
334 void BOOST_REGEX_CALL re_message_init()
335 {
336    BOOST_RE_GUARD_STACK
337    if(message_count == 0)
338    {
339       mess_locale = new std::string("xxxxxxxxxxxxxxxx");
340    }
341    ++message_count;
342 }
343
344 void BOOST_REGEX_CALL re_message_update()
345 {
346    BOOST_RE_GUARD_STACK
347    //
348    // called whenever the global locale changes:
349    //
350    std::string l(std::setlocale(LC_MESSAGES, 0));
351    if(*mess_locale != l)
352    {
353       *mess_locale = l;
354 #if defined(BOOST_HAS_NL_TYPES_H)
355       if(message_cat != (nl_catd)-1)
356       {
357          catclose(message_cat);
358          message_cat = (nl_catd)-1;
359       }
360       if(*boost::re_detail::c_traits_base::get_catalogue())
361       {
362          message_cat = catopen(boost::re_detail::c_traits_base::get_catalogue(), 0);
363 #ifndef BOOST_NO_EXCEPTIONS
364          if(message_cat == (nl_catd)-1)
365          {
366             std::string m("Unable to open message catalog: ");
367             throw std::runtime_error(m + boost::re_detail::c_traits_base::get_catalogue());
368          }
369 #else
370          BOOST_REGEX_NOEH_ASSERT(message_cat != (nl_catd)-1);
371 #endif
372       }
373 #endif
374       for(int i = 0; i < boost::REG_E_UNKNOWN; ++i)
375       {
376          if(re_custom_error_messages[i])
377          {
378             boost::re_detail::re_strfree(re_custom_error_messages[i]);
379             re_custom_error_messages[i] = 0;
380          }
381       }
382    }
383 }
384
385 void BOOST_REGEX_CALL re_message_free()
386 {
387    BOOST_RE_GUARD_STACK
388    --message_count;
389    if(message_count == 0)
390    {
391 #if defined(BOOST_HAS_NL_TYPES_H)
392       if(message_cat != (nl_catd)-1)
393          catclose(message_cat);
394 #endif
395       delete mess_locale;
396       for(int i = 0; i < boost::REG_E_UNKNOWN; ++i)
397       {
398          if(re_custom_error_messages[i])
399          {
400             boost::re_detail::re_strfree(re_custom_error_messages[i]);
401             re_custom_error_messages[i] = 0;
402          }
403       }
404    }
405 }
406
407
408 const char* BOOST_REGEX_CALL re_get_error_str(unsigned int id)
409 {
410    BOOST_RE_GUARD_STACK
411 #ifdef BOOST_HAS_THREADS
412    boost::re_detail::cs_guard g(*boost::re_detail::p_re_lock);
413 #endif
414    if(re_custom_error_messages[id] == 0)
415    {
416       char buf[256];
417       _re_get_message(buf, 256, id + 200);
418       if(*buf)
419       {
420          re_custom_error_messages[id] = boost::re_detail::re_strdup(buf);
421          return re_custom_error_messages[id];
422       }
423       return boost::re_detail::re_default_error_messages[id];
424    }
425    return re_custom_error_messages[id];
426 }
427
428 } // namespace
429
430 namespace boost{
431 namespace re_detail{
432
433 char c_traits_base::regex_message_catalogue[BOOST_REGEX_MAX_PATH] = {0};
434
435 std::string BOOST_REGEX_CALL c_traits_base::error_string(unsigned id)
436 {
437    return re_get_error_str(id);
438 }
439
440 void BOOST_REGEX_CALL c_traits_base::do_update_collate()
441 {
442    BOOST_RE_GUARD_STACK
443    re_update_collate();
444    std::string s;
445    const char* p = "zero";
446    if(c_regex_traits<char>::lookup_collatename(s, p, p+4))
447    {
448       jm_assert(s.size() == 1);
449       re_zero = *s.c_str();
450    }
451    else
452       re_zero = '0';
453
454    p = "ten";
455    if(c_regex_traits<char>::lookup_collatename(s, p, p+3))
456    {
457       jm_assert(s.size() == 1);
458       re_ten = *s.c_str();
459    }
460    else
461       re_ten = 'a';
462 }
463
464 void BOOST_REGEX_CALL c_traits_base::do_update_ctype()
465 {
466    BOOST_RE_GUARD_STACK
467    // start by updating the syntax map:
468    unsigned int i;
469    char buf[map_size+2];
470    std::memset(syntax_map, syntax_char, map_size);
471    for(i = 1; i < syntax_max; ++i)
472    {
473       char* ptr = buf;
474       re_get_message(static_cast<char*>(buf), map_size, i+100);
475       for(; *ptr; ++ptr)
476       {
477          syntax_map[(unsigned char)*ptr] = (unsigned char)i;
478       }
479    }
480
481    // now update the character class map,
482    // and lower case map:
483    std::memset(class_map, 0, map_size);
484    for(i = 0; i < map_size; ++i)
485    {
486       if(std::isalpha(i))
487          class_map[i] |= char_class_alpha;
488       if(std::iscntrl(i))
489          class_map[i] |= char_class_cntrl;
490       if(std::isdigit(i))
491          class_map[i] |= char_class_digit;
492       if(std::islower(i))
493          class_map[i] |= char_class_lower;
494       if(std::isupper(i))
495          class_map[i] |= char_class_upper;
496       if(std::ispunct(i))
497          class_map[i] |= char_class_punct;
498       if(std::isspace(i))
499          class_map[i] |= char_class_space;
500       if(std::isxdigit(i))
501          class_map[i] |= char_class_xdigit;
502    }
503    class_map['_'] |= char_class_underscore;
504    class_map[' '] |= char_class_blank;
505    class_map['\t'] |= char_class_blank;
506    for(i = 0; i < map_size; ++i)
507    {
508       lower_case_map[i] = (char)std::tolower(i);
509    }
510    re_update_classes();
511 }
512
513 boost::uint_fast32_t BOOST_REGEX_CALL c_traits_base::do_lookup_class(const char* p)
514 {
515    BOOST_RE_GUARD_STACK
516    unsigned int i;
517    for(i = 0; i < re_classes_max; ++i)
518    {
519       if(pclasses[i] == p)
520       {
521          return re_char_class_id[i];
522       }
523    }
524    for(i = 0; i < re_classes_max; ++i)
525    {
526       if(std::strcmp(re_char_class_names[i], p) == 0)
527       {
528          return re_char_class_id[i];
529       }
530    }
531    return 0;
532 }
533
534 bool BOOST_REGEX_CALL c_traits_base::do_lookup_collate(std::string& buf, const char* p)
535 {
536    BOOST_RE_GUARD_STACK
537    std::list<collate_name_t>::iterator first, last;
538    first = pcoll_names->begin();
539    last = pcoll_names->end();
540    while(first != last)
541    {
542       if((*first).name == p)
543       {
544          buf = (*first).value;
545          return true;
546       }
547       ++first;
548    }
549
550    bool result = re_detail::re_lookup_def_collate_name(buf, p);
551    if((result == 0) && (std::strlen(p) == 1))
552    {
553       result = true;
554       buf = *p;
555    }
556    return result;
557 }
558
559 std::string BOOST_REGEX_CALL c_traits_base::set_message_catalogue(const std::string& l)
560 {
561    if(sizeof(regex_message_catalogue) <= l.size())
562       return l;
563    std::string old(regex_message_catalogue);
564    std::strcpy(regex_message_catalogue, l.c_str());
565    return old;
566 }
567
568 unsigned char c_traits_base::syntax_map[map_size];
569 unsigned short c_traits_base::class_map[map_size];
570 char c_traits_base::lower_case_map[map_size];
571
572 } // namespace re_detail
573
574 #ifndef BOOST_NO_WREGEX
575 bool BOOST_REGEX_CALL c_regex_traits<wchar_t>::lookup_collatename(std::basic_string<wchar_t>& out, const wchar_t* first, const wchar_t* last)
576 {
577    BOOST_RE_GUARD_STACK
578    std::basic_string<wchar_t> s(first, last);
579    std::size_t len = strnarrow(static_cast<char*>(0), 0, s.c_str());
580    scoped_array<char> buf(new char[len]);
581    strnarrow(buf.get(), len, s.c_str());
582    std::string t_out;
583    bool result = base_type::do_lookup_collate(t_out, buf.get());
584    if(t_out.size() == 0) result = false;
585    if(result)
586    {
587       if(t_out[0])
588       {
589          len = strwiden(static_cast<wchar_t*>(0), 0, t_out.c_str());
590          scoped_array<wchar_t> wb(new wchar_t[len]);
591          strwiden(wb.get(), len, t_out.c_str());
592          out = wb.get();
593       }
594       else
595          out.append(1, (wchar_t)0);
596    }
597    return result;
598 }
599 #endif
600
601 c_regex_traits<char> c_regex_traits<char>::i;
602
603 void BOOST_REGEX_CALL c_regex_traits<char>::init()
604 {
605    BOOST_RE_GUARD_STACK
606 #ifdef BOOST_HAS_THREADS
607    re_detail::re_init_threads();
608    re_detail::cs_guard g(*re_detail::p_re_lock);
609 #endif
610    // just keep track of entry_count
611    if(entry_count == 0)
612    {
613       ctype_name = new std::string("xxxxxxxxxxxxxxxx");
614 #ifndef BOOST_NO_EXCEPTIONS
615       try{
616 #endif
617          collate_name = new std::string("xxxxxxxxxxxxxxxx");
618          BOOST_REGEX_NOEH_ASSERT(collate_name)
619 #ifndef BOOST_NO_EXCEPTIONS
620       }
621       catch(...)
622       {
623          delete ctype_name;
624          throw;
625       }
626 #endif
627    }
628    re_message_init();
629    re_init_classes();
630    re_init_collate();
631    ++entry_count;
632 }
633
634 void BOOST_REGEX_CALL c_regex_traits<char>::update()
635 {
636    BOOST_RE_GUARD_STACK
637    #ifdef BOOST_HAS_THREADS
638    re_detail::cs_guard g(*re_detail::p_re_lock);
639    #endif
640    re_message_update();
641    if(*collate_name != std::setlocale(LC_COLLATE, 0))
642    {
643       do_update_collate();
644       *collate_name = std::setlocale(LC_COLLATE, 0);
645    }
646    if(*ctype_name != std::setlocale(LC_CTYPE, 0))
647    {
648       do_update_ctype();
649       *ctype_name = std::setlocale(LC_CTYPE, 0);
650    }
651    sort_type = re_detail::find_sort_syntax(&i, &sort_delim);
652 }
653
654 void BOOST_REGEX_CALL c_regex_traits<char>::m_free()
655 {
656    BOOST_RE_GUARD_STACK
657    #ifdef BOOST_HAS_THREADS
658    re_detail::cs_guard g(*re_detail::p_re_lock);
659    #endif
660    re_message_free();
661    re_free_classes();
662    re_free_collate();
663    --entry_count;
664    if(entry_count == 0)
665    {
666       delete ctype_name;
667       delete collate_name;
668    }
669 #ifdef BOOST_HAS_THREADS
670    g.acquire(false);
671    re_detail::re_free_threads();
672 #endif
673 }
674
675 void BOOST_REGEX_CALL c_regex_traits<char>::transform(std::string& out, const std::string& in)
676 {
677    BOOST_RE_GUARD_STACK
678    std::size_t n = std::strxfrm(0, in.c_str(), 0);
679    if(n == (std::size_t)(-1))
680    {
681       out = in;
682       return;
683    }
684    scoped_array<char> buf(new char[n+1]);
685    n = std::strxfrm(buf.get(), in.c_str(), n+1);
686    if(n == (std::size_t)(-1))
687    {
688       out = in;
689       return;
690    }
691    out = buf.get();
692 }
693
694 void BOOST_REGEX_CALL c_regex_traits<char>::transform_primary(std::string& out, const std::string& in)
695 {
696    transform(out, in);
697    switch(sort_type)
698    {
699    case re_detail::sort_C:
700    case re_detail::sort_unknown:
701       break;
702    case re_detail::sort_fixed:
703       out.erase((int)sort_delim);
704       break;
705    case re_detail::sort_delim:
706       for(unsigned int i = 0; i < out.size(); ++i)
707       {
708          if((out[i] == sort_delim) && (i+1 < out.size()))
709          {
710             out.erase(i+1);
711             break;
712          }
713       }
714    }
715 }
716
717 unsigned c_regex_traits<char>::sort_type;
718 char c_regex_traits<char>::sort_delim;
719
720
721 int BOOST_REGEX_CALL c_regex_traits<char>::toi(char c)
722 {
723    if(is_class(c, char_class_digit))
724       return c - re_zero;
725    if(is_class(c, char_class_xdigit))
726       return 10 + translate(c, true) - translate(re_ten, true);
727    return -1; // error!!
728 }
729
730 int BOOST_REGEX_CALL c_regex_traits<char>::toi(const char*& first, const char* last, int radix)
731 {
732    unsigned int maxval;
733    if(radix < 0)
734    {
735       // if radix is less than zero, then restrict
736       // return value to charT. NB assumes sizeof(charT) <= sizeof(int)
737       radix *= -1;
738       maxval = 1u << (sizeof(*first) * CHAR_BIT - 1);
739       maxval /= radix;
740       maxval *= 2;
741       maxval -= 1;
742    }
743    else
744    {
745       maxval = (unsigned int)-1;
746       maxval /= radix;
747    }
748
749    unsigned int result = 0;
750    unsigned int type = (radix > 10) ? char_class_xdigit : char_class_digit;
751    while((first != last) && is_class(*first, type) && (result <= maxval))
752    {
753       result *= radix;
754       result += toi(*first);
755       ++first;
756    }
757    return result;
758 }
759
760 #ifndef BOOST_NO_WREGEX
761
762 unsigned int BOOST_REGEX_CALL c_regex_traits<wchar_t>::syntax_type(size_type c)
763 {
764    BOOST_RE_GUARD_STACK
765    std::list<syntax_map_t>::const_iterator first, last;
766    first = syntax->begin();
767    last = syntax->end();
768    while(first != last)
769    {
770       if((uchar_type)(*first).c == c)
771          return (*first).type;
772       ++first;
773    }
774    return 0;
775 }
776
777 void BOOST_REGEX_CALL c_regex_traits<wchar_t>::init()
778 {
779    BOOST_RE_GUARD_STACK
780    re_detail::re_init_threads();
781 #ifdef BOOST_HAS_THREADS
782    re_detail::cs_guard g(*re_detail::p_re_lock);
783 #endif
784    re_message_init();
785    re_init_classes();
786    re_init_collate();
787    if(nlsw_count == 0)
788    {
789       wlocale_name = new std::string("xxxxxxxxxxxxxxxx");
790 #ifndef BOOST_NO_EXCEPTIONS
791       try{
792 #endif
793          syntax = new std::list<syntax_map_t>();
794          BOOST_REGEX_NOEH_ASSERT(syntax)
795 #ifndef BOOST_NO_EXCEPTIONS
796       }
797       catch(...)
798       {
799          delete wlocale_name;
800          throw;
801       }
802 #endif
803    }
804    ++nlsw_count;
805 }
806
807 bool BOOST_REGEX_CALL c_regex_traits<wchar_t>::do_lookup_collate(std::basic_string<wchar_t>& out, const wchar_t* first, const wchar_t* last)
808 {
809    BOOST_RE_GUARD_STACK
810    std::basic_string<wchar_t> s(first, last);
811    std::size_t len = strnarrow(static_cast<char*>(0), 0, s.c_str());
812    scoped_array<char> buf(new char[len]);
813    strnarrow(buf.get(), len, s.c_str());
814    std::string t_out;
815    bool result = base_type::do_lookup_collate(t_out, buf.get());
816    if(result)
817    {
818       len = strwiden(static_cast<wchar_t*>(0), 0, t_out.c_str());
819       scoped_array<wchar_t> wb(new wchar_t[len]);
820       strwiden(wb.get(), len, t_out.c_str());
821       out = wb.get();
822    }
823    return result;
824 }
825
826
827 void BOOST_REGEX_CALL c_regex_traits<wchar_t>::update()
828 {
829    BOOST_RE_GUARD_STACK
830 #ifdef BOOST_HAS_THREADS
831    re_detail::cs_guard g(*re_detail::p_re_lock);
832 #endif
833    re_message_update();
834    re_update_classes();
835    re_update_collate();
836    std::string l(std::setlocale(LC_CTYPE, 0));
837    if(*wlocale_name != l)
838    {
839       *wlocale_name = l;
840       std::basic_string<wchar_t> s;
841       const wchar_t* p = L"zero";
842       if(do_lookup_collate(s, p, p+4))
843       {
844          jm_assert(s.size() == 1);
845          re_zero_w = *s.c_str();
846       }
847       else
848          re_zero_w = L'0';
849
850       p = L"ten";
851       if(do_lookup_collate(s, p, p+3))
852       {
853          jm_assert(s.size() == 1);
854          re_ten_w = *s.c_str();
855       }
856       else
857          re_ten_w = L'a';
858
859       unsigned int i;
860       wchar_t buf[256];
861       syntax_map_t sm;
862       syntax->clear();
863       for(i = 1; i < syntax_max; ++i)
864       {
865          wchar_t* ptr = buf;
866          re_get_message(static_cast<wchar_t*>(buf), 256, i+100);
867          for(; *ptr; ++ptr)
868          {
869             sm.c = *ptr;
870             sm.type = i;
871             syntax->push_back(sm);
872          }
873       }
874       sort_type = re_detail::find_sort_syntax(&init_, &sort_delim);
875    }
876 }
877
878 void BOOST_REGEX_CALL c_regex_traits<wchar_t>::m_free()
879 {
880    BOOST_RE_GUARD_STACK
881 #ifdef BOOST_HAS_THREADS
882    re_detail::cs_guard g(*re_detail::p_re_lock);
883 #endif
884    --nlsw_count;
885    re_message_free();
886    re_free_classes();
887    re_free_collate();
888    if(nlsw_count == 0)
889    {
890       // cleanup:
891       delete wlocale_name;
892       delete syntax;
893    }
894 #ifdef BOOST_HAS_THREADS
895    g.acquire(false);
896    re_detail::re_free_threads();
897 #endif
898 }
899
900 bool BOOST_REGEX_CALL c_regex_traits<wchar_t>::do_iswclass(wchar_t c, boost::uint_fast32_t f)
901 {
902    BOOST_RE_GUARD_STACK
903    if((c & ~0xFF) == 0)
904       return BOOST_REGEX_MAKE_BOOL(re_detail::wide_unicode_classes[(uchar_type)c] & f);
905    if((f & char_class_alpha) && std::iswalpha(c))
906       return true;
907    if((f & char_class_cntrl) && std::iswcntrl(c))
908       return true;
909    if((f & char_class_digit) && std::iswdigit(c))
910       return true;
911    if((f & char_class_lower) && std::iswlower(c))
912       return true;
913    if((f & char_class_punct) && std::iswpunct(c))
914       return true;
915    if((f & char_class_space) && std::iswspace(c))
916       return true;
917    if((f & char_class_upper) && std::iswupper(c))
918       return true;
919    if((f & char_class_xdigit) && std::iswxdigit(c))
920       return true;
921    if(f & char_class_unicode)
922       return true;
923    return false;
924 }
925
926 void BOOST_REGEX_CALL c_regex_traits<wchar_t>::transform(std::basic_string<wchar_t>& out, const std::basic_string<wchar_t>& in)
927 {
928    BOOST_RE_GUARD_STACK
929 #ifndef BOOST_MSVC
930    std::size_t n = std::wcsxfrm(0, in.c_str(), 0);
931 #else
932    // broken wcsxfrm under VC6 doesn't check size of
933    // output buffer, we have no choice but to guess!
934    std::size_t n = 100 * in.size();
935 #endif
936    if((n == (std::size_t)(-1)) || (n == 0))
937    {
938       out = in;
939       return;
940    }
941    scoped_array<wchar_t> buf(new wchar_t[n+1]);
942    n = std::wcsxfrm(buf.get(), in.c_str(), n+1);
943    if(n == (std::size_t)(-1))
944    {
945       out = in;
946       return;
947    }
948    out = buf.get();
949 }
950
951 void BOOST_REGEX_CALL c_regex_traits<wchar_t>::transform_primary(std::basic_string<wchar_t>& out, const std::basic_string<wchar_t>& in)
952 {
953    transform(out, in);
954    switch(sort_type)
955    {
956    case re_detail::sort_C:
957    case re_detail::sort_unknown:
958       break;
959    case re_detail::sort_fixed:
960       if((unsigned)sort_delim < out.size())
961          out.erase((int)sort_delim);
962       break;
963    case re_detail::sort_delim:
964       for(unsigned int i = 0; i < out.size(); ++i)
965       {
966          if((out[i] == sort_delim) && (i+1 < out.size()))
967          {
968             out.erase(i+1);
969             break;
970          }
971       }
972    }
973 }
974
975 unsigned c_regex_traits<wchar_t>::sort_type;
976 wchar_t c_regex_traits<wchar_t>::sort_delim;
977
978
979 int BOOST_REGEX_CALL c_regex_traits<wchar_t>::toi(wchar_t c)
980 {
981    if(is_class(c, char_class_digit))
982       return c - re_zero_w;
983    if(is_class(c, char_class_xdigit))
984       return 10 + translate(c, true) - translate(re_ten_w, true);
985    return -1; // error!!
986 }
987
988 int BOOST_REGEX_CALL c_regex_traits<wchar_t>::toi(const wchar_t*& first, const wchar_t* last, int radix)
989 {
990    unsigned int maxval;
991    if(radix < 0)
992    {
993       // if radix is less than zero, then restrict
994       // return value to charT. NB assumes sizeof(charT) <= sizeof(int)
995       radix *= -1;
996       maxval = 1u << (sizeof(*first) * CHAR_BIT - 1);
997       maxval /= radix;
998       maxval *= 2;
999       maxval -= 1;
1000    }
1001    else
1002    {
1003       maxval = (unsigned int)-1;
1004       maxval /= radix;
1005    }
1006
1007    unsigned int result = 0;
1008    unsigned int type = (radix > 10) ? char_class_xdigit : char_class_digit;
1009    while((first != last) && is_class(*first, type) && (result <= maxval))
1010    {
1011       result *= radix;
1012       result += toi(*first);
1013       ++first;
1014    }
1015    return result;
1016 }
1017
1018 boost::uint_fast32_t BOOST_REGEX_CALL c_regex_traits<wchar_t>::lookup_classname(const wchar_t* first, const wchar_t* last)
1019 {
1020    std::basic_string<wchar_t> s(first, last);
1021    std::size_t len = strnarrow(static_cast<char*>(0), 0, s.c_str());
1022    scoped_array<char> buf(new char[len]);
1023    strnarrow(buf.get(), len, s.c_str());
1024    boost::uint_fast32_t result =  do_lookup_class(buf.get());
1025    return result;
1026 }
1027
1028 c_regex_traits<wchar_t> c_regex_traits<wchar_t>::init_;
1029
1030 std::size_t BOOST_REGEX_CALL c_regex_traits<wchar_t>::strnarrow(char *s1, std::size_t len, const wchar_t *s2)
1031 {
1032    BOOST_RE_GUARD_STACK
1033    std::size_t size = std::wcslen(s2) + 1;
1034    if(size > len)
1035       return size;
1036    return std::wcstombs(s1, s2, len);
1037 }
1038
1039 std::size_t BOOST_REGEX_CALL c_regex_traits<wchar_t>::strwiden(wchar_t *s1, std::size_t len, const char *s2)
1040 {
1041    BOOST_RE_GUARD_STACK
1042    std::size_t size = std::strlen(s2) + 1;
1043    if(size > len)
1044       return size;
1045    size = std::mbstowcs(s1, s2, len);
1046    s1[size] = 0;
1047    return size + 1;
1048 }
1049
1050 #endif // BOOST_NO_WREGEX
1051
1052 } // namespace boost
1053
1054