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