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