OSDN Git Service

2000-08-30 Benjamin Kosnik <bkoz@redhat.com>
[pf3gnuchains/gcc-fork.git] / libstdc++-v3 / src / locale.cc
1 // Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
2 //
3 // This file is part of the GNU ISO C++ Library.  This library is free
4 // software; you can redistribute it and/or modify it under the
5 // terms of the GNU General Public License as published by the
6 // Free Software Foundation; either version 2, or (at your option)
7 // any later version.
8
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13
14 // You should have received a copy of the GNU General Public License along
15 // with this library; see the file COPYING.  If not, write to the Free
16 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 // USA.
18
19 // As a special exception, you may use this file as part of a free software
20 // library without restriction.  Specifically, if other files instantiate
21 // templates or use macros or inline functions from this file, or you compile
22 // this file and link it with other files to produce an executable, this
23 // file does not by itself cause the resulting executable to be covered by
24 // the GNU General Public License.  This exception does not however
25 // invalidate any other reasons why the executable file might be covered by
26 // the GNU General Public License.
27
28 #include <bits/std_clocale.h>
29 #include <bits/std_cstring.h>
30 #include <bits/std_cassert.h>
31 #include <bits/std_cctype.h>
32 #include <bits/std_limits.h>
33 #include <bits/std_exception.h>
34 #include <bits/std_stdexcept.h>
35 #include <bits/std_locale.h>
36 #include <bits/std_istream.h>
37 #include <bits/std_ostream.h>
38 #include <bits/std_vector.h>
39 #include <bits/std_memory.h>      // for auto_ptr
40 #ifdef _GLIBCPP_USE_WCHAR_T  
41   #include <bits/std_cwctype.h>     // for towupper, etc.
42 #endif
43 namespace std {
44
45   // locale::_Impl
46   locale::_Impl::
47   ~_Impl() throw()
48   {
49     std::vector<facet*>::iterator it = _M_facets->begin();
50     for (; it != _M_facets->end(); ++it)
51       (*it)->_M_remove_reference();
52     delete _M_facets;
53     delete _M_category_names;
54   }
55
56   locale::_Impl::
57   _Impl(size_t __numfacets, size_t __refs)
58   : _M_num_references(__refs - 1)
59   , _M_facets(0)
60   , _M_category_names(0)
61   , _M_has_name(false)
62   , _M_cached_name_ok(false)
63   , _M_cached_name(string ("*"))
64   { 
65     typedef vector<facet*, allocator<facet*> > __vec_facet;
66     typedef vector<string, allocator<string> > __vec_string;
67
68     auto_ptr<__vec_facet> __pvf(new __vec_facet(__numfacets, (facet*)0));
69     auto_ptr<__vec_string> __pcn(new __vec_string(_S_num_categories,
70                                                   string("*")));
71     _M_facets = __pvf.release();
72     _M_category_names = __pcn.release();
73   }
74   
75   locale::_Impl::
76   _Impl(const _Impl& __other, size_t __refs)
77   : _M_num_references(__refs)
78   , _M_facets(0)
79   , _M_category_names(0)
80   , _M_has_name(__other._M_has_name)
81   , _M_cached_name_ok(__other._M_cached_name_ok)
82   , _M_cached_name(__other._M_cached_name)
83   {
84     typedef vector<facet*, allocator<facet*> > __vec_facet;
85     typedef vector<string, allocator<string> > __vec_string;
86
87     auto_ptr<__vec_facet> __pvf(new __vec_facet(*(__other._M_facets)));
88     auto_ptr<__vec_string> 
89       __pcn(new __vec_string(*(__other._M_category_names)));
90
91     std::vector<facet*>::iterator __it = __pvf->begin();
92     for (; __it != __pvf->end(); ++__it)
93       (*__it)->_M_add_reference();
94
95     // these must be last since in the presence of an exception, the 
96     // destructor for 'this' won't run until AFTER execution has passed  
97     // the closing brace of the constructor
98     _M_facets = __pvf.release();
99     _M_category_names = __pcn.release();
100   }
101   
102   void
103   locale::_Impl::
104   _M_replace_categories(const _Impl* __other, category __cats)
105   {
106     assert((__cats & locale::all) && !(__cats & ~locale::all));
107     
108     unsigned mask = (locale::all & -(unsigned)locale::all);
109     for (unsigned ix = 0; (-mask & __cats) != 0; ++ix, (mask <<= 1))
110       {
111         if (mask & __cats)
112           {
113             _M_replace_category(__other, _S_facet_categories[ix]);
114             (*_M_category_names)[ix] = (*(__other->_M_category_names))[ix];
115           }
116       }
117   }
118
119   void
120   locale::_Impl::
121   _M_replace_category(const _Impl* __other, const locale::id* const* __idpp)
122   {
123     for (; *__idpp; ++__idpp)
124       _M_replace_facet(__other, *__idpp);
125   }
126   
127   void
128   locale::_Impl::
129   _M_replace_facet(const _Impl* __other, const locale::id* __idp)
130   {
131     size_t __index = __idp->_M_index;
132     if (__index == 0 
133         || __other->_M_facets->size() <= __index 
134         || (*(__other->_M_facets))[__index] == 0)
135       throw runtime_error("no locale facet");
136         
137     _M_install_facet(__idp, (*(__other->_M_facets))[__index]); 
138   }
139
140   void
141   locale::_Impl::
142   _M_install_facet(const locale::id* __idp, facet* __fp)
143   {
144     if (__fp == 0)
145       return;
146
147     size_t& __index = __idp->_M_index;
148     if (!__index)
149       __index = ++locale::id::_S_highwater;  // XXX MT
150
151     if (__index >= _M_facets->size())
152       _M_facets->resize(__index + 1, 0);  // might throw
153     facet*& __fpr = (*_M_facets)[__index];
154     // order matters, here:
155     __fp->_M_add_reference();
156     if (__fpr) 
157       __fpr->_M_remove_reference();
158     __fpr = __fp;
159   }
160
161   // locale facet category descriptions
162   const locale::id* const
163   locale::_Impl::_S_id_collate[] =
164   {
165     &std::collate<char>::id,
166 #ifdef _GLIBCPP_USE_WCHAR_T
167     &std::collate<wchar_t>::id,
168 #endif
169     0
170   };
171   
172   const locale::id* const
173   locale::_Impl::_S_id_ctype[] =
174   {
175     &std::ctype<char>::id, 
176 #ifdef _GLIBCPP_USE_WCHAR_T
177     &std::ctype<wchar_t>::id,
178 #endif
179     &std::codecvt<char, char, mbstate_t>::id,
180 #ifdef _GLIBCPP_USE_WCHAR_T
181     &std::codecvt<wchar_t, char, mbstate_t>::id,
182 #endif
183     0
184   };
185
186   const locale::id* const
187   locale::_Impl::_S_id_monetary[] =
188   {
189     &std::moneypunct<char, false>::id, 
190 #ifdef _GLIBCPP_USE_WCHAR_T
191     &std::moneypunct<wchar_t, false>::id,
192 #endif
193     &std::moneypunct<char,true >::id, 
194 #ifdef _GLIBCPP_USE_WCHAR_T
195     &std::moneypunct<wchar_t,true >::id,
196 #endif
197     &std::money_get<char>::id,        
198 #ifdef _GLIBCPP_USE_WCHAR_T
199     &std::money_get<wchar_t>::id,
200 #endif
201     &std::money_put<char>::id,        
202 #ifdef _GLIBCPP_USE_WCHAR_T
203     &std::money_put<wchar_t>::id,
204 #endif
205     0
206   };
207
208   const locale::id* const
209   locale::_Impl::_S_id_numeric[] =
210   {
211     &std::numpunct<char>::id, 
212 #ifdef _GLIBCPP_USE_WCHAR_T
213     &std::numpunct<wchar_t>::id,
214 #endif
215     &std::num_get<char>::id,  
216  #ifdef _GLIBCPP_USE_WCHAR_T
217     &std::num_get<wchar_t>::id,
218 #endif
219     &std::num_put<char>::id,  
220 #ifdef _GLIBCPP_USE_WCHAR_T
221     &std::num_put<wchar_t>::id,
222 #endif
223     0
224   };
225   
226   const locale::id* const
227   locale::_Impl::_S_id_time[] =
228   {
229     &std::time_get<char>::id, 
230 #ifdef _GLIBCPP_USE_WCHAR_T
231     &std::time_get<wchar_t>::id,
232 #endif
233     &std::time_put<char>::id, 
234 #ifdef _GLIBCPP_USE_WCHAR_T
235     &std::time_put<wchar_t>::id,
236 #endif
237     0
238   };
239   
240   const locale::id* const
241   locale::_Impl::_S_id_messages[] =
242   {
243     &std::time_get<char>::id, 
244 #ifdef _GLIBCPP_USE_WCHAR_T
245     &std::time_get<wchar_t>::id,
246 #endif
247     &std::time_put<char>::id, 
248 #ifdef _GLIBCPP_USE_WCHAR_T
249     &std::time_put<wchar_t>::id,
250 #endif
251     0
252   };
253   
254   const locale::id* const* const
255   locale::_Impl::_S_facet_categories[] =
256   {
257     //  order must match the decl order in class locale.
258     locale::_Impl::_S_id_collate,
259     locale::_Impl::_S_id_ctype,
260     locale::_Impl::_S_id_monetary,
261     locale::_Impl::_S_id_numeric,
262     locale::_Impl::_S_id_time,
263     locale::_Impl::_S_id_messages,
264     0
265   };
266   
267   locale::_Impl* locale::_S_global;  // init'd to 0 before static ctors run
268   locale::_Impl* locale::_S_classic; // init'd to 0 before static ctors run
269
270   locale::
271   locale(_Impl* __ip) throw()
272   : _M_impl(__ip)
273   { __ip->_M_add_reference(); }
274
275   locale::
276   locale(const locale& __other, const locale& __one, category __cats)
277   {
278     __cats = _S_normalize_category(__cats);    // might throw
279     _M_impl = new _Impl(*__other._M_impl, 1);  // might throw
280
281     try { 
282       _M_impl->_M_replace_categories(__one._M_impl, __cats); 
283     }
284     catch (...) { 
285       _M_impl->_M_remove_reference(); 
286       throw; 
287     }
288
289     _M_impl->_M_cached_name_ok = false;
290     if (!__other._M_impl->_M_has_name)
291       _M_impl->_M_has_name = false;
292   }
293
294   const locale&
295   locale::
296   operator=(const locale& __other) throw()
297   {
298     __other._M_impl->_M_add_reference();
299     _M_impl->_M_remove_reference();
300     _M_impl = __other._M_impl;
301     return *this;
302   }
303
304   locale
305   locale::
306   global(const locale& __other)
307   {
308     // XXX MT
309     _S_initialize();
310     locale __keep(_S_global);
311     __other._M_impl->_M_add_reference();
312     _S_global->_M_remove_reference();
313     _S_global = __other._M_impl; 
314     if (_S_global->_M_has_name)
315       setlocale(LC_ALL, __other.name().c_str());
316     return __keep;
317   }
318
319   string
320   locale::
321   name() const
322   {
323     // XXX not done
324     return "*";
325   }
326
327   locale const&
328   locale::
329   classic()
330   {
331     static locale* __classic_locale;
332     // XXX MT
333     if (!_S_classic)
334       {
335         try {
336           _S_classic = _S_global = new _Impl(26u, 2u);
337           // One reference for _M_classic, one for _M_global
338           // (constructor for (*the_classic_locale) adds a third)
339             
340           // collate category
341           _S_classic->_M_facet_init(new std::collate<char>);
342           
343           // ctype category
344           _S_classic->_M_facet_init(new std::ctype<char>);
345           _S_classic->_M_facet_init(new codecvt<char, char, mbstate_t>);
346
347           // monetary category
348           _S_classic->_M_facet_init(new moneypunct<char, false>);
349           _S_classic->_M_facet_init(new moneypunct<char,true >);
350           _S_classic->_M_facet_init(new money_get<char>);
351           _S_classic->_M_facet_init(new money_put<char>);
352           
353           // numeric category
354           _S_classic->_M_facet_init(new numpunct<char>);
355           _S_classic->_M_facet_init(new num_get<char>);
356           _S_classic->_M_facet_init(new num_put<char>);
357           
358           // time category
359           _S_classic->_M_facet_init(new time_get<char>);
360           _S_classic->_M_facet_init(new time_put<char>);
361           
362           // messages category
363           _S_classic->_M_facet_init(new std::messages<char>);
364
365 #ifdef  _GLIBCPP_USE_WCHAR_T
366           _S_classic->_M_facet_init(new std::collate<wchar_t>);
367           _S_classic->_M_facet_init(new std::ctype<wchar_t>);
368           _S_classic->_M_facet_init(new codecvt<wchar_t, char, mbstate_t>);
369           _S_classic->_M_facet_init(new moneypunct<wchar_t, false>);
370           _S_classic->_M_facet_init(new moneypunct<wchar_t,true >);
371           _S_classic->_M_facet_init(new money_get<wchar_t>);
372           _S_classic->_M_facet_init(new money_put<wchar_t>);
373           _S_classic->_M_facet_init(new numpunct<wchar_t>);
374           _S_classic->_M_facet_init(new num_get<wchar_t>);
375           _S_classic->_M_facet_init(new num_put<wchar_t>);
376           _S_classic->_M_facet_init(new time_get<wchar_t>);
377           _S_classic->_M_facet_init(new time_put<wchar_t>);
378           _S_classic->_M_facet_init(new std::messages<wchar_t>);
379 #endif    
380
381           // finesse static init order hassles
382           __classic_locale = new locale(_S_classic);
383         }
384         catch(...) {
385           delete __classic_locale;
386           if (_S_classic)
387             {
388               _S_classic->_M_remove_reference();
389               _S_global->_M_remove_reference();
390             }
391           _S_classic = _S_global = 0;
392           // XXX MT
393           throw;
394         }
395       }
396     return *__classic_locale;
397   }
398
399   int
400   locale::
401   _S_normalize_category(int __cats) 
402   {
403     if ((__cats & all) && !(__cats & ~all))
404       return __cats;
405
406     // NB: May be a C-style "LC_ALL" category; convert.
407     switch (__cats)
408       {
409       case LC_COLLATE:  return collate; 
410       case LC_CTYPE:    return ctype;
411       case LC_MONETARY: return monetary;
412       case LC_NUMERIC:  return numeric;
413       case LC_TIME:     return time; 
414 #ifdef _GLIBCPP_HAVE_LC_MESSAGES
415       case LC_MESSAGES: return messages;
416 #endif  
417       case LC_ALL:      return all;
418       }
419     
420     // XXX should throw derived class here
421     throw runtime_error("bad locale category");
422     /* NOTREACHED */
423   }
424
425   locale::facet::
426   facet(size_t __refs) throw()
427   : _M_num_references(__refs - 1) 
428   { }
429
430   void  
431   locale::facet::
432   _M_add_reference() throw()
433   { 
434     if (this) 
435       ++_M_num_references; 
436   }                     // XXX MT
437
438   void  
439   locale::facet::
440   _M_remove_reference() throw()
441   {
442     if (this && _M_num_references-- == 0)
443       {
444         try { 
445           delete this; 
446         }  // XXX MT
447         catch (...) { 
448         }
449       }
450   }
451
452   char const* 
453   _Bad_use_facet::
454   what() const throw()
455   { return "bad_cast thrown from use_facet"; }
456
457   _Bad_use_facet::
458   ~_Bad_use_facet() throw() { }
459   
460   size_t locale::id::_S_highwater;  // init'd to 0 by linker
461
462
463   // Platform-specific initialization code for ctype tables.
464   #include <ctype.cc>
465
466   locale::id ctype<char>::id;
467
468   ctype<char>::
469   ~ctype()
470   { if (_M_del) delete[] this->table(); }
471
472   char
473   ctype<char>::
474   do_widen(char __c) const
475   { return __c; }
476   
477   const char* 
478   ctype<char>::
479   do_widen(const char* __low, const char* __high, char* __dest) const
480   {
481     memcpy(__dest, __low, __high - __low);
482     return __high;
483   }
484   
485   char
486   ctype<char>::
487   do_narrow(char __c, char /*__dfault*/) const
488   { return __c; }
489   
490   const char* 
491   ctype<char>::
492   do_narrow(const char* __low, const char* __high, char /*__dfault*/,
493             char* __dest) const
494   {
495     memcpy(__dest, __low, __high - __low);
496     return __high;
497   }
498
499   ctype_byname<char>::
500   ctype_byname(const char* /*__s*/, size_t __refs)
501   : ctype<char>(new mask[table_size], true, __refs)
502   { }
503
504
505   locale::id collate<char>::id;
506
507   collate<char>::collate(size_t __refs)
508   : _Collate<char>(__refs) { }
509   
510   collate<char>::~collate() { }
511   
512   int 
513   collate<char>::
514   do_compare(const char* __lo1, const char* __hi1, 
515              const char* __lo2, const char* __hi2) const
516   {
517     for (; __lo1 < __hi1 && __lo2 < __hi2; ++__lo1, ++__lo2) 
518       if (*__lo1 != *__lo2) 
519         return (*__lo1 < *__lo2) ? -1 : 1;
520     if (__lo1 < __hi1) 
521       return 1;
522     else if (__lo2 < __hi2) 
523       return -1;
524     else 
525       return 0;
526   }
527   
528   string
529   collate<char>::
530   do_transform(const char* __lo, const char* __hi) const
531   { return string(__lo, __hi - __lo); }
532   
533   long
534   collate<char>::
535   do_hash(const char* __lo, const char* __hi) const
536   {
537     unsigned long __val = 0xdeadbeef;
538     for (; __lo < __hi; ++__lo)
539       __val = *__lo ^ ((__val << 7) & 
540                    (__val >> (numeric_limits<unsigned long>::digits - 1)));
541     return __val;
542   }
543   
544   collate_byname<char>::
545   collate_byname(const char* /*__s*/, size_t __refs)
546   : collate<char>(__refs) { }
547
548   numpunct_byname<char>::
549   numpunct_byname(const char* /*__s*/, size_t __refs)
550   : numpunct<char>(__refs) { }
551
552   moneypunct_byname<char, false>::
553   moneypunct_byname(const char* /*__s*/, size_t __refs)
554   : moneypunct<char, false>(__refs) { }
555   
556   moneypunct_byname<char, true>::
557   moneypunct_byname(const char* /*__s*/, size_t __refs)
558   : moneypunct<char, true>(__refs) { }
559   
560   messages_byname<char>::
561   messages_byname(const char* /*__s*/, size_t __refs)
562   : messages<char>(__refs) { }
563
564 #ifdef _GLIBCPP_USE_WCHAR_T  
565   locale::id ctype<wchar_t>::id;
566
567   ctype<wchar_t>::
568   ~ctype() { }
569
570   // NB: These ctype<wchar_t> methods are not configuration-specific,
571   // unlike the ctype<char> bits.
572   ctype<wchar_t>::ctype(size_t __refs) : _Ctype<wchar_t>(__refs) { }
573
574   wchar_t
575   ctype<wchar_t>::do_toupper(wchar_t __c) const
576   { return towupper(__c); }
577
578   const wchar_t*
579   ctype<wchar_t>::do_toupper(wchar_t* __low, const wchar_t* __high) const
580   {
581     while (__low < __high)
582       {
583         *__low = towupper(*__low);
584         ++__low;
585       }
586     return __high;
587   }
588   
589   wchar_t
590   ctype<wchar_t>::do_tolower(wchar_t __c) const
591   { return towlower(__c); }
592   
593   const wchar_t*
594   ctype<wchar_t>::do_tolower(wchar_t* __low, const wchar_t* __high) const
595   {
596     while (__low < __high)
597       {
598         *__low = towlower(*__low);
599         ++__low;
600       }
601     return __high;
602   }
603
604   bool
605   ctype<wchar_t>::
606   do_is(mask __m, char_type __c) const
607   { return static_cast<bool>(iswctype(_M_convert_to_wmask(__m), __c)); }
608   
609   const wchar_t* 
610   ctype<wchar_t>::
611   do_is(const wchar_t* __low, const wchar_t* __high, mask* __m) const
612   {
613     while (__low < __high && !this->is(*__m, *__low))
614       ++__low;
615     return __low;
616   }
617   
618   const wchar_t* 
619   ctype<wchar_t>::
620   do_scan_is(mask __m, const wchar_t* __low, const wchar_t* __high) const
621   {
622     while (__low < __high && !this->is(__m, *__low))
623       ++__low;
624     return __low;
625   }
626
627   const wchar_t*
628   ctype<wchar_t>::
629   do_scan_not(mask __m, const char_type* __low, const char_type* __high) const
630   {
631     while (__low < __high && this->is(__m, *__low) != 0)
632       ++__low;
633     return __low;
634   }
635
636   wchar_t
637   ctype<wchar_t>::
638   do_widen(char __c) const
639   { return btowc(__c); }
640   
641   const char* 
642   ctype<wchar_t>::
643   do_widen(const char* __low, const char* __high, wchar_t* __dest) const
644   {
645     mbstate_t __state;
646     memset(&__state, 0, sizeof(mbstate_t));
647     mbsrtowcs(__dest, &__low, __high - __low, &__state);
648     return __high;
649   }
650
651   char
652   ctype<wchar_t>::
653   do_narrow(wchar_t __wc, char __dfault) const
654   { 
655     int __c = wctob(__wc);
656     return (__c == EOF ? __dfault : static_cast<char>(__c)); 
657   }
658
659   const wchar_t*
660   ctype<wchar_t>::
661   do_narrow(const wchar_t* __low, const wchar_t* __high, char __dfault, 
662             char* __dest) const
663   {
664     mbstate_t __state;
665     memset(&__state, 0, sizeof(mbstate_t));
666     size_t __len = __high - __low;
667     size_t __conv = wcsrtombs(__dest, &__low, __len, &__state);
668     if (__conv == __len)
669       *__dest = __dfault;
670     return __high;
671   }
672
673   ctype_byname<wchar_t>::
674   ctype_byname(const char* /*__s*/, size_t __refs)
675   : ctype<wchar_t>(__refs) { }
676
677   locale::id collate<wchar_t>::id;
678
679   collate<wchar_t>::
680   collate(size_t __refs)
681   : _Collate<wchar_t> (__refs) { }
682   
683   collate<wchar_t>::
684   ~collate() { }
685
686   int 
687   collate<wchar_t>::
688   do_compare(const wchar_t* /*__lo1*/, const wchar_t* /*__hi1*/,
689              const wchar_t* /*__lo2*/, const wchar_t* /*__hi2*/) const
690   {
691     return 0; // XXX not done
692   }
693   
694   wstring collate<wchar_t>::
695   do_transform(const wchar_t* /*__lo*/, const wchar_t* /*__hi*/) const
696   {
697     return wstring(); // XXX not done
698   }
699   
700   long collate<wchar_t>::
701   do_hash(const wchar_t* /*__lo*/, const wchar_t* /*__hi*/) const
702   {
703     return 0; // XXX not done
704   }
705
706   numpunct_byname<wchar_t>::
707   numpunct_byname(const char* /*__s*/, size_t __refs)
708   : numpunct<wchar_t> (__refs) { }
709
710   collate_byname<wchar_t>::
711   collate_byname(const char* /*__s*/, size_t __refs)
712   : collate<wchar_t> (__refs) { }
713   
714   moneypunct_byname<wchar_t, false>::
715   moneypunct_byname(const char* /*__s*/, size_t __refs)
716   : moneypunct<wchar_t, false> (__refs) { }
717   
718   moneypunct_byname<wchar_t, true>::
719   moneypunct_byname(const char* /*__s*/, size_t __refs)
720   : moneypunct<wchar_t, true> (__refs) { }
721     
722   messages_byname<wchar_t>::
723   messages_byname(const char* /*__s*/, size_t __refs)
724   : messages<wchar_t> (__refs) { }
725 #endif //  _GLIBCPP_USE_WCHAR_T
726
727 } // namespace std
728
729
730
731
732
733