localename.cc revision 132720
1// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 2// Free Software Foundation, Inc. 3// 4// This file is part of the GNU ISO C++ Library. This library is free 5// software; you can redistribute it and/or modify it under the 6// terms of the GNU General Public License as published by the 7// Free Software Foundation; either version 2, or (at your option) 8// any later version. 9 10// This library is distributed in the hope that it will be useful, 11// but WITHOUT ANY WARRANTY; without even the implied warranty of 12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13// GNU General Public License for more details. 14 15// You should have received a copy of the GNU General Public License along 16// with this library; see the file COPYING. If not, write to the Free 17// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 18// USA. 19 20// As a special exception, you may use this file as part of a free software 21// library without restriction. Specifically, if other files instantiate 22// templates or use macros or inline functions from this file, or you compile 23// this file and link it with other files to produce an executable, this 24// file does not by itself cause the resulting executable to be covered by 25// the GNU General Public License. This exception does not however 26// invalidate any other reasons why the executable file might be covered by 27// the GNU General Public License. 28 29#include <clocale> 30#include <cstring> 31#include <locale> 32 33namespace std 34{ 35 using namespace __gnu_cxx; 36 37 38 locale::locale(const char* __s) : _M_impl(0) 39 { 40 if (__s) 41 { 42 _S_initialize(); 43 if (std::strcmp(__s, "C") == 0 || std::strcmp(__s, "POSIX") == 0) 44 (_M_impl = _S_classic)->_M_add_reference(); 45 else if (std::strcmp(__s, "") != 0) 46 _M_impl = new _Impl(__s, 1); 47 else 48 { 49 // Get it from the environment. 50 char* __env = std::getenv("LC_ALL"); 51 // If LC_ALL is set we are done. 52 if (__env && std::strcmp(__env, "") != 0) 53 { 54 if (std::strcmp(__env, "C") == 0 55 || std::strcmp(__env, "POSIX") == 0) 56 (_M_impl = _S_classic)->_M_add_reference(); 57 else 58 _M_impl = new _Impl(__env, 1); 59 } 60 else 61 { 62 // LANG may set a default different from "C". 63 string __res; 64 char* __env = std::getenv("LANG"); 65 if (!__env || std::strcmp(__env, "") == 0 66 || std::strcmp(__env, "C") == 0 67 || std::strcmp(__env, "POSIX") == 0) 68 __res = "C"; 69 else 70 __res = __env; 71 72 // Scan the categories looking for the first one 73 // different from LANG. 74 size_t __i = 0; 75 if (__res == "C") 76 for (; __i < _S_categories_size; ++__i) 77 { 78 __env = std::getenv(_S_categories[__i]); 79 if (__env && std::strcmp(__env, "") != 0 80 && std::strcmp(__env, "C") != 0 81 && std::strcmp(__env, "POSIX") != 0) 82 break; 83 } 84 else 85 for (; __i < _S_categories_size; ++__i) 86 { 87 __env = std::getenv(_S_categories[__i]); 88 if (__env && std::strcmp(__env, "") != 0 89 && __res != __env) 90 break; 91 } 92 93 // If one is found, build the complete string of 94 // the form LC_CTYPE=xxx;LC_NUMERIC=yyy; and so on... 95 if (__i < _S_categories_size) 96 { 97 string __str; 98 for (size_t __j = 0; __j < __i; ++__j) 99 { 100 __str += _S_categories[__j]; 101 __str += '='; 102 __str += __res; 103 __str += ';'; 104 } 105 __str += _S_categories[__i]; 106 __str += '='; 107 __str += __env; 108 __str += ';'; 109 __i++; 110 for (; __i < _S_categories_size; ++__i) 111 { 112 __env = std::getenv(_S_categories[__i]); 113 if (!__env || std::strcmp(__env, "") == 0) 114 { 115 __str += _S_categories[__i]; 116 __str += '='; 117 __str += __res; 118 __str += ';'; 119 } 120 else if (std::strcmp(__env, "C") == 0 121 || std::strcmp(__env, "POSIX") == 0) 122 { 123 __str += _S_categories[__i]; 124 __str += "=C;"; 125 } 126 else 127 { 128 __str += _S_categories[__i]; 129 __str += '='; 130 __str += __env; 131 __str += ';'; 132 } 133 } 134 __str.erase(__str.end() - 1); 135 _M_impl = new _Impl(__str.c_str(), 1); 136 } 137 // ... otherwise either an additional instance of 138 // the "C" locale or LANG. 139 else if (__res == "C") 140 (_M_impl = _S_classic)->_M_add_reference(); 141 else 142 _M_impl = new _Impl(__res.c_str(), 1); 143 } 144 } 145 } 146 else 147 __throw_runtime_error(__N("locale::locale NULL not valid")); 148 } 149 150 locale::locale(const locale& __base, const char* __s, category __cat) 151 : _M_impl(0) 152 { 153 // NB: There are complicated, yet more efficient ways to do 154 // this. Building up locales on a per-category way is tedious, so 155 // let's do it this way until people complain. 156 locale __add(__s); 157 _M_coalesce(__base, __add, __cat); 158 } 159 160 locale::locale(const locale& __base, const locale& __add, category __cat) 161 : _M_impl(0) 162 { _M_coalesce(__base, __add, __cat); } 163 164 void 165 locale::_M_coalesce(const locale& __base, const locale& __add, 166 category __cat) 167 { 168 __cat = _S_normalize_category(__cat); 169 _M_impl = new _Impl(*__base._M_impl, 1); 170 171 try 172 { _M_impl->_M_replace_categories(__add._M_impl, __cat); } 173 catch (...) 174 { 175 _M_impl->_M_remove_reference(); 176 __throw_exception_again; 177 } 178 } 179 180 // Construct named _Impl. 181 locale::_Impl:: 182 _Impl(const char* __s, size_t __refs) 183 : _M_refcount(__refs), _M_facets(0), _M_facets_size(_GLIBCXX_NUM_FACETS), 184 _M_caches(0), _M_names(0) 185 { 186 // Initialize the underlying locale model, which also checks to 187 // see if the given name is valid. 188 __c_locale __cloc; 189 locale::facet::_S_create_c_locale(__cloc, __s); 190 191 try 192 { 193 _M_facets = new const facet*[_M_facets_size]; 194 for (size_t __i = 0; __i < _M_facets_size; ++__i) 195 _M_facets[__i] = 0; 196 _M_caches = new const facet*[_M_facets_size]; 197 for (size_t __j = 0; __j < _M_facets_size; ++__j) 198 _M_caches[__j] = 0; 199 _M_names = new char*[_S_categories_size]; 200 for (size_t __k = 0; __k < _S_categories_size; ++__k) 201 _M_names[__k] = 0; 202 203 // Name all the categories. 204 const size_t __len = std::strlen(__s); 205 if (!std::strchr(__s, ';')) 206 { 207 for (size_t __i = 0; __i < _S_categories_size; ++__i) 208 { 209 _M_names[__i] = new char[__len + 1]; 210 std::strcpy(_M_names[__i], __s); 211 } 212 } 213 else 214 { 215 const char* __beg = __s; 216 for (size_t __i = 0; __i < _S_categories_size; ++__i) 217 { 218 __beg = std::strchr(__beg, '=') + 1; 219 const char* __end = std::strchr(__beg, ';'); 220 if (!__end) 221 __end = __s + __len; 222 char* __new = new char[__end - __beg + 1]; 223 std::memcpy(__new, __beg, __end - __beg); 224 __new[__end - __beg] = '\0'; 225 _M_names[__i] = __new; 226 } 227 } 228 229 // Construct all standard facets and add them to _M_facets. 230 _M_init_facet(new std::ctype<char>(__cloc, 0, false)); 231 _M_init_facet(new codecvt<char, char, mbstate_t>(__cloc)); 232 _M_init_facet(new numpunct<char>(__cloc)); 233 _M_init_facet(new num_get<char>); 234 _M_init_facet(new num_put<char>); 235 _M_init_facet(new std::collate<char>(__cloc)); 236 _M_init_facet(new moneypunct<char, false>(__cloc, __s)); 237 _M_init_facet(new moneypunct<char, true>(__cloc, __s)); 238 _M_init_facet(new money_get<char>); 239 _M_init_facet(new money_put<char>); 240 _M_init_facet(new __timepunct<char>(__cloc, __s)); 241 _M_init_facet(new time_get<char>); 242 _M_init_facet(new time_put<char>); 243 _M_init_facet(new std::messages<char>(__cloc, __s)); 244 245#ifdef _GLIBCXX_USE_WCHAR_T 246 _M_init_facet(new std::ctype<wchar_t>(__cloc)); 247 _M_init_facet(new codecvt<wchar_t, char, mbstate_t>(__cloc)); 248 _M_init_facet(new numpunct<wchar_t>(__cloc)); 249 _M_init_facet(new num_get<wchar_t>); 250 _M_init_facet(new num_put<wchar_t>); 251 _M_init_facet(new std::collate<wchar_t>(__cloc)); 252 _M_init_facet(new moneypunct<wchar_t, false>(__cloc, __s)); 253 _M_init_facet(new moneypunct<wchar_t, true>(__cloc, __s)); 254 _M_init_facet(new money_get<wchar_t>); 255 _M_init_facet(new money_put<wchar_t>); 256 _M_init_facet(new __timepunct<wchar_t>(__cloc, __s)); 257 _M_init_facet(new time_get<wchar_t>); 258 _M_init_facet(new time_put<wchar_t>); 259 _M_init_facet(new std::messages<wchar_t>(__cloc, __s)); 260#endif 261 locale::facet::_S_destroy_c_locale(__cloc); 262 } 263 catch(...) 264 { 265 locale::facet::_S_destroy_c_locale(__cloc); 266 this->~_Impl(); 267 __throw_exception_again; 268 } 269 } 270 271 void 272 locale::_Impl:: 273 _M_replace_categories(const _Impl* __imp, category __cat) 274 { 275 for (size_t __ix = 0; __ix < _S_categories_size; ++__ix) 276 { 277 const category __mask = 1 << __ix; 278 if (__mask & __cat) 279 { 280 // Need to replace entry in _M_facets with other locale's info. 281 _M_replace_category(__imp, _S_facet_categories[__ix]); 282 // If both have names, go ahead and mangle. 283 if (std::strcmp(_M_names[__ix], "*") != 0 284 && std::strcmp(__imp->_M_names[__ix], "*") != 0) 285 { 286 char* __new = new char[std::strlen(__imp->_M_names[__ix]) + 1]; 287 std::strcpy(__new, __imp->_M_names[__ix]); 288 delete [] _M_names[__ix]; 289 _M_names[__ix] = __new; 290 } 291 } 292 } 293 } 294} // namespace std 295