1169691Skan// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 297403Sobrien// Free Software Foundation, Inc. 397403Sobrien// 497403Sobrien// This file is part of the GNU ISO C++ Library. This library is free 597403Sobrien// software; you can redistribute it and/or modify it under the 697403Sobrien// terms of the GNU General Public License as published by the 797403Sobrien// Free Software Foundation; either version 2, or (at your option) 897403Sobrien// any later version. 997403Sobrien 1097403Sobrien// This library is distributed in the hope that it will be useful, 1197403Sobrien// but WITHOUT ANY WARRANTY; without even the implied warranty of 1297403Sobrien// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1397403Sobrien// GNU General Public License for more details. 1497403Sobrien 1597403Sobrien// You should have received a copy of the GNU General Public License along 1697403Sobrien// with this library; see the file COPYING. If not, write to the Free 17169691Skan// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 1897403Sobrien// USA. 1997403Sobrien 2097403Sobrien// As a special exception, you may use this file as part of a free software 2197403Sobrien// library without restriction. Specifically, if other files instantiate 2297403Sobrien// templates or use macros or inline functions from this file, or you compile 2397403Sobrien// this file and link it with other files to produce an executable, this 2497403Sobrien// file does not by itself cause the resulting executable to be covered by 2597403Sobrien// the GNU General Public License. This exception does not however 2697403Sobrien// invalidate any other reasons why the executable file might be covered by 2797403Sobrien// the GNU General Public License. 2897403Sobrien 2997403Sobrien#include <clocale> 3097403Sobrien#include <cstring> 3197403Sobrien#include <locale> 3297403Sobrien 33169691Skan_GLIBCXX_BEGIN_NAMESPACE(std) 34169691Skan 35107606Sobrien using namespace __gnu_cxx; 36107606Sobrien 37132720Skan locale::locale(const char* __s) : _M_impl(0) 3897403Sobrien { 39132720Skan if (__s) 40132720Skan { 41132720Skan _S_initialize(); 42132720Skan if (std::strcmp(__s, "C") == 0 || std::strcmp(__s, "POSIX") == 0) 43132720Skan (_M_impl = _S_classic)->_M_add_reference(); 44132720Skan else if (std::strcmp(__s, "") != 0) 45132720Skan _M_impl = new _Impl(__s, 1); 46132720Skan else 47132720Skan { 48132720Skan // Get it from the environment. 49132720Skan char* __env = std::getenv("LC_ALL"); 50132720Skan // If LC_ALL is set we are done. 51132720Skan if (__env && std::strcmp(__env, "") != 0) 52132720Skan { 53132720Skan if (std::strcmp(__env, "C") == 0 54132720Skan || std::strcmp(__env, "POSIX") == 0) 55132720Skan (_M_impl = _S_classic)->_M_add_reference(); 56132720Skan else 57132720Skan _M_impl = new _Impl(__env, 1); 58132720Skan } 59132720Skan else 60132720Skan { 61132720Skan // LANG may set a default different from "C". 62169691Skan string __lang; 63169691Skan __env = std::getenv("LANG"); 64132720Skan if (!__env || std::strcmp(__env, "") == 0 65132720Skan || std::strcmp(__env, "C") == 0 66132720Skan || std::strcmp(__env, "POSIX") == 0) 67169691Skan __lang = "C"; 68132720Skan else 69169691Skan __lang = __env; 70132720Skan 71132720Skan // Scan the categories looking for the first one 72132720Skan // different from LANG. 73132720Skan size_t __i = 0; 74169691Skan if (__lang == "C") 75132720Skan for (; __i < _S_categories_size; ++__i) 76132720Skan { 77132720Skan __env = std::getenv(_S_categories[__i]); 78132720Skan if (__env && std::strcmp(__env, "") != 0 79132720Skan && std::strcmp(__env, "C") != 0 80132720Skan && std::strcmp(__env, "POSIX") != 0) 81132720Skan break; 82132720Skan } 83132720Skan else 84132720Skan for (; __i < _S_categories_size; ++__i) 85132720Skan { 86132720Skan __env = std::getenv(_S_categories[__i]); 87132720Skan if (__env && std::strcmp(__env, "") != 0 88169691Skan && __lang != __env) 89132720Skan break; 90132720Skan } 91132720Skan 92132720Skan // If one is found, build the complete string of 93132720Skan // the form LC_CTYPE=xxx;LC_NUMERIC=yyy; and so on... 94132720Skan if (__i < _S_categories_size) 95132720Skan { 96132720Skan string __str; 97169691Skan __str.reserve(128); 98132720Skan for (size_t __j = 0; __j < __i; ++__j) 99132720Skan { 100132720Skan __str += _S_categories[__j]; 101132720Skan __str += '='; 102169691Skan __str += __lang; 103132720Skan __str += ';'; 104132720Skan } 105132720Skan __str += _S_categories[__i]; 106132720Skan __str += '='; 107132720Skan __str += __env; 108132720Skan __str += ';'; 109169691Skan ++__i; 110132720Skan for (; __i < _S_categories_size; ++__i) 111132720Skan { 112132720Skan __env = std::getenv(_S_categories[__i]); 113169691Skan __str += _S_categories[__i]; 114132720Skan if (!__env || std::strcmp(__env, "") == 0) 115132720Skan { 116132720Skan __str += '='; 117169691Skan __str += __lang; 118132720Skan __str += ';'; 119132720Skan } 120132720Skan else if (std::strcmp(__env, "C") == 0 121132720Skan || std::strcmp(__env, "POSIX") == 0) 122169691Skan __str += "=C;"; 123132720Skan else 124132720Skan { 125132720Skan __str += '='; 126132720Skan __str += __env; 127132720Skan __str += ';'; 128132720Skan } 129132720Skan } 130132720Skan __str.erase(__str.end() - 1); 131132720Skan _M_impl = new _Impl(__str.c_str(), 1); 132132720Skan } 133132720Skan // ... otherwise either an additional instance of 134132720Skan // the "C" locale or LANG. 135169691Skan else if (__lang == "C") 136132720Skan (_M_impl = _S_classic)->_M_add_reference(); 137132720Skan else 138169691Skan _M_impl = new _Impl(__lang.c_str(), 1); 139132720Skan } 140132720Skan } 141132720Skan } 142132720Skan else 143132720Skan __throw_runtime_error(__N("locale::locale NULL not valid")); 144132720Skan } 145107606Sobrien 146132720Skan locale::locale(const locale& __base, const char* __s, category __cat) 147132720Skan : _M_impl(0) 148132720Skan { 149132720Skan // NB: There are complicated, yet more efficient ways to do 150132720Skan // this. Building up locales on a per-category way is tedious, so 151132720Skan // let's do it this way until people complain. 152132720Skan locale __add(__s); 153132720Skan _M_coalesce(__base, __add, __cat); 15497403Sobrien } 15597403Sobrien 156132720Skan locale::locale(const locale& __base, const locale& __add, category __cat) 157132720Skan : _M_impl(0) 158132720Skan { _M_coalesce(__base, __add, __cat); } 159132720Skan 160132720Skan void 161132720Skan locale::_M_coalesce(const locale& __base, const locale& __add, 162132720Skan category __cat) 16397403Sobrien { 164132720Skan __cat = _S_normalize_category(__cat); 165132720Skan _M_impl = new _Impl(*__base._M_impl, 1); 166132720Skan 167132720Skan try 168132720Skan { _M_impl->_M_replace_categories(__add._M_impl, __cat); } 169132720Skan catch (...) 17097403Sobrien { 171132720Skan _M_impl->_M_remove_reference(); 17297403Sobrien __throw_exception_again; 17397403Sobrien } 17497403Sobrien } 17597403Sobrien 17697403Sobrien // Construct named _Impl. 17797403Sobrien locale::_Impl:: 178169691Skan _Impl(const char* __s, size_t __refs) 179132720Skan : _M_refcount(__refs), _M_facets(0), _M_facets_size(_GLIBCXX_NUM_FACETS), 180169691Skan _M_caches(0), _M_names(0) 18197403Sobrien { 182132720Skan // Initialize the underlying locale model, which also checks to 183132720Skan // see if the given name is valid. 18497403Sobrien __c_locale __cloc; 18597403Sobrien locale::facet::_S_create_c_locale(__cloc, __s); 18697403Sobrien 18797403Sobrien try 188117397Skan { 189132720Skan _M_facets = new const facet*[_M_facets_size]; 190132720Skan for (size_t __i = 0; __i < _M_facets_size; ++__i) 19197403Sobrien _M_facets[__i] = 0; 192132720Skan _M_caches = new const facet*[_M_facets_size]; 193132720Skan for (size_t __j = 0; __j < _M_facets_size; ++__j) 194132720Skan _M_caches[__j] = 0; 195132720Skan _M_names = new char*[_S_categories_size]; 196132720Skan for (size_t __k = 0; __k < _S_categories_size; ++__k) 197132720Skan _M_names[__k] = 0; 19897403Sobrien 199169691Skan // Name the categories. 200132720Skan const size_t __len = std::strlen(__s); 201169691Skan if (!std::memchr(__s, ';', __len)) 202107606Sobrien { 203169691Skan _M_names[0] = new char[__len + 1]; 204169691Skan std::memcpy(_M_names[0], __s, __len + 1); 205107606Sobrien } 206132720Skan else 207107606Sobrien { 208146897Skan const char* __end = __s; 209132720Skan for (size_t __i = 0; __i < _S_categories_size; ++__i) 210132720Skan { 211146897Skan const char* __beg = std::strchr(__end + 1, '=') + 1; 212146897Skan __end = std::strchr(__beg, ';'); 213132720Skan if (!__end) 214132720Skan __end = __s + __len; 215169691Skan _M_names[__i] = new char[__end - __beg + 1]; 216169691Skan std::memcpy(_M_names[__i], __beg, __end - __beg); 217169691Skan _M_names[__i][__end - __beg] = '\0'; 218132720Skan } 219107606Sobrien } 220132720Skan 221132720Skan // Construct all standard facets and add them to _M_facets. 222132720Skan _M_init_facet(new std::ctype<char>(__cloc, 0, false)); 223132720Skan _M_init_facet(new codecvt<char, char, mbstate_t>(__cloc)); 224132720Skan _M_init_facet(new numpunct<char>(__cloc)); 225132720Skan _M_init_facet(new num_get<char>); 226132720Skan _M_init_facet(new num_put<char>); 227132720Skan _M_init_facet(new std::collate<char>(__cloc)); 228132720Skan _M_init_facet(new moneypunct<char, false>(__cloc, __s)); 229132720Skan _M_init_facet(new moneypunct<char, true>(__cloc, __s)); 230132720Skan _M_init_facet(new money_get<char>); 231132720Skan _M_init_facet(new money_put<char>); 232132720Skan _M_init_facet(new __timepunct<char>(__cloc, __s)); 233132720Skan _M_init_facet(new time_get<char>); 234132720Skan _M_init_facet(new time_put<char>); 235132720Skan _M_init_facet(new std::messages<char>(__cloc, __s)); 23697403Sobrien 237132720Skan#ifdef _GLIBCXX_USE_WCHAR_T 238132720Skan _M_init_facet(new std::ctype<wchar_t>(__cloc)); 239132720Skan _M_init_facet(new codecvt<wchar_t, char, mbstate_t>(__cloc)); 240132720Skan _M_init_facet(new numpunct<wchar_t>(__cloc)); 241132720Skan _M_init_facet(new num_get<wchar_t>); 242132720Skan _M_init_facet(new num_put<wchar_t>); 243132720Skan _M_init_facet(new std::collate<wchar_t>(__cloc)); 244132720Skan _M_init_facet(new moneypunct<wchar_t, false>(__cloc, __s)); 245132720Skan _M_init_facet(new moneypunct<wchar_t, true>(__cloc, __s)); 246132720Skan _M_init_facet(new money_get<wchar_t>); 247132720Skan _M_init_facet(new money_put<wchar_t>); 248132720Skan _M_init_facet(new __timepunct<wchar_t>(__cloc, __s)); 249132720Skan _M_init_facet(new time_get<wchar_t>); 250132720Skan _M_init_facet(new time_put<wchar_t>); 251132720Skan _M_init_facet(new std::messages<wchar_t>(__cloc, __s)); 25297403Sobrien#endif 253132720Skan locale::facet::_S_destroy_c_locale(__cloc); 254132720Skan } 255132720Skan catch(...) 256132720Skan { 257132720Skan locale::facet::_S_destroy_c_locale(__cloc); 258132720Skan this->~_Impl(); 259132720Skan __throw_exception_again; 260132720Skan } 26197403Sobrien } 26297403Sobrien 26397403Sobrien void 26497403Sobrien locale::_Impl:: 26597403Sobrien _M_replace_categories(const _Impl* __imp, category __cat) 26697403Sobrien { 267169691Skan category __mask = 1; 268169691Skan const bool __have_names = _M_names[0] && __imp->_M_names[0]; 269169691Skan for (size_t __ix = 0; __ix < _S_categories_size; ++__ix, __mask <<= 1) 27097403Sobrien { 27197403Sobrien if (__mask & __cat) 27297403Sobrien { 27397403Sobrien // Need to replace entry in _M_facets with other locale's info. 27497403Sobrien _M_replace_category(__imp, _S_facet_categories[__ix]); 27597403Sobrien // If both have names, go ahead and mangle. 276169691Skan if (__have_names) 277107606Sobrien { 278169691Skan if (!_M_names[1]) 279169691Skan { 280169691Skan // A full set of _M_names must be prepared, all identical 281169691Skan // to _M_names[0] to begin with. Then, below, a few will 282169691Skan // be replaced by the corresponding __imp->_M_names. I.e., 283169691Skan // not a "simple" locale anymore (see locale::operator==). 284169691Skan const size_t __len = std::strlen(_M_names[0]) + 1; 285169691Skan for (size_t __i = 1; __i < _S_categories_size; ++__i) 286169691Skan { 287169691Skan _M_names[__i] = new char[__len]; 288169691Skan std::memcpy(_M_names[__i], _M_names[0], __len); 289169691Skan } 290169691Skan } 291169691Skan 292169691Skan // FIXME: Hack for libstdc++/29217: the numerical encodings 293169691Skan // of the time and collate categories are swapped vs the 294169691Skan // order of the names in locale::_S_categories. We'd like to 295169691Skan // adjust the former (the latter is dictated by compatibility 296169691Skan // with glibc) but we can't for binary compatibility. 297169691Skan size_t __ix_name = __ix; 298169691Skan if (__ix == 2 || __ix == 3) 299169691Skan __ix_name = 5 - __ix; 300169691Skan 301169691Skan char* __src = __imp->_M_names[__ix_name] ? 302169691Skan __imp->_M_names[__ix_name] : __imp->_M_names[0]; 303169691Skan const size_t __len = std::strlen(__src) + 1; 304169691Skan char* __new = new char[__len]; 305169691Skan std::memcpy(__new, __src, __len); 306169691Skan delete [] _M_names[__ix_name]; 307169691Skan _M_names[__ix_name] = __new; 308107606Sobrien } 30997403Sobrien } 31097403Sobrien } 31197403Sobrien } 312169691Skan 313169691Skan_GLIBCXX_END_NAMESPACE 314