// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003 // 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 #include #include namespace __gnu_cxx { using namespace std; // Defined in globals.cc. extern locale::facet* facet_vec[_GLIBCPP_NUM_FACETS]; extern char* name_vec[6 + _GLIBCPP_NUM_CATEGORIES]; extern char name_c[6 + _GLIBCPP_NUM_CATEGORIES][2]; extern std::ctype ctype_c; extern std::collate collate_c; extern numpunct numpunct_c; extern num_get num_get_c; extern num_put num_put_c; extern codecvt codecvt_c; extern moneypunct moneypunct_fc; extern moneypunct moneypunct_tc; extern money_get money_get_c; extern money_put money_put_c; extern __timepunct timepunct_c; extern time_get time_get_c; extern time_put time_put_c; extern std::messages messages_c; #ifdef _GLIBCPP_USE_WCHAR_T extern std::ctype ctype_w; extern std::collate collate_w; extern numpunct numpunct_w; extern num_get num_get_w; extern num_put num_put_w; extern codecvt codecvt_w; extern moneypunct moneypunct_fw; extern moneypunct moneypunct_tw; extern money_get money_get_w; extern money_put money_put_w; extern __timepunct timepunct_w; extern time_get time_get_w; extern time_put time_put_w; extern std::messages messages_w; #endif extern locale::facet* cache_vec[_GLIBCPP_NUM_FACETS]; extern std::__numpunct_cache numpunct_cache_c; #ifdef _GLIBCPP_USE_WCHAR_T extern std::__numpunct_cache numpunct_cache_w; #endif } // namespace __gnu_cxx namespace std { using namespace __gnu_cxx; locale::_Impl:: ~_Impl() throw() { for (size_t __i = 0; __i < _M_facets_size; ++__i) if (_M_facets[__i]) _M_facets[__i]->_M_remove_reference(); delete [] _M_facets; for (size_t __i = 0; __i < _M_facets_size; ++__i) if (_M_caches[__i]) _M_caches[__i]->_M_remove_reference(); delete [] _M_caches; for (size_t __i = 0; __i < _S_categories_size; ++__i) delete [] _M_names[__i]; delete [] _M_names; } // Clone existing _Impl object. locale::_Impl:: _Impl(const _Impl& __imp, size_t __refs) : _M_references(__refs), _M_facets_size(__imp._M_facets_size) { try { _M_facets = new const facet*[_M_facets_size]; for (size_t __i = 0; __i < _M_facets_size; ++__i) _M_facets[__i] = 0; } catch(...) { delete [] _M_facets; __throw_exception_again; } for (size_t __i = 0; __i < _M_facets_size; ++__i) { _M_facets[__i] = __imp._M_facets[__i]; if (_M_facets[__i]) _M_facets[__i]->_M_add_reference(); } try { _M_caches = new const facet*[_M_facets_size]; } catch(...) { delete [] _M_caches; __throw_exception_again; } for (size_t __i = 0; __i < _M_facets_size; ++__i) { _M_caches[__i] = __imp._M_caches[__i]; if (_M_caches[__i]) _M_caches[__i]->_M_add_reference(); } try { _M_names = new char*[_S_categories_size]; } catch(...) { delete [] _M_names; __throw_exception_again; } for (size_t __i = 0; __i < _S_categories_size; ++__i) { char* __new = new char[strlen(__imp._M_names[__i]) + 1]; strcpy(__new, __imp._M_names[__i]); _M_names[__i] = __new; } } // Construct named _Impl. locale::_Impl:: _Impl(const char* __s, size_t __refs) : _M_references(__refs), _M_facets_size(_GLIBCPP_NUM_FACETS) { // Initialize the underlying locale model, which also checks to // see if the given name is valid. __c_locale __cloc; locale::facet::_S_create_c_locale(__cloc, __s); try { _M_facets = new const facet*[_M_facets_size]; for (size_t __i = 0; __i < _M_facets_size; ++__i) _M_facets[__i] = 0; } catch(...) { delete [] _M_facets; __throw_exception_again; } try { _M_caches = new const facet*[_M_facets_size]; for (size_t __i = 0; __i < _M_facets_size; ++__i) _M_caches[__i] = 0; } catch(...) { delete [] _M_caches; __throw_exception_again; } // Name all the categories. try { _M_names = new char*[_S_categories_size]; } catch(...) { delete [] _M_names; __throw_exception_again; } size_t __len = strlen(__s); if (!strchr(__s, ';')) { for (size_t __i = 0; __i < _S_categories_size; ++__i) { _M_names[__i] = new char[__len + 1]; strcpy(_M_names[__i], __s); } } else { const char* __beg = __s; for (size_t __i = 0; __i < _S_categories_size; ++__i) { __beg = strchr(__beg, '=') + 1; const char* __end = strchr(__beg, ';'); if (!__end) __end = __s + __len; char* __new = new char[__end - __beg + 1]; memcpy(__new, __beg, __end - __beg); __new[__end - __beg] = '\0'; _M_names[__i] = __new; } } // Construct all standard facets and add them to _M_facets. _M_init_facet(new std::ctype(__cloc, 0, false)); _M_init_facet(new codecvt(__cloc)); _M_init_facet(new numpunct(__cloc)); _M_init_facet(new num_get); _M_init_facet(new num_put); _M_init_facet(new std::collate(__cloc)); _M_init_facet(new moneypunct(__cloc, __s)); _M_init_facet(new moneypunct(__cloc, __s)); _M_init_facet(new money_get); _M_init_facet(new money_put); _M_init_facet(new __timepunct(__cloc, __s)); _M_init_facet(new time_get); _M_init_facet(new time_put); _M_init_facet(new std::messages(__cloc, __s)); #ifdef _GLIBCPP_USE_WCHAR_T _M_init_facet(new std::ctype(__cloc)); _M_init_facet(new codecvt(__cloc)); _M_init_facet(new numpunct(__cloc)); _M_init_facet(new num_get); _M_init_facet(new num_put); _M_init_facet(new std::collate(__cloc)); _M_init_facet(new moneypunct(__cloc, __s)); _M_init_facet(new moneypunct(__cloc, __s)); _M_init_facet(new money_get); _M_init_facet(new money_put); _M_init_facet(new __timepunct(__cloc, __s)); _M_init_facet(new time_get); _M_init_facet(new time_put); _M_init_facet(new std::messages(__cloc, __s)); #endif locale::facet::_S_destroy_c_locale(__cloc); } // Construct "C" _Impl. locale::_Impl:: _Impl(facet**, size_t __refs, bool) : _M_references(__refs), _M_facets_size(_GLIBCPP_NUM_FACETS) { // Initialize the underlying locale model. locale::facet::_S_c_name[0] = 'C'; locale::facet::_S_c_name[1] = '\0'; locale::facet::_S_create_c_locale(locale::facet::_S_c_locale, locale::facet::_S_c_name); _M_facets = new (&facet_vec) const facet*[_M_facets_size]; for (size_t __i = 0; __i < _M_facets_size; ++__i) _M_facets[__i] = 0; _M_caches = new (&cache_vec) const facet*[_M_facets_size]; for (size_t __i = 0; __i < _M_facets_size; ++__i) _M_caches[__i] = 0; // Name all the categories. _M_names = new (&name_vec) char*[_S_categories_size]; for (size_t __i = 0; __i < _S_categories_size; ++__i) { _M_names[__i] = new (&name_c[__i]) char[2]; strcpy(_M_names[__i], locale::facet::_S_c_name); } // This is needed as presently the C++ version of "C" locales // != data in the underlying locale model for __timepunct, // numpunct, and moneypunct. Also, the "C" locales must be // constructed in a way such that they are pre-allocated. // NB: Set locale::facets(ref) count to one so that each individual // facet is not destroyed when the locale (and thus locale::_Impl) is // destroyed. _M_init_facet(new (&ctype_c) std::ctype(0, false, 1)); _M_init_facet(new (&codecvt_c) codecvt(1)); // Safe to cache this. typedef __numpunct_cache num_cache_c; num_cache_c* __npc = new (&numpunct_cache_c) num_cache_c(2); _M_init_facet(new (&numpunct_c) numpunct(__npc, 1)); _M_init_facet(new (&num_get_c) num_get(1)); _M_init_facet(new (&num_put_c) num_put(1)); _M_init_facet(new (&collate_c) std::collate(1)); _M_init_facet(new (&moneypunct_fc) moneypunct(1)); _M_init_facet(new (&moneypunct_tc) moneypunct(1)); _M_init_facet(new (&money_get_c) money_get(1)); _M_init_facet(new (&money_put_c) money_put(1)); _M_init_facet(new (&timepunct_c) __timepunct(1)); _M_init_facet(new (&time_get_c) time_get(1)); _M_init_facet(new (&time_put_c) time_put(1)); _M_init_facet(new (&messages_c) std::messages(1)); #ifdef _GLIBCPP_USE_WCHAR_T _M_init_facet(new (&ctype_w) std::ctype(1)); _M_init_facet(new (&codecvt_w) codecvt(1)); typedef __numpunct_cache num_cache_w; num_cache_w* __npw = new (&numpunct_cache_w) num_cache_w(2); _M_init_facet(new (&numpunct_w) numpunct(__npw, 1)); _M_init_facet(new (&num_get_w) num_get(1)); _M_init_facet(new (&num_put_w) num_put(1)); _M_init_facet(new (&collate_w) std::collate(1)); _M_init_facet(new (&moneypunct_fw) moneypunct(1)); _M_init_facet(new (&moneypunct_tw) moneypunct(1)); _M_init_facet(new (&money_get_w) money_get(1)); _M_init_facet(new (&money_put_w) money_put(1)); _M_init_facet(new (&timepunct_w) __timepunct(1)); _M_init_facet(new (&time_get_w) time_get(1)); _M_init_facet(new (&time_put_w) time_put(1)); _M_init_facet(new (&messages_w) std::messages(1)); #endif // This locale is safe to pre-cache, after all the facets have // been installed. _M_caches[numpunct::id._M_id()] = __npc; #ifdef _GLIBCPP_USE_WCHAR_T _M_caches[numpunct::id._M_id()] = __npw; #endif } void locale::_Impl:: _M_replace_categories(const _Impl* __imp, category __cat) { category __mask; for (size_t __ix = 0; __ix < _S_categories_size; ++__ix) { __mask = 1 << __ix; if (__mask & __cat) { // Need to replace entry in _M_facets with other locale's info. _M_replace_category(__imp, _S_facet_categories[__ix]); // If both have names, go ahead and mangle. if (strcmp(_M_names[__ix], "*") != 0 && strcmp(__imp->_M_names[__ix], "*") != 0) { delete [] _M_names[__ix]; char* __new = new char[strlen(__imp->_M_names[__ix]) + 1]; strcpy(__new, __imp->_M_names[__ix]); _M_names[__ix] = __new; } } } } void locale::_Impl:: _M_replace_category(const _Impl* __imp, const locale::id* const* __idpp) { for (; *__idpp; ++__idpp) _M_replace_facet(__imp, *__idpp); } void locale::_Impl:: _M_replace_facet(const _Impl* __imp, const locale::id* __idp) { size_t __index = __idp->_M_id(); if ((__index > (__imp->_M_facets_size - 1)) || !__imp->_M_facets[__index]) __throw_runtime_error("locale::_Impl::_M_replace_facet"); _M_install_facet(__idp, __imp->_M_facets[__index]); } void locale::_Impl:: _M_install_facet(const locale::id* __idp, const facet* __fp) { if (__fp) { size_t __index = __idp->_M_id(); // Check size of facet vector to ensure adequate room. if (__index > _M_facets_size - 1) { const size_t __new_size = __index + 4; // New facet array. const facet** __oldf = _M_facets; const facet** __newf; __newf = new const facet*[__new_size]; for (size_t __i = 0; __i < _M_facets_size; ++__i) __newf[__i] = _M_facets[__i]; for (size_t __i2 = _M_facets_size; __i2 < __new_size; ++__i2) __newf[__i2] = 0; // New cache array. const facet** __oldc = _M_caches; const facet** __newc; __newc = new const facet*[__new_size]; for (size_t __i = 0; __i < _M_facets_size; ++__i) __newc[__i] = _M_caches[__i]; for (size_t __i2 = _M_facets_size; __i2 < __new_size; ++__i2) __newc[__i2] = 0; _M_facets_size = __new_size; _M_facets = __newf; _M_caches = __newc; delete [] __oldf; delete [] __oldc; } __fp->_M_add_reference(); const facet*& __fpr = _M_facets[__index]; if (__fpr) { // Replacing an existing facet. Order matters. __fpr->_M_remove_reference(); __fpr = __fp; } else { // Installing a newly created facet into an empty // _M_facets container, say a newly-constructed, // swanky-fresh _Impl. _M_facets[__index] = __fp; } // Ideally, it would be nice to only remove the caches that // are now incorrect. However, some of the caches depend on // multiple facets, and we only know about one facet // here. It's no great loss: the first use of the new facet // will create a new, correctly cached facet anyway. for (size_t __i = 0; __i < _M_facets_size; ++__i) { const facet* __cpr = _M_caches[__i]; if (__cpr) { __cpr->_M_remove_reference(); _M_caches[__i] = 0; } } } } } // namespace std