diff options
author | obrien <obrien@FreeBSD.org> | 2002-05-28 16:16:03 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 2002-05-28 16:16:03 +0000 |
commit | 0895e1acb698e05d503c26bec5471de2e88b7d93 (patch) | |
tree | 7b14e1142a8f8cf48f311f5246aa3b355f2380b6 /contrib/libstdc++/src/locale.cc | |
parent | efbfe7b228c18b8cc364aabaefd6f8253bc6b5ad (diff) | |
download | FreeBSD-src-0895e1acb698e05d503c26bec5471de2e88b7d93.zip FreeBSD-src-0895e1acb698e05d503c26bec5471de2e88b7d93.tar.gz |
Gcc 3.1.0 pre-release's C++ support bits from the FSF anoncvs repo
on 9-May-2002 15:57:15 EDT.
Diffstat (limited to 'contrib/libstdc++/src/locale.cc')
-rw-r--r-- | contrib/libstdc++/src/locale.cc | 588 |
1 files changed, 588 insertions, 0 deletions
diff --git a/contrib/libstdc++/src/locale.cc b/contrib/libstdc++/src/locale.cc new file mode 100644 index 0000000..26c2834 --- /dev/null +++ b/contrib/libstdc++/src/locale.cc @@ -0,0 +1,588 @@ +// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 +// Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. + +// As a special exception, you may use this file as part of a free software +// library without restriction. Specifically, if other files instantiate +// templates or use macros or inline functions from this file, or you compile +// this file and link it with other files to produce an executable, this +// file does not by itself cause the resulting executable to be covered by +// the GNU General Public License. This exception does not however +// invalidate any other reasons why the executable file might be covered by +// the GNU General Public License. + +#include <clocale> +#include <cstring> +#include <cassert> +#include <cctype> +#include <cwctype> // For towupper, etc. +#include <limits> +#include <exception> +#include <locale> +#include <istream> +#include <ostream> +#include <bits/atomicity.h> + +namespace std +{ + // Defined in globals.cc. + extern locale c_locale; + extern locale::_Impl c_locale_impl; + extern locale::facet** facet_vec; + + // Definitions for static const data members of locale. + const locale::category locale::none; + const locale::category locale::ctype; + const locale::category locale::numeric; + const locale::category locale::collate; + const locale::category locale::time; + const locale::category locale::monetary; + const locale::category locale::messages; + const locale::category locale::all; + + locale::_Impl* locale::_S_classic; + locale::_Impl* locale::_S_global; + const size_t locale::_S_num_categories; + + // Definitions for locale::id of standard facets that are specialized. + locale::id ctype<char>::id; + locale::id codecvt<char, char, mbstate_t>::id; + +#ifdef _GLIBCPP_USE_WCHAR_T + locale::id ctype<wchar_t>::id; + locale::id codecvt<wchar_t, char, mbstate_t>::id; +#endif + + // Definitions for static const data members of locale::id + _Atomic_word locale::id::_S_highwater; // init'd to 0 by linker + + // Definitions for static const data members of locale::_Impl + const locale::id* const + locale::_Impl::_S_id_ctype[] = + { + &std::ctype<char>::id, + &codecvt<char, char, mbstate_t>::id, +#ifdef _GLIBCPP_USE_WCHAR_T + &std::ctype<wchar_t>::id, + &codecvt<wchar_t, char, mbstate_t>::id, +#endif + 0 + }; + + const locale::id* const + locale::_Impl::_S_id_numeric[] = + { + &num_get<char>::id, + &num_put<char>::id, + &numpunct<char>::id, +#ifdef _GLIBCPP_USE_WCHAR_T + &num_get<wchar_t>::id, + &num_put<wchar_t>::id, + &numpunct<wchar_t>::id, +#endif + 0 + }; + + const locale::id* const + locale::_Impl::_S_id_collate[] = + { + &std::collate<char>::id, +#ifdef _GLIBCPP_USE_WCHAR_T + &std::collate<wchar_t>::id, +#endif + 0 + }; + + const locale::id* const + locale::_Impl::_S_id_time[] = + { + &__timepunct<char>::id, + &time_get<char>::id, + &time_put<char>::id, +#ifdef _GLIBCPP_USE_WCHAR_T + &__timepunct<wchar_t>::id, + &time_get<wchar_t>::id, + &time_put<wchar_t>::id, +#endif + 0 + }; + + const locale::id* const + locale::_Impl::_S_id_monetary[] = + { + &money_get<char>::id, + &money_put<char>::id, + &moneypunct<char, false>::id, + &moneypunct<char, true >::id, +#ifdef _GLIBCPP_USE_WCHAR_T + &money_get<wchar_t>::id, + &money_put<wchar_t>::id, + &moneypunct<wchar_t, false>::id, + &moneypunct<wchar_t, true >::id, +#endif + 0 + }; + + const locale::id* const + locale::_Impl::_S_id_messages[] = + { + &std::messages<char>::id, +#ifdef _GLIBCPP_USE_WCHAR_T + &std::messages<wchar_t>::id, +#endif + 0 + }; + + const locale::id* const* const + locale::_Impl::_S_facet_categories[] = + { + // Order must match the decl order in class locale. + locale::_Impl::_S_id_ctype, + locale::_Impl::_S_id_numeric, + locale::_Impl::_S_id_collate, + locale::_Impl::_S_id_monetary, + locale::_Impl::_S_id_time, + locale::_Impl::_S_id_messages, + 0 + }; + + locale::~locale() throw() + { _M_impl->_M_remove_reference(); } + + void + locale::_M_coalesce(const locale& __base, const locale& __add, + category __cat) + { + __cat = _S_normalize_category(__cat); + _M_impl = new _Impl(*__base._M_impl, 1); + + try + { _M_impl->_M_replace_categories(__add._M_impl, __cat); } + catch (...) + { + _M_impl->_M_remove_reference(); + __throw_exception_again; + } + } + + locale::locale() throw() + { + _S_initialize(); + (_M_impl = _S_global)->_M_add_reference(); + } + + locale::locale(const locale& __other) throw() + { (_M_impl = __other._M_impl)->_M_add_reference(); } + + // This is used to initialize global and classic locales, and + // assumes that the _Impl objects are constructed correctly. + locale::locale(_Impl* __ip) throw() : _M_impl(__ip) + { } + + locale::locale(const char* __s) + { + if (__s) + { + _S_initialize(); + if (strcmp(__s, "C") == 0 || strcmp(__s, "POSIX") == 0) + (_M_impl = _S_classic)->_M_add_reference(); + else if (strcmp(__s, "") == 0) + _M_impl = new _Impl(setlocale(LC_ALL, __s), 1); + else + _M_impl = new _Impl(__s, 1); + } + else + __throw_runtime_error("attempt to create locale from NULL name"); + } + + locale::locale(const locale& __base, const char* __s, category __cat) + { + // NB: There are complicated, yet more efficient ways to do + // this. Building up locales on a per-category way is tedious, so + // let's do it this way until people complain. + locale __add(__s); + _M_coalesce(__base, __add, __cat); + } + + locale::locale(const locale& __base, const locale& __add, category __cat) + { _M_coalesce(__base, __add, __cat); } + + bool + locale::operator==(const locale& __rhs) const throw() + { + string __name = this->name(); + return (_M_impl == __rhs._M_impl + || (__name != "*" && __name == __rhs.name())); + } + + const locale& + locale::operator=(const locale& __other) throw() + { + __other._M_impl->_M_add_reference(); + _M_impl->_M_remove_reference(); + _M_impl = __other._M_impl; + return *this; + } + + locale + locale::global(const locale& __other) + { + // XXX MT + _S_initialize(); + _Impl* __old = _S_global; + __other._M_impl->_M_add_reference(); + _S_global = __other._M_impl; + if (_S_global->_M_check_same_name() + && (strcmp(_S_global->_M_names[0], "*") != 0)) + setlocale(LC_ALL, __other.name().c_str()); + + // Reference count sanity check: one reference removed for the + // subsition of __other locale, one added by return-by-value. Net + // difference: zero. When the returned locale object's destrutor + // is called, then the reference count is decremented and possibly + // destroyed. + return locale(__old); + } + + string + locale::name() const + { + // Need some kind of separator character. This one was pretty much + // arbitrarily chosen as to not conflict with glibc locales: the + // exact formatting is not set in stone. + const char __separator = '|'; + + string __ret; + if (_M_impl->_M_check_same_name()) + __ret = _M_impl->_M_names[0]; + else + { + for (size_t i = 0; i < _S_num_categories; ++i) + { + __ret += __separator; + __ret += _M_impl->_M_names[i]; + } + } + return __ret; + } + + const locale& + locale::classic() + { + static _STL_mutex_lock __lock __STL_MUTEX_INITIALIZER; + _STL_auto_lock __auto(__lock); + + if (!_S_classic) + { + try + { + // 26 Standard facets, 2 references. + // One reference for _M_classic, one for _M_global + facet** f = new(&facet_vec) facet*[_GLIBCPP_NUM_FACETS]; + for (size_t __i = 0; __i < _GLIBCPP_NUM_FACETS; ++__i) + f[__i] = 0; + + _S_classic = new (&c_locale_impl) _Impl(f, 2, true); + _S_global = _S_classic; + new (&c_locale) locale(_S_classic); + } + catch(...) + { + // Just call destructor, so that locale_impl_c's memory is + // not deallocated via a call to delete. + if (_S_classic) + _S_classic->~_Impl(); + _S_classic = _S_global = 0; + __throw_exception_again; + } + } + return c_locale; + } + + locale::category + locale::_S_normalize_category(category __cat) + { + int __ret = 0; + if (__cat == none || (__cat & all) && !(__cat & ~all)) + __ret = __cat; + else + { + // NB: May be a C-style "LC_ALL" category; convert. + switch (__cat) + { + case LC_COLLATE: + __ret = collate; + break; + case LC_CTYPE: + __ret = ctype; + break; + case LC_MONETARY: + __ret = monetary; + break; + case LC_NUMERIC: + __ret = numeric; + break; + case LC_TIME: + __ret = time; + break; +#ifdef _GLIBCPP_HAVE_LC_MESSAGES + case LC_MESSAGES: + __ret = messages; + break; +#endif + case LC_ALL: + __ret = all; + break; + default: + __throw_runtime_error("bad locale category"); + } + } + return __ret; + } + + __c_locale + locale::facet::_S_c_locale; + + locale::facet:: + ~facet() { } + + locale::facet:: + facet(size_t __refs) throw() : _M_references(__refs) + { + if (!_S_c_locale) + _S_create_c_locale(_S_c_locale, "C"); + } + + void + locale::facet:: + _M_add_reference() throw() + { __atomic_add(&_M_references, 1); } + + void + locale::facet:: + _M_remove_reference() throw() + { + if (__exchange_and_add(&_M_references, -1) == 0) + { + try + { delete this; } + catch (...) + { } + } + } + + locale::id::id() + { } + + // Definitions for static const data members of ctype_base. + const ctype_base::mask ctype_base::space; + const ctype_base::mask ctype_base::print; + const ctype_base::mask ctype_base::cntrl; + const ctype_base::mask ctype_base::upper; + const ctype_base::mask ctype_base::lower; + const ctype_base::mask ctype_base::alpha; + const ctype_base::mask ctype_base::digit; + const ctype_base::mask ctype_base::punct; + const ctype_base::mask ctype_base::xdigit; + const ctype_base::mask ctype_base::alnum; + const ctype_base::mask ctype_base::graph; + + // Platform-specific initialization code for ctype tables. + #include <bits/ctype_noninline.h> + + const size_t ctype<char>::table_size; + + ctype<char>::~ctype() + { + if (_M_c_locale_ctype != _S_c_locale) + _S_destroy_c_locale(_M_c_locale_ctype); + if (_M_del) + delete[] this->table(); + } + + // These are dummy placeholders as these virtual functions are never called. + bool + ctype<char>::do_is(mask, char_type) const + { return false; } + + const char* + ctype<char>::do_is(const char_type* __c, const char_type*, mask*) const + { return __c; } + + const char* + ctype<char>::do_scan_is(mask, const char_type* __c, const char_type*) const + { return __c; } + + const char* + ctype<char>::do_scan_not(mask, const char_type* __c, const char_type*) const + { return __c; } + + char + ctype<char>::do_widen(char __c) const + { return __c; } + + const char* + ctype<char>::do_widen(const char* __lo, const char* __hi, char* __dest) const + { + memcpy(__dest, __lo, __hi - __lo); + return __hi; + } + + char + ctype<char>::do_narrow(char __c, char /*__dfault*/) const + { return __c; } + + const char* + ctype<char>::do_narrow(const char* __lo, const char* __hi, + char /*__dfault*/, char* __dest) const + { + memcpy(__dest, __lo, __hi - __lo); + return __hi; + } + +#ifdef _GLIBCPP_USE_WCHAR_T + ctype<wchar_t>::ctype(size_t __refs) + : __ctype_abstract_base<wchar_t>(__refs) + { _M_c_locale_ctype = _S_c_locale; } + + ctype<wchar_t>::ctype(__c_locale __cloc, size_t __refs) + : __ctype_abstract_base<wchar_t>(__refs) + { _M_c_locale_ctype = _S_clone_c_locale(__cloc); } + + ctype<wchar_t>::~ctype() + { + if (_M_c_locale_ctype != _S_c_locale) + _S_destroy_c_locale(_M_c_locale_ctype); + } + + template<> + ctype_byname<wchar_t>::ctype_byname(const char* __s, size_t __refs) + : ctype<wchar_t>(__refs) + { + if (_M_c_locale_ctype != _S_c_locale) + _S_destroy_c_locale(_M_c_locale_ctype); + _S_create_c_locale(_M_c_locale_ctype, __s); + } +#endif + + // Definitions for static const data members of time_base + template<> + const char* + __timepunct<char>::_S_timezones[14] = + { + "GMT", "HST", "AKST", "PST", "MST", "CST", "EST", "AST", "NST", "CET", + "IST", "EET", "CST", "JST" + }; + +#ifdef _GLIBCPP_USE_WCHAR_T + template<> + const wchar_t* + __timepunct<wchar_t>::_S_timezones[14] = + { + L"GMT", L"HST", L"AKST", L"PST", L"MST", L"CST", L"EST", L"AST", + L"NST", L"CET", L"IST", L"EET", L"CST", L"JST" + }; +#endif + + // Definitions for static const data members of money_base + const money_base::pattern + money_base::_S_default_pattern = { {symbol, sign, none, value} }; + + template<> + const ctype<char>& + use_facet<ctype<char> >(const locale& __loc) + { + size_t __i = ctype<char>::id._M_id(); + const locale::_Impl* __tmp = __loc._M_impl; + return static_cast<const ctype<char>&>(*(__tmp->_M_facets[__i])); + } + +#ifdef _GLIBCPP_USE_WCHAR_T + template<> + const ctype<wchar_t>& + use_facet<ctype<wchar_t> >(const locale& __loc) + { + size_t __i = ctype<wchar_t>::id._M_id(); + const locale::_Impl* __tmp = __loc._M_impl; + return static_cast<const ctype<wchar_t>&>(*(__tmp->_M_facets[__i])); + } +#endif + + const char __num_base::_S_atoms[] = "0123456789eEabcdfABCDF"; + + bool + __num_base::_S_format_float(const ios_base& __io, char* __fptr, char __mod, + streamsize __prec) + { + bool __incl_prec = false; + ios_base::fmtflags __flags = __io.flags(); + *__fptr++ = '%'; + // [22.2.2.2.2] Table 60 + if (__flags & ios_base::showpos) + *__fptr++ = '+'; + if (__flags & ios_base::showpoint) + *__fptr++ = '#'; + // As per [22.2.2.2.2.11] + if (__flags & ios_base::fixed || __prec > 0) + { + *__fptr++ = '.'; + *__fptr++ = '*'; + __incl_prec = true; + } + if (__mod) + *__fptr++ = __mod; + ios_base::fmtflags __fltfield = __flags & ios_base::floatfield; + // [22.2.2.2.2] Table 58 + if (__fltfield == ios_base::fixed) + *__fptr++ = 'f'; + else if (__fltfield == ios_base::scientific) + *__fptr++ = (__flags & ios_base::uppercase) ? 'E' : 'e'; + else + *__fptr++ = (__flags & ios_base::uppercase) ? 'G' : 'g'; + *__fptr = '\0'; + return __incl_prec; + } + + void + __num_base::_S_format_int(const ios_base& __io, char* __fptr, char __mod, + char __modl) + { + ios_base::fmtflags __flags = __io.flags(); + *__fptr++ = '%'; + // [22.2.2.2.2] Table 60 + if (__flags & ios_base::showpos) + *__fptr++ = '+'; + if (__flags & ios_base::showbase) + *__fptr++ = '#'; + *__fptr++ = 'l'; + + // For long long types. + if (__modl) + *__fptr++ = __modl; + + ios_base::fmtflags __bsefield = __flags & ios_base::basefield; + if (__bsefield == ios_base::hex) + *__fptr++ = (__flags & ios_base::uppercase) ? 'X' : 'x'; + else if (__bsefield == ios_base::oct) + *__fptr++ = 'o'; + else + *__fptr++ = __mod; + *__fptr = '\0'; + } +} // namespace std + |