1 // Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
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)
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.
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,
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.
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.
49 std::vector<facet*>::iterator it = _M_facets->begin();
50 for (; it != _M_facets->end(); ++it)
51 (*it)->_M_remove_reference();
53 delete _M_category_names;
57 _Impl(size_t __numfacets, size_t __refs)
58 : _M_num_references(__refs - 1)
60 , _M_category_names(0)
62 , _M_cached_name_ok(false)
63 , _M_cached_name(string ("*"))
65 typedef vector<facet*, allocator<facet*> > __vec_facet;
66 typedef vector<string, allocator<string> > __vec_string;
68 auto_ptr<__vec_facet> __pvf(new __vec_facet(__numfacets, (facet*)0));
69 auto_ptr<__vec_string> __pcn(new __vec_string(_S_num_categories,
71 _M_facets = __pvf.release();
72 _M_category_names = __pcn.release();
76 _Impl(const _Impl& __other, size_t __refs)
77 : _M_num_references(__refs)
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)
84 typedef vector<facet*, allocator<facet*> > __vec_facet;
85 typedef vector<string, allocator<string> > __vec_string;
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)));
91 std::vector<facet*>::iterator __it = __pvf->begin();
92 for (; __it != __pvf->end(); ++__it)
93 (*__it)->_M_add_reference();
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();
104 _M_replace_categories(const _Impl* __other, category __cats)
106 assert((__cats & locale::all) && !(__cats & ~locale::all));
108 unsigned mask = (locale::all & -(unsigned)locale::all);
109 for (unsigned ix = 0; (-mask & __cats) != 0; ++ix, (mask <<= 1))
113 _M_replace_category(__other, _S_facet_categories[ix]);
114 (*_M_category_names)[ix] = (*(__other->_M_category_names))[ix];
121 _M_replace_category(const _Impl* __other, const locale::id* const* __idpp)
123 for (; *__idpp; ++__idpp)
124 _M_replace_facet(__other, *__idpp);
129 _M_replace_facet(const _Impl* __other, const locale::id* __idp)
131 size_t __index = __idp->_M_index;
133 || __other->_M_facets->size() <= __index
134 || (*(__other->_M_facets))[__index] == 0)
135 throw runtime_error("no locale facet");
137 _M_install_facet(__idp, (*(__other->_M_facets))[__index]);
142 _M_install_facet(const locale::id* __idp, facet* __fp)
147 size_t& __index = __idp->_M_index;
149 __index = ++locale::id::_S_highwater; // XXX MT
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();
157 __fpr->_M_remove_reference();
161 // locale facet category descriptions
162 const locale::id* const
163 locale::_Impl::_S_id_collate[] =
165 &std::collate<char>::id,
166 #ifdef _GLIBCPP_USE_WCHAR_T
167 &std::collate<wchar_t>::id,
172 const locale::id* const
173 locale::_Impl::_S_id_ctype[] =
175 &std::ctype<char>::id,
176 #ifdef _GLIBCPP_USE_WCHAR_T
177 &std::ctype<wchar_t>::id,
179 &std::codecvt<char, char, mbstate_t>::id,
180 #ifdef _GLIBCPP_USE_WCHAR_T
181 &std::codecvt<wchar_t, char, mbstate_t>::id,
186 const locale::id* const
187 locale::_Impl::_S_id_monetary[] =
189 &std::moneypunct<char, false>::id,
190 #ifdef _GLIBCPP_USE_WCHAR_T
191 &std::moneypunct<wchar_t, false>::id,
193 &std::moneypunct<char,true >::id,
194 #ifdef _GLIBCPP_USE_WCHAR_T
195 &std::moneypunct<wchar_t,true >::id,
197 &std::money_get<char>::id,
198 #ifdef _GLIBCPP_USE_WCHAR_T
199 &std::money_get<wchar_t>::id,
201 &std::money_put<char>::id,
202 #ifdef _GLIBCPP_USE_WCHAR_T
203 &std::money_put<wchar_t>::id,
208 const locale::id* const
209 locale::_Impl::_S_id_numeric[] =
211 &std::numpunct<char>::id,
212 #ifdef _GLIBCPP_USE_WCHAR_T
213 &std::numpunct<wchar_t>::id,
215 &std::num_get<char>::id,
216 #ifdef _GLIBCPP_USE_WCHAR_T
217 &std::num_get<wchar_t>::id,
219 &std::num_put<char>::id,
220 #ifdef _GLIBCPP_USE_WCHAR_T
221 &std::num_put<wchar_t>::id,
226 const locale::id* const
227 locale::_Impl::_S_id_time[] =
229 &std::time_get<char>::id,
230 #ifdef _GLIBCPP_USE_WCHAR_T
231 &std::time_get<wchar_t>::id,
233 &std::time_put<char>::id,
234 #ifdef _GLIBCPP_USE_WCHAR_T
235 &std::time_put<wchar_t>::id,
240 const locale::id* const
241 locale::_Impl::_S_id_messages[] =
243 &std::time_get<char>::id,
244 #ifdef _GLIBCPP_USE_WCHAR_T
245 &std::time_get<wchar_t>::id,
247 &std::time_put<char>::id,
248 #ifdef _GLIBCPP_USE_WCHAR_T
249 &std::time_put<wchar_t>::id,
254 const locale::id* const* const
255 locale::_Impl::_S_facet_categories[] =
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,
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
271 locale(_Impl* __ip) throw()
273 { __ip->_M_add_reference(); }
276 locale(const locale& __other, const locale& __one, category __cats)
278 __cats = _S_normalize_category(__cats); // might throw
279 _M_impl = new _Impl(*__other._M_impl, 1); // might throw
282 _M_impl->_M_replace_categories(__one._M_impl, __cats);
285 _M_impl->_M_remove_reference();
289 _M_impl->_M_cached_name_ok = false;
290 if (!__other._M_impl->_M_has_name)
291 _M_impl->_M_has_name = false;
296 operator=(const locale& __other) throw()
298 __other._M_impl->_M_add_reference();
299 _M_impl->_M_remove_reference();
300 _M_impl = __other._M_impl;
306 global(const locale& __other)
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());
331 static locale* __classic_locale;
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)
341 _S_classic->_M_facet_init(new std::collate<char>);
344 _S_classic->_M_facet_init(new std::ctype<char>);
345 _S_classic->_M_facet_init(new codecvt<char, char, mbstate_t>);
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>);
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>);
359 _S_classic->_M_facet_init(new time_get<char>);
360 _S_classic->_M_facet_init(new time_put<char>);
363 _S_classic->_M_facet_init(new std::messages<char>);
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>);
381 // finesse static init order hassles
382 __classic_locale = new locale(_S_classic);
385 delete __classic_locale;
388 _S_classic->_M_remove_reference();
389 _S_global->_M_remove_reference();
391 _S_classic = _S_global = 0;
396 return *__classic_locale;
401 _S_normalize_category(int __cats)
403 if ((__cats & all) && !(__cats & ~all))
406 // NB: May be a C-style "LC_ALL" category; convert.
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;
417 case LC_ALL: return all;
420 // XXX should throw derived class here
421 throw runtime_error("bad locale category");
426 facet(size_t __refs) throw()
427 : _M_num_references(__refs - 1)
432 _M_add_reference() throw()
440 _M_remove_reference() throw()
442 if (this && _M_num_references-- == 0)
455 { return "bad_cast thrown from use_facet"; }
458 ~_Bad_use_facet() throw() { }
460 size_t locale::id::_S_highwater; // init'd to 0 by linker
463 // Platform-specific initialization code for ctype tables.
466 locale::id ctype<char>::id;
470 { if (_M_del) delete[] this->table(); }
474 do_widen(char __c) const
479 do_widen(const char* __low, const char* __high, char* __dest) const
481 memcpy(__dest, __low, __high - __low);
487 do_narrow(char __c, char /*__dfault*/) const
492 do_narrow(const char* __low, const char* __high, char /*__dfault*/,
495 memcpy(__dest, __low, __high - __low);
500 ctype_byname(const char* /*__s*/, size_t __refs)
501 : ctype<char>(new mask[table_size], true, __refs)
505 locale::id collate<char>::id;
507 collate<char>::collate(size_t __refs)
508 : _Collate<char>(__refs) { }
510 collate<char>::~collate() { }
514 do_compare(const char* __lo1, const char* __hi1,
515 const char* __lo2, const char* __hi2) const
517 for (; __lo1 < __hi1 && __lo2 < __hi2; ++__lo1, ++__lo2)
518 if (*__lo1 != *__lo2)
519 return (*__lo1 < *__lo2) ? -1 : 1;
522 else if (__lo2 < __hi2)
530 do_transform(const char* __lo, const char* __hi) const
531 { return string(__lo, __hi - __lo); }
535 do_hash(const char* __lo, const char* __hi) const
537 unsigned long __val = 0xdeadbeef;
538 for (; __lo < __hi; ++__lo)
539 __val = *__lo ^ ((__val << 7) &
540 (__val >> (numeric_limits<unsigned long>::digits - 1)));
544 collate_byname<char>::
545 collate_byname(const char* /*__s*/, size_t __refs)
546 : collate<char>(__refs) { }
548 numpunct_byname<char>::
549 numpunct_byname(const char* /*__s*/, size_t __refs)
550 : numpunct<char>(__refs) { }
552 moneypunct_byname<char, false>::
553 moneypunct_byname(const char* /*__s*/, size_t __refs)
554 : moneypunct<char, false>(__refs) { }
556 moneypunct_byname<char, true>::
557 moneypunct_byname(const char* /*__s*/, size_t __refs)
558 : moneypunct<char, true>(__refs) { }
560 messages_byname<char>::
561 messages_byname(const char* /*__s*/, size_t __refs)
562 : messages<char>(__refs) { }
564 #ifdef _GLIBCPP_USE_WCHAR_T
565 locale::id ctype<wchar_t>::id;
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) { }
575 ctype<wchar_t>::do_toupper(wchar_t __c) const
576 { return towupper(__c); }
579 ctype<wchar_t>::do_toupper(wchar_t* __low, const wchar_t* __high) const
581 while (__low < __high)
583 *__low = towupper(*__low);
590 ctype<wchar_t>::do_tolower(wchar_t __c) const
591 { return towlower(__c); }
594 ctype<wchar_t>::do_tolower(wchar_t* __low, const wchar_t* __high) const
596 while (__low < __high)
598 *__low = towlower(*__low);
606 do_is(mask __m, char_type __c) const
607 { return static_cast<bool>(iswctype(_M_convert_to_wmask(__m), __c)); }
611 do_is(const wchar_t* __low, const wchar_t* __high, mask* __m) const
613 while (__low < __high && !this->is(*__m, *__low))
620 do_scan_is(mask __m, const wchar_t* __low, const wchar_t* __high) const
622 while (__low < __high && !this->is(__m, *__low))
629 do_scan_not(mask __m, const char_type* __low, const char_type* __high) const
631 while (__low < __high && this->is(__m, *__low) != 0)
638 do_widen(char __c) const
639 { return btowc(__c); }
643 do_widen(const char* __low, const char* __high, wchar_t* __dest) const
646 memset(&__state, 0, sizeof(mbstate_t));
647 mbsrtowcs(__dest, &__low, __high - __low, &__state);
653 do_narrow(wchar_t __wc, char __dfault) const
655 int __c = wctob(__wc);
656 return (__c == EOF ? __dfault : static_cast<char>(__c));
661 do_narrow(const wchar_t* __low, const wchar_t* __high, char __dfault,
665 memset(&__state, 0, sizeof(mbstate_t));
666 size_t __len = __high - __low;
667 size_t __conv = wcsrtombs(__dest, &__low, __len, &__state);
673 ctype_byname<wchar_t>::
674 ctype_byname(const char* /*__s*/, size_t __refs)
675 : ctype<wchar_t>(__refs) { }
677 locale::id collate<wchar_t>::id;
680 collate(size_t __refs)
681 : _Collate<wchar_t> (__refs) { }
688 do_compare(const wchar_t* /*__lo1*/, const wchar_t* /*__hi1*/,
689 const wchar_t* /*__lo2*/, const wchar_t* /*__hi2*/) const
691 return 0; // XXX not done
694 wstring collate<wchar_t>::
695 do_transform(const wchar_t* /*__lo*/, const wchar_t* /*__hi*/) const
697 return wstring(); // XXX not done
700 long collate<wchar_t>::
701 do_hash(const wchar_t* /*__lo*/, const wchar_t* /*__hi*/) const
703 return 0; // XXX not done
706 numpunct_byname<wchar_t>::
707 numpunct_byname(const char* /*__s*/, size_t __refs)
708 : numpunct<wchar_t> (__refs) { }
710 collate_byname<wchar_t>::
711 collate_byname(const char* /*__s*/, size_t __refs)
712 : collate<wchar_t> (__refs) { }
714 moneypunct_byname<wchar_t, false>::
715 moneypunct_byname(const char* /*__s*/, size_t __refs)
716 : moneypunct<wchar_t, false> (__refs) { }
718 moneypunct_byname<wchar_t, true>::
719 moneypunct_byname(const char* /*__s*/, size_t __refs)
720 : moneypunct<wchar_t, true> (__refs) { }
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