source: trunk/gcc/libstdc++-v3/src/locale.cc

Last change on this file was 1392, checked in by bird, 21 years ago

This commit was generated by cvs2svn to compensate for changes in r1391,
which included commits to RCS files with non-trunk default branches.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 14.7 KB
Line 
1// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003
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 <cctype>
32#include <cwctype> // For towupper, etc.
33#include <locale>
34#include <bits/atomicity.h>
35
36namespace __gnu_cxx
37{
38 // Defined in globals.cc.
39 extern std::locale c_locale;
40 extern std::locale::_Impl c_locale_impl;
41} // namespace __gnu_cxx
42
43namespace std
44{
45 using namespace __gnu_cxx;
46
47 // Definitions for static const data members of locale.
48 const locale::category locale::none;
49 const locale::category locale::ctype;
50 const locale::category locale::numeric;
51 const locale::category locale::collate;
52 const locale::category locale::time;
53 const locale::category locale::monetary;
54 const locale::category locale::messages;
55 const locale::category locale::all;
56
57 // In the future, GLIBCXX_ABI > 5 should remove all uses of
58 // _GLIBCPP_ASM_SYMVER in this file, and remove exports of any
59 // static data members of locale.
60 locale::_Impl* locale::_S_classic;
61 locale::_Impl* locale::_S_global;
62 const size_t locale::_S_categories_size;
63 _GLIBCPP_ASM_SYMVER(_ZNSt6locale18_S_categories_sizeE, _ZNSt6locale17_S_num_categoriesE, GLIBCPP_3.2)
64 const size_t locale::_S_extra_categories_size;
65
66 // Definitions for static const data members of locale::id
67 _Atomic_word locale::id::_S_highwater; // init'd to 0 by linker
68
69 // Definitions for static const data members of locale::_Impl
70 const locale::id* const
71 locale::_Impl::_S_id_ctype[] =
72 {
73 &std::ctype<char>::id,
74 &codecvt<char, char, mbstate_t>::id,
75#ifdef _GLIBCPP_USE_WCHAR_T
76 &std::ctype<wchar_t>::id,
77 &codecvt<wchar_t, char, mbstate_t>::id,
78#endif
79 0
80 };
81
82 const locale::id* const
83 locale::_Impl::_S_id_numeric[] =
84 {
85 &num_get<char>::id,
86 &num_put<char>::id,
87 &numpunct<char>::id,
88#ifdef _GLIBCPP_USE_WCHAR_T
89 &num_get<wchar_t>::id,
90 &num_put<wchar_t>::id,
91 &numpunct<wchar_t>::id,
92#endif
93 0
94 };
95
96 const locale::id* const
97 locale::_Impl::_S_id_collate[] =
98 {
99 &std::collate<char>::id,
100#ifdef _GLIBCPP_USE_WCHAR_T
101 &std::collate<wchar_t>::id,
102#endif
103 0
104 };
105
106 const locale::id* const
107 locale::_Impl::_S_id_time[] =
108 {
109 &__timepunct<char>::id,
110 &time_get<char>::id,
111 &time_put<char>::id,
112#ifdef _GLIBCPP_USE_WCHAR_T
113 &__timepunct<wchar_t>::id,
114 &time_get<wchar_t>::id,
115 &time_put<wchar_t>::id,
116#endif
117 0
118 };
119
120 const locale::id* const
121 locale::_Impl::_S_id_monetary[] =
122 {
123 &money_get<char>::id,
124 &money_put<char>::id,
125 &moneypunct<char, false>::id,
126 &moneypunct<char, true >::id,
127#ifdef _GLIBCPP_USE_WCHAR_T
128 &money_get<wchar_t>::id,
129 &money_put<wchar_t>::id,
130 &moneypunct<wchar_t, false>::id,
131 &moneypunct<wchar_t, true >::id,
132#endif
133 0
134 };
135
136 const locale::id* const
137 locale::_Impl::_S_id_messages[] =
138 {
139 &std::messages<char>::id,
140#ifdef _GLIBCPP_USE_WCHAR_T
141 &std::messages<wchar_t>::id,
142#endif
143 0
144 };
145
146 const locale::id* const* const
147 locale::_Impl::_S_facet_categories[] =
148 {
149 // Order must match the decl order in class locale.
150 locale::_Impl::_S_id_ctype,
151 locale::_Impl::_S_id_numeric,
152 locale::_Impl::_S_id_collate,
153 locale::_Impl::_S_id_time,
154 locale::_Impl::_S_id_monetary,
155 locale::_Impl::_S_id_messages,
156 0
157 };
158
159 locale::locale() throw()
160 {
161 _S_initialize();
162 (_M_impl = _S_global)->_M_add_reference();
163 }
164
165 locale::locale(const locale& __other) throw()
166 { (_M_impl = __other._M_impl)->_M_add_reference(); }
167
168 // This is used to initialize global and classic locales, and
169 // assumes that the _Impl objects are constructed correctly.
170 // The lack of a reference increment is intentional.
171 locale::locale(_Impl* __ip) throw() : _M_impl(__ip)
172 { }
173
174 locale::locale(const char* __s)
175 {
176 if (__s)
177 {
178 _S_initialize();
179 if (strcmp(__s, "C") == 0 || strcmp(__s, "POSIX") == 0)
180 (_M_impl = _S_classic)->_M_add_reference();
181 else if (strcmp(__s, "") != 0)
182 _M_impl = new _Impl(__s, 1);
183 else
184 {
185 // Get it from the environment.
186 char* __env = getenv("LC_ALL");
187 // If LC_ALL is set we are done.
188 if (__env && strcmp(__env, "") != 0)
189 {
190 if (strcmp(__env, "C") == 0 || strcmp(__env, "POSIX") == 0)
191 (_M_impl = _S_classic)->_M_add_reference();
192 else
193 _M_impl = new _Impl(__env, 1);
194 }
195 else
196 {
197 string __res;
198 // LANG may set a default different from "C".
199 char* __env = getenv("LANG");
200 if (!__env || strcmp(__env, "") == 0 || strcmp(__env, "C") == 0
201 || strcmp(__env, "POSIX") == 0)
202 __res = "C";
203 else
204 __res = __env;
205
206 // Scan the categories looking for the first one
207 // different from LANG.
208 size_t __i = 0;
209 if (__res == "C")
210 for (; __i < _S_categories_size
211 + _S_extra_categories_size; ++__i)
212 {
213 __env = getenv(_S_categories[__i]);
214 if (__env && strcmp(__env, "") != 0
215 && strcmp(__env, "C") != 0
216 && strcmp(__env, "POSIX") != 0)
217 break;
218 }
219 else
220 for (; __i < _S_categories_size
221 + _S_extra_categories_size; ++__i)
222 {
223 __env = getenv(_S_categories[__i]);
224 if (__env && strcmp(__env, "") != 0
225 && __res != __env)
226 break;
227 }
228
229 // If one is found, build the complete string of
230 // the form LC_CTYPE=xxx;LC_NUMERIC=yyy; and so on...
231 if (__i < _S_categories_size + _S_extra_categories_size)
232 {
233 string __str;
234 for (size_t __j = 0; __j < __i; ++__j)
235 {
236 __str += _S_categories[__j];
237 __str += '=';
238 __str += __res;
239 __str += ';';
240 }
241 __str += _S_categories[__i];
242 __str += '=';
243 __str += __env;
244 __str += ';';
245 __i++;
246 for (; __i < _S_categories_size
247 + _S_extra_categories_size; ++__i)
248 {
249 __env = getenv(_S_categories[__i]);
250 if (!__env || strcmp(__env, "") == 0)
251 {
252 __str += _S_categories[__i];
253 __str += '=';
254 __str += __res;
255 __str += ';';
256 }
257 else if (strcmp(__env, "C") == 0
258 || strcmp(__env, "POSIX") == 0)
259 {
260 __str += _S_categories[__i];
261 __str += "=C;";
262 }
263 else
264 {
265 __str += _S_categories[__i];
266 __str += '=';
267 __str += __env;
268 __str += ';';
269 }
270 }
271 __str.erase(__str.end() - 1);
272 _M_impl = new _Impl(__str.c_str(), 1);
273 }
274 // ... otherwise either an additional instance of
275 // the "C" locale or LANG.
276 else if (__res == "C")
277 (_M_impl = _S_classic)->_M_add_reference();
278 else
279 _M_impl = new _Impl(__res.c_str(), 1);
280 }
281 }
282 }
283 else
284 __throw_runtime_error("attempt to create locale from NULL name");
285 }
286
287 locale::locale(const locale& __base, const char* __s, category __cat)
288 {
289 // NB: There are complicated, yet more efficient ways to do
290 // this. Building up locales on a per-category way is tedious, so
291 // let's do it this way until people complain.
292 locale __add(__s);
293 _M_coalesce(__base, __add, __cat);
294 }
295
296 locale::locale(const locale& __base, const locale& __add, category __cat)
297 { _M_coalesce(__base, __add, __cat); }
298
299 locale::~locale() throw()
300 { _M_impl->_M_remove_reference(); }
301
302 bool
303 locale::operator==(const locale& __rhs) const throw()
304 {
305 string __name = this->name();
306 return (_M_impl == __rhs._M_impl
307 || (__name != "*" && __name == __rhs.name()));
308 }
309
310 const locale&
311 locale::operator=(const locale& __other) throw()
312 {
313 __other._M_impl->_M_add_reference();
314 _M_impl->_M_remove_reference();
315 _M_impl = __other._M_impl;
316 return *this;
317 }
318
319 locale
320 locale::global(const locale& __other)
321 {
322 // XXX MT
323 _S_initialize();
324 _Impl* __old = _S_global;
325 __other._M_impl->_M_add_reference();
326 _S_global = __other._M_impl;
327 if (_S_global->_M_check_same_name()
328 && (strcmp(_S_global->_M_names[0], "*") != 0))
329 setlocale(LC_ALL, __other.name().c_str());
330
331 // Reference count sanity check: one reference removed for the
332 // subsition of __other locale, one added by return-by-value. Net
333 // difference: zero. When the returned locale object's destrutor
334 // is called, then the reference count is decremented and possibly
335 // destroyed.
336 return locale(__old);
337 }
338
339 string
340 locale::name() const
341 {
342 string __ret;
343 if (_M_impl->_M_check_same_name())
344 __ret = _M_impl->_M_names[0];
345 else
346 {
347 __ret += _S_categories[0];
348 __ret += '=';
349 __ret += _M_impl->_M_names[0];
350 for (size_t __i = 1;
351 __i < _S_categories_size + _S_extra_categories_size;
352 ++__i)
353 {
354 __ret += ';';
355 __ret += _S_categories[__i];
356 __ret += '=';
357 __ret += _M_impl->_M_names[__i];
358 }
359 }
360 return __ret;
361 }
362
363 const locale&
364 locale::classic()
365 {
366 // Locking protocol: singleton-called-before-threading-starts
367 if (!_S_classic)
368 {
369 try
370 {
371 // 26 Standard facets, 2 references.
372 // One reference for _S_classic, one for _S_global
373 _S_classic = new (&c_locale_impl) _Impl(0, 2, true);
374 _S_global = _S_classic;
375 new (&c_locale) locale(_S_classic);
376 }
377 catch(...)
378 {
379 // Just call destructor, so that locale_impl_c's memory is
380 // not deallocated via a call to delete.
381 if (_S_classic)
382 _S_classic->~_Impl();
383 _S_classic = _S_global = 0;
384 __throw_exception_again;
385 }
386 }
387 return c_locale;
388 }
389
390 void
391 locale::_M_coalesce(const locale& __base, const locale& __add,
392 category __cat)
393 {
394 __cat = _S_normalize_category(__cat);
395 _M_impl = new _Impl(*__base._M_impl, 1);
396
397 try
398 { _M_impl->_M_replace_categories(__add._M_impl, __cat); }
399 catch (...)
400 {
401 _M_impl->_M_remove_reference();
402 __throw_exception_again;
403 }
404 }
405
406 locale::category
407 locale::_S_normalize_category(category __cat)
408 {
409 int __ret = 0;
410 if (__cat == none || (__cat & all) && !(__cat & ~all))
411 __ret = __cat;
412 else
413 {
414 // NB: May be a C-style "LC_ALL" category; convert.
415 switch (__cat)
416 {
417 case LC_COLLATE:
418 __ret = collate;
419 break;
420 case LC_CTYPE:
421 __ret = ctype;
422 break;
423 case LC_MONETARY:
424 __ret = monetary;
425 break;
426 case LC_NUMERIC:
427 __ret = numeric;
428 break;
429 case LC_TIME:
430 __ret = time;
431 break;
432#ifdef _GLIBCPP_HAVE_LC_MESSAGES
433 case LC_MESSAGES:
434 __ret = messages;
435 break;
436#endif
437 case LC_ALL:
438 __ret = all;
439 break;
440 default:
441 __throw_runtime_error("bad locale category");
442 }
443 }
444 return __ret;
445 }
446
447 __c_locale
448 locale::facet::_S_c_locale;
449
450 char locale::facet::_S_c_name[2];
451
452 locale::facet::
453 ~facet() { }
454
455 locale::facet::
456 facet(size_t __refs) throw() : _M_references(__refs ? 1 : 0)
457 { }
458
459 void
460 locale::facet::
461 _M_add_reference() throw()
462 { __atomic_add(&_M_references, 1); }
463
464 void
465 locale::facet::
466 _M_remove_reference() throw()
467 {
468 if (__exchange_and_add(&_M_references, -1) == 1)
469 {
470 try
471 { delete this; }
472 catch (...)
473 { }
474 }
475 }
476
477 locale::id::id()
478 { }
479
480 // Definitions for static const data members of time_base
481 template<>
482 const char*
483 __timepunct<char>::_S_timezones[14] =
484 {
485 "GMT", "HST", "AKST", "PST", "MST", "CST", "EST", "AST", "NST", "CET",
486 "IST", "EET", "CST", "JST"
487 };
488
489#ifdef _GLIBCPP_USE_WCHAR_T
490 template<>
491 const wchar_t*
492 __timepunct<wchar_t>::_S_timezones[14] =
493 {
494 L"GMT", L"HST", L"AKST", L"PST", L"MST", L"CST", L"EST", L"AST",
495 L"NST", L"CET", L"IST", L"EET", L"CST", L"JST"
496 };
497#endif
498
499 // Definitions for static const data members of money_base
500 const money_base::pattern
501 money_base::_S_default_pattern = { {symbol, sign, none, value} };
502
503 const char* __num_base::_S_atoms_in = "0123456789eEabcdfABCDF";
504 const char* __num_base::_S_atoms_out ="-+xX0123456789abcdef0123456789ABCDEF";
505
506 // _GLIBCPP_RESOLVE_LIB_DEFECTS
507 // According to the resolution of DR 231, about 22.2.2.2.2, p11,
508 // "str.precision() is specified in the conversion specification".
509 void
510 __num_base::_S_format_float(const ios_base& __io, char* __fptr,
511 char __mod, streamsize/* unused post DR 231 */)
512 {
513 ios_base::fmtflags __flags = __io.flags();
514 *__fptr++ = '%';
515 // [22.2.2.2.2] Table 60
516 if (__flags & ios_base::showpos)
517 *__fptr++ = '+';
518 if (__flags & ios_base::showpoint)
519 *__fptr++ = '#';
520
521 // As per DR 231: _always_, not only when
522 // __flags & ios_base::fixed || __prec > 0
523 *__fptr++ = '.';
524 *__fptr++ = '*';
525
526 if (__mod)
527 *__fptr++ = __mod;
528 ios_base::fmtflags __fltfield = __flags & ios_base::floatfield;
529 // [22.2.2.2.2] Table 58
530 if (__fltfield == ios_base::fixed)
531 *__fptr++ = 'f';
532 else if (__fltfield == ios_base::scientific)
533 *__fptr++ = (__flags & ios_base::uppercase) ? 'E' : 'e';
534 else
535 *__fptr++ = (__flags & ios_base::uppercase) ? 'G' : 'g';
536 *__fptr = '\0';
537 }
538
539 void
540 __num_base::_S_format_int(const ios_base& __io, char* __fptr, char __mod,
541 char __modl)
542 {
543 ios_base::fmtflags __flags = __io.flags();
544 *__fptr++ = '%';
545 // [22.2.2.2.2] Table 60
546 if (__flags & ios_base::showpos)
547 *__fptr++ = '+';
548 if (__flags & ios_base::showbase)
549 *__fptr++ = '#';
550 *__fptr++ = 'l';
551
552 // For long long types.
553 if (__modl)
554 *__fptr++ = __modl;
555
556 ios_base::fmtflags __bsefield = __flags & ios_base::basefield;
557 if (__bsefield == ios_base::hex)
558 *__fptr++ = (__flags & ios_base::uppercase) ? 'X' : 'x';
559 else if (__bsefield == ios_base::oct)
560 *__fptr++ = 'o';
561 else
562 *__fptr++ = __mod;
563 *__fptr = '\0';
564 }
565} // namespace std
566
Note: See TracBrowser for help on using the repository browser.