localename.cc revision 117397
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 <locale>
32
33namespace __gnu_cxx
34{
35  using namespace std;
36
37  // Defined in globals.cc.
38  extern locale::facet* facet_vec[_GLIBCPP_NUM_FACETS];
39  extern locale::facet* facet_cache_vec[2 * _GLIBCPP_NUM_FACETS];
40  extern char* facet_name[6 + _GLIBCPP_NUM_CATEGORIES];
41
42  extern std::ctype<char>			ctype_c;
43  extern std::collate<char> 			collate_c;
44  extern numpunct<char> 			numpunct_c;
45  extern num_get<char> 				num_get_c;
46  extern num_put<char> 				num_put_c;
47  extern codecvt<char, char, mbstate_t>		codecvt_c;
48  extern moneypunct<char, false> 		moneypunct_fc;
49  extern moneypunct<char, true> 		moneypunct_tc;
50  extern money_get<char> 			money_get_c;
51  extern money_put<char> 			money_put_c;
52  extern __timepunct<char> 			timepunct_c;
53  extern time_get<char> 			time_get_c;
54  extern time_put<char> 			time_put_c;
55  extern std::messages<char> 			messages_c;
56#ifdef  _GLIBCPP_USE_WCHAR_T
57  extern std::ctype<wchar_t>			ctype_w;
58  extern std::collate<wchar_t> 			collate_w;
59  extern numpunct<wchar_t> 			numpunct_w;
60  extern num_get<wchar_t> 			num_get_w;
61  extern num_put<wchar_t> 			num_put_w;
62  extern codecvt<wchar_t, char, mbstate_t>	codecvt_w;
63  extern moneypunct<wchar_t, false> 		moneypunct_fw;
64  extern moneypunct<wchar_t, true> 		moneypunct_tw;
65  extern money_get<wchar_t> 			money_get_w;
66  extern money_put<wchar_t> 			money_put_w;
67  extern __timepunct<wchar_t> 			timepunct_w;
68  extern time_get<wchar_t> 			time_get_w;
69  extern time_put<wchar_t> 			time_put_w;
70  extern std::messages<wchar_t> 		messages_w;
71#endif
72
73  extern std::__locale_cache<numpunct<char> >	locale_cache_np_c;
74#ifdef  _GLIBCPP_USE_WCHAR_T
75  extern std::__locale_cache<numpunct<wchar_t> >	locale_cache_np_w;
76#endif
77} // namespace __gnu_cxx
78
79namespace std
80{
81  using namespace __gnu_cxx;
82
83  locale::_Impl::
84  ~_Impl() throw()
85  {
86    // Clean up facets, then caches.  No cache refcounts for now.
87    for (size_t __i = 0; __i < _M_facets_size; ++__i)
88      if (_M_facets[__i])
89	_M_facets[__i]->_M_remove_reference();
90    for (size_t __i = _M_facets_size; __i < 2*_M_facets_size; ++__i)
91      if (_M_facets[__i])
92	delete (__locale_cache_base*)_M_facets[__i];
93    delete [] _M_facets;
94
95    for (size_t __i = 0;
96	 __i < _S_categories_size + _S_extra_categories_size; ++__i)
97      delete [] _M_names[__i];
98  }
99
100  // Clone existing _Impl object.
101  locale::_Impl::
102  _Impl(const _Impl& __imp, size_t __refs)
103  : _M_references(__refs), _M_facets_size(__imp._M_facets_size) // XXX
104  {
105    try
106      {
107	// Space for facets and matching caches
108	_M_facets = new facet*[2*_M_facets_size];
109	for (size_t __i = 0; __i < 2*_M_facets_size; ++__i)
110	  _M_facets[__i] = 0;
111      }
112    catch(...)
113      {
114	delete [] _M_facets;
115	__throw_exception_again;
116      }
117    for (size_t __i = 0; __i < _M_facets_size; ++__i)
118      {
119	_M_facets[__i] = __imp._M_facets[__i];
120	if (_M_facets[__i])
121	  _M_facets[__i]->_M_add_reference();
122      }
123    for (size_t __i = 0;
124	 __i < _S_categories_size + _S_extra_categories_size; ++__i)
125      {
126	char* __new = new char[strlen(__imp._M_names[__i]) + 1];
127	strcpy(__new, __imp._M_names[__i]);
128	_M_names[__i] = __new;
129      }
130  }
131
132  // Construct named _Impl.
133  locale::_Impl::
134  _Impl(const char* __s, size_t __refs)
135  : _M_references(__refs), _M_facets_size(_GLIBCPP_NUM_FACETS)
136  {
137    // Initialize the underlying locale model, which also checks
138    // to see if the given name is valid.
139    __c_locale __cloc;
140    locale::facet::_S_create_c_locale(__cloc, __s);
141
142    try
143      {
144	// Space for facets and matching caches
145	_M_facets = new facet*[2*_M_facets_size];
146	for (size_t __i = 0; __i < 2*_M_facets_size; ++__i)
147	  _M_facets[__i] = 0;
148      }
149    catch(...)
150      {
151	delete [] _M_facets;
152	__throw_exception_again;
153      }
154
155    // Name all the categories.
156    size_t __len = strlen(__s);
157    if (!strchr(__s, ';'))
158      {
159	for (size_t __i = 0;
160	     __i < _S_categories_size + _S_extra_categories_size; ++__i)
161	  {
162	    _M_names[__i] = new char[__len + 1];
163	    strcpy(_M_names[__i], __s);
164	  }
165      }
166    else
167      {
168	const char* __beg = __s;
169	for (size_t __i = 0;
170	     __i < _S_categories_size + _S_extra_categories_size; ++__i)
171	  {
172	    __beg = strchr(__beg, '=') + 1;
173	    const char* __end = strchr(__beg, ';');
174	    if (!__end)
175	      __end = __s + __len;
176	    char* __new = new char[__end - __beg + 1];
177	    memcpy(__new, __beg, __end - __beg);
178	    __new[__end - __beg] = '\0';
179	    _M_names[__i] = __new;
180	  }
181      }
182
183    // Construct all standard facets and add them to _M_facets.
184    _M_init_facet(new std::ctype<char>(__cloc, 0, false));
185    _M_init_facet(new codecvt<char, char, mbstate_t>);
186    _M_init_facet(new numpunct<char>(__cloc));
187    _M_init_facet(new num_get<char>);
188    _M_init_facet(new num_put<char>);
189    _M_init_facet(new std::collate<char>(__cloc));
190    _M_init_facet(new moneypunct<char, false>(__cloc, __s));
191    _M_init_facet(new moneypunct<char, true>(__cloc, __s));
192    _M_init_facet(new money_get<char>);
193    _M_init_facet(new money_put<char>);
194    _M_init_facet(new __timepunct<char>(__cloc, __s));
195    _M_init_facet(new time_get<char>);
196    _M_init_facet(new time_put<char>);
197    _M_init_facet(new std::messages<char>(__cloc, __s));
198
199#ifdef  _GLIBCPP_USE_WCHAR_T
200    _M_init_facet(new std::ctype<wchar_t>(__cloc));
201    _M_init_facet(new codecvt<wchar_t, char, mbstate_t>);
202    _M_init_facet(new numpunct<wchar_t>(__cloc));
203    _M_init_facet(new num_get<wchar_t>);
204    _M_init_facet(new num_put<wchar_t>);
205    _M_init_facet(new std::collate<wchar_t>(__cloc));
206    _M_init_facet(new moneypunct<wchar_t, false>(__cloc, __s));
207    _M_init_facet(new moneypunct<wchar_t, true>(__cloc, __s));
208    _M_init_facet(new money_get<wchar_t>);
209    _M_init_facet(new money_put<wchar_t>);
210    _M_init_facet(new __timepunct<wchar_t>(__cloc, __s));
211    _M_init_facet(new time_get<wchar_t>);
212    _M_init_facet(new time_put<wchar_t>);
213    _M_init_facet(new std::messages<wchar_t>(__cloc, __s));
214#endif
215    locale::facet::_S_destroy_c_locale(__cloc);
216  }
217
218  // Construct "C" _Impl.
219  locale::_Impl::
220  _Impl(facet**, size_t __refs, bool)
221  : _M_references(__refs), _M_facets_size(_GLIBCPP_NUM_FACETS)
222  {
223    // Initialize the underlying locale model.
224    locale::facet::_S_c_name[0] = 'C';
225    locale::facet::_S_c_name[1] = '\0';
226    locale::facet::_S_create_c_locale(locale::facet::_S_c_locale,
227				      locale::facet::_S_c_name);
228
229    // Space for facets and matching caches
230    _M_facets = new(&facet_cache_vec) facet*[2*_M_facets_size];
231    for (size_t __i = 0; __i < 2*_M_facets_size; ++__i)
232      _M_facets[__i] = 0;
233
234    // Name all the categories.
235    for (size_t __i = 0;
236	 __i < _S_categories_size + _S_extra_categories_size; ++__i)
237      {
238	_M_names[__i]  = new (&facet_name[__i]) char[2];
239	strcpy(_M_names[__i], locale::facet::_S_c_name);
240      }
241
242    // This is needed as presently the C++ version of "C" locales
243    // != data in the underlying locale model for __timepunct,
244    // numpunct, and moneypunct. Also, the "C" locales must be
245    // constructed in a way such that they are pre-allocated.
246    // NB: Set locale::facets(ref) count to one so that each individual
247    // facet is not destroyed when the locale (and thus locale::_Impl) is
248    // destroyed.
249    _M_init_facet(new (&ctype_c) std::ctype<char>(0, false, 1));
250    _M_init_facet(new (&codecvt_c) codecvt<char, char, mbstate_t>(1));
251    _M_init_facet(new (&numpunct_c) numpunct<char>(1));
252    _M_init_facet(new (&num_get_c) num_get<char>(1));
253    _M_init_facet(new (&num_put_c) num_put<char>(1));
254    _M_init_facet(new (&collate_c) std::collate<char>(1));
255    _M_init_facet(new (&moneypunct_fc) moneypunct<char, false>(1));
256    _M_init_facet(new (&moneypunct_tc) moneypunct<char, true>(1));
257    _M_init_facet(new (&money_get_c) money_get<char>(1));
258    _M_init_facet(new (&money_put_c) money_put<char>(1));
259    _M_init_facet(new (&timepunct_c) __timepunct<char>(1));
260    _M_init_facet(new (&time_get_c) time_get<char>(1));
261    _M_init_facet(new (&time_put_c) time_put<char>(1));
262    _M_init_facet(new (&messages_c) std::messages<char>(1));
263#ifdef  _GLIBCPP_USE_WCHAR_T
264    _M_init_facet(new (&ctype_w) std::ctype<wchar_t>(1));
265    _M_init_facet(new (&codecvt_w) codecvt<wchar_t, char, mbstate_t>(1));
266    _M_init_facet(new (&numpunct_w) numpunct<wchar_t>(1));
267    _M_init_facet(new (&num_get_w) num_get<wchar_t>(1));
268    _M_init_facet(new (&num_put_w) num_put<wchar_t>(1));
269    _M_init_facet(new (&collate_w) std::collate<wchar_t>(1));
270    _M_init_facet(new (&moneypunct_fw) moneypunct<wchar_t, false>(1));
271    _M_init_facet(new (&moneypunct_tw) moneypunct<wchar_t, true>(1));
272    _M_init_facet(new (&money_get_w) money_get<wchar_t>(1));
273    _M_init_facet(new (&money_put_w) money_put<wchar_t>(1));
274    _M_init_facet(new (&timepunct_w) __timepunct<wchar_t>(1));
275    _M_init_facet(new (&time_get_w) time_get<wchar_t>(1));
276    _M_init_facet(new (&time_put_w) time_put<wchar_t>(1));
277    _M_init_facet(new (&messages_w) std::messages<wchar_t>(1));
278#endif
279
280    // Initialize the static locale caches for C locale.
281
282    locale ltmp(this);		// Doesn't bump refcount
283    _M_add_reference();		// Bump so destructor doesn't trash us
284
285    // These need to be built in static allocated memory.  There must
286    // be a better way to do this!
287    __locale_cache<numpunct<char> >* __lc =
288      new (&locale_cache_np_c) __locale_cache<numpunct<char> >(ltmp, true);
289    _M_facets[numpunct<char>::id._M_id() + _M_facets_size] =
290      reinterpret_cast<locale::facet*>(__lc);
291
292#ifdef  _GLIBCPP_USE_WCHAR_T
293    __locale_cache<numpunct<wchar_t> >* __wlc =
294      new (&locale_cache_np_w) __locale_cache<numpunct<wchar_t> >(ltmp, true);
295    _M_facets[numpunct<wchar_t>::id._M_id() + _M_facets_size] =
296      reinterpret_cast<locale::facet*>(__wlc);
297#endif
298  }
299
300  void
301  locale::_Impl::
302  _M_replace_categories(const _Impl* __imp, category __cat)
303  {
304    category __mask;
305    for (size_t __ix = 0; __ix < _S_categories_size; ++__ix)
306      {
307	__mask = 1 << __ix;
308	if (__mask & __cat)
309	  {
310	    // Need to replace entry in _M_facets with other locale's info.
311	    _M_replace_category(__imp, _S_facet_categories[__ix]);
312	    // If both have names, go ahead and mangle.
313	    if (strcmp(_M_names[__ix], "*") != 0
314		&& strcmp(__imp->_M_names[__ix], "*") != 0)
315	      {
316		delete [] _M_names[__ix];
317		char* __new = new char[strlen(__imp->_M_names[__ix]) + 1];
318		strcpy(__new, __imp->_M_names[__ix]);
319		_M_names[__ix] = __new;
320	      }
321	  }
322      }
323  }
324
325  void
326  locale::_Impl::
327  _M_replace_category(const _Impl* __imp, const locale::id* const* __idpp)
328  {
329    for (; *__idpp; ++__idpp)
330      _M_replace_facet(__imp, *__idpp);
331  }
332
333  void
334  locale::_Impl::
335  _M_replace_facet(const _Impl* __imp, const locale::id* __idp)
336  {
337    size_t __index = __idp->_M_id();
338    if ((__index > (__imp->_M_facets_size - 1)) || !__imp->_M_facets[__index])
339      __throw_runtime_error("no locale facet");
340    _M_install_facet(__idp, __imp->_M_facets[__index]);
341  }
342
343  void
344  locale::_Impl::
345  _M_install_facet(const locale::id* __idp, facet* __fp)
346  {
347    if (__fp)
348      {
349	size_t __index = __idp->_M_id();
350
351	// Check size of facet vector to ensure adequate room.
352	if (__index > _M_facets_size - 1)
353	  {
354	    facet** __old = _M_facets;
355	    facet** __new;
356	    const size_t __new_size = __index + 4;
357	    __new = new facet*[2 * __new_size];
358	    for (size_t __i = 0; __i < _M_facets_size; ++__i)
359	      __new[__i] = _M_facets[__i];
360	    for (size_t __i2 = _M_facets_size; __i2 < __new_size; ++__i2)
361	      __new[__i2] = 0;
362	    // Also copy caches and clear extra space
363	    for (size_t __i = 0; __i < _M_facets_size; ++__i)
364	      __new[__i + __new_size] = _M_facets[__i + _M_facets_size];
365	    for (size_t __i2 = _M_facets_size; __i2 < __new_size; ++__i2)
366	      __new[__i2 + __new_size] = 0;
367
368	    _M_facets_size = __new_size;
369	    _M_facets = __new;
370	    delete [] __old;
371	  }
372
373	__fp->_M_add_reference();
374	facet*& __fpr = _M_facets[__index];
375	if (__fpr)
376	  {
377	    // Replacing an existing facet. Order matters.
378	    __fpr->_M_remove_reference();
379	    __fpr = __fp;
380	  }
381	else
382	  {
383	    // Installing a newly created facet into an empty
384	    // _M_facets container, say a newly-constructed,
385	    // swanky-fresh _Impl.
386	    _M_facets[__index] = __fp;
387	  }
388      }
389  }
390} // namespace std
391