1 // Wrapper for underlying C-language localization -*- C++ -*-
2 
3 // Copyright (C) 2001-2018 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library.  This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
10 
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19 
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23 // <http://www.gnu.org/licenses/>.
24 
25 //
26 // ISO C++ 14882: 22.8  Standard locale categories.
27 //
28 
29 // Written by Benjamin Kosnik <bkoz@redhat.com>
30 
31 #include <locale>
32 #include <stdexcept>
33 #include <limits>
34 #include <algorithm>
35 #include <langinfo.h>
36 #include <bits/c++locale_internal.h>
37 
38 #include <backward/auto_ptr.h>
39 
40 namespace std _GLIBCXX_VISIBILITY(default)
41 {
42 _GLIBCXX_BEGIN_NAMESPACE_VERSION
43 
44   template<>
45     void
__convert_to_v(const char * __s,float & __v,ios_base::iostate & __err,const __c_locale & __cloc)46     __convert_to_v(const char* __s, float& __v, ios_base::iostate& __err,
47 		   const __c_locale& __cloc) throw()
48     {
49       char* __sanity;
50       __v = __strtof_l(__s, &__sanity, __cloc);
51 
52       // _GLIBCXX_RESOLVE_LIB_DEFECTS
53       // 23. Num_get overflow result.
54       if (__sanity == __s || *__sanity != '\0')
55 	{
56 	  __v = 0.0f;
57 	  __err = ios_base::failbit;
58 	}
59       else if (__v == numeric_limits<float>::infinity())
60 	{
61 	  __v = numeric_limits<float>::max();
62 	  __err = ios_base::failbit;
63 	}
64       else if (__v == -numeric_limits<float>::infinity())
65 	{
66 	  __v = -numeric_limits<float>::max();
67 	  __err = ios_base::failbit;
68 	}
69     }
70 
71   template<>
72     void
__convert_to_v(const char * __s,double & __v,ios_base::iostate & __err,const __c_locale & __cloc)73     __convert_to_v(const char* __s, double& __v, ios_base::iostate& __err,
74 		   const __c_locale& __cloc) throw()
75     {
76       char* __sanity;
77       __v = __strtod_l(__s, &__sanity, __cloc);
78 
79       // _GLIBCXX_RESOLVE_LIB_DEFECTS
80       // 23. Num_get overflow result.
81       if (__sanity == __s || *__sanity != '\0')
82 	{
83 	  __v = 0.0;
84 	  __err = ios_base::failbit;
85 	}
86       else if (__v == numeric_limits<double>::infinity())
87 	{
88 	  __v = numeric_limits<double>::max();
89 	  __err = ios_base::failbit;
90 	}
91       else if (__v == -numeric_limits<double>::infinity())
92 	{
93 	  __v = -numeric_limits<double>::max();
94 	  __err = ios_base::failbit;
95 	}
96     }
97 
98   template<>
99     void
__convert_to_v(const char * __s,long double & __v,ios_base::iostate & __err,const __c_locale & __cloc)100     __convert_to_v(const char* __s, long double& __v, ios_base::iostate& __err,
101 		   const __c_locale& __cloc) throw()
102     {
103       char* __sanity;
104 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
105       // Prefer strtold_l, as __strtold_l isn't prototyped in more recent
106       // glibc versions.
107       __v = strtold_l(__s, &__sanity, __cloc);
108 #else
109       __v = __strtold_l(__s, &__sanity, __cloc);
110 #endif
111 
112       // _GLIBCXX_RESOLVE_LIB_DEFECTS
113       // 23. Num_get overflow result.
114       if (__sanity == __s || *__sanity != '\0')
115 	{
116 	  __v = 0.0l;
117 	  __err = ios_base::failbit;
118 	}
119       else if (__v == numeric_limits<long double>::infinity())
120 	{
121 	  __v = numeric_limits<long double>::max();
122 	  __err = ios_base::failbit;
123 	}
124       else if (__v == -numeric_limits<long double>::infinity())
125 	{
126 	  __v = -numeric_limits<long double>::max();
127 	  __err = ios_base::failbit;
128 	}
129     }
130 
131   void
_S_create_c_locale(__c_locale & __cloc,const char * __s,__c_locale __old)132   locale::facet::_S_create_c_locale(__c_locale& __cloc, const char* __s,
133 				    __c_locale __old)
134   {
135     __cloc = __newlocale(1 << LC_ALL, __s, __old);
136     if (!__cloc)
137       {
138 	// This named locale is not supported by the underlying OS.
139 	__throw_runtime_error(__N("locale::facet::_S_create_c_locale "
140 				  "name not valid"));
141       }
142   }
143 
144   void
_S_destroy_c_locale(__c_locale & __cloc)145   locale::facet::_S_destroy_c_locale(__c_locale& __cloc)
146   {
147     if (__cloc && _S_get_c_locale() != __cloc)
148       __freelocale(__cloc);
149   }
150 
151   __c_locale
_S_clone_c_locale(__c_locale & __cloc)152   locale::facet::_S_clone_c_locale(__c_locale& __cloc) throw()
153   { return __duplocale(__cloc); }
154 
155   __c_locale
_S_lc_ctype_c_locale(__c_locale __cloc,const char * __s)156   locale::facet::_S_lc_ctype_c_locale(__c_locale __cloc, const char* __s)
157   {
158     __c_locale __dup = __duplocale(__cloc);
159     if (__dup == __c_locale(0))
160       __throw_runtime_error(__N("locale::facet::_S_lc_ctype_c_locale "
161 				"duplocale error"));
162 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
163     __c_locale __changed = __newlocale(LC_CTYPE_MASK, __s, __dup);
164 #else
165     __c_locale __changed = __newlocale(1 << LC_CTYPE, __s, __dup);
166 #endif
167     if (__changed == __c_locale(0))
168       {
169 	__freelocale(__dup);
170 	__throw_runtime_error(__N("locale::facet::_S_lc_ctype_c_locale "
171 				  "newlocale error"));
172       }
173     return __changed;
174   }
175 
176   struct _CatalogIdComp
177   {
178     bool
operator ()std::_CatalogIdComp179     operator()(messages_base::catalog __cat, const Catalog_info* __info) const
180     { return __cat < __info->_M_id; }
181 
182     bool
operator ()std::_CatalogIdComp183     operator()(const Catalog_info* __info, messages_base::catalog __cat) const
184     { return __info->_M_id < __cat; }
185   };
186 
~Catalogs()187   Catalogs::~Catalogs()
188   {
189     for (vector<Catalog_info*>::iterator __it = _M_infos.begin();
190 	 __it != _M_infos.end(); ++__it)
191       delete *__it;
192   }
193 
194   messages_base::catalog
_M_add(const char * __domain,locale __l)195   Catalogs::_M_add(const char* __domain, locale __l)
196   {
197     __gnu_cxx::__scoped_lock lock(_M_mutex);
198 
199     // The counter is not likely to roll unless catalogs keep on being
200     // opened/closed which is consider as an application mistake for the
201     // moment.
202     if (_M_catalog_counter == numeric_limits<messages_base::catalog>::max())
203       return -1;
204 
205     auto_ptr<Catalog_info> info(new Catalog_info(_M_catalog_counter++,
206 						 __domain, __l));
207 
208     // Check if we managed to allocate memory for domain.
209     if (!info->_M_domain)
210       return -1;
211 
212     _M_infos.push_back(info.get());
213     return info.release()->_M_id;
214   }
215 
216   void
_M_erase(messages_base::catalog __c)217   Catalogs::_M_erase(messages_base::catalog __c)
218   {
219     __gnu_cxx::__scoped_lock lock(_M_mutex);
220 
221     vector<Catalog_info*>::iterator __res =
222       lower_bound(_M_infos.begin(), _M_infos.end(), __c, _CatalogIdComp());
223     if (__res == _M_infos.end() || (*__res)->_M_id != __c)
224       return;
225 
226     delete *__res;
227     _M_infos.erase(__res);
228 
229     // Just in case closed catalog was the last open.
230     if (__c == _M_catalog_counter - 1)
231       --_M_catalog_counter;
232   }
233 
234   const Catalog_info*
_M_get(messages_base::catalog __c) const235   Catalogs::_M_get(messages_base::catalog __c) const
236   {
237     __gnu_cxx::__scoped_lock lock(_M_mutex);
238 
239     vector<Catalog_info*>::const_iterator __res =
240       lower_bound(_M_infos.begin(), _M_infos.end(), __c, _CatalogIdComp());
241 
242     if (__res != _M_infos.end() && (*__res)->_M_id == __c)
243       return *__res;
244 
245     return 0;
246   }
247 
248   Catalogs&
get_catalogs()249   get_catalogs()
250   {
251     static Catalogs __catalogs;
252     return __catalogs;
253   }
254 
255 _GLIBCXX_END_NAMESPACE_VERSION
256 } // namespace
257 
258 namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
259 {
260 _GLIBCXX_BEGIN_NAMESPACE_VERSION
261 
262   const char* const category_names[6 + _GLIBCXX_NUM_CATEGORIES] =
263     {
264       "LC_CTYPE",
265       "LC_NUMERIC",
266       "LC_TIME",
267       "LC_COLLATE",
268       "LC_MONETARY",
269       "LC_MESSAGES",
270       "LC_PAPER",
271       "LC_NAME",
272       "LC_ADDRESS",
273       "LC_TELEPHONE",
274       "LC_MEASUREMENT",
275       "LC_IDENTIFICATION"
276     };
277 
278 _GLIBCXX_END_NAMESPACE_VERSION
279 } // namespace
280 
281 namespace std _GLIBCXX_VISIBILITY(default)
282 {
283 _GLIBCXX_BEGIN_NAMESPACE_VERSION
284 
285   const char* const* const locale::_S_categories = __gnu_cxx::category_names;
286 
287 _GLIBCXX_END_NAMESPACE_VERSION
288 } // namespace
289 
290 // XXX GLIBCXX_ABI Deprecated
291 #ifdef _GLIBCXX_LONG_DOUBLE_COMPAT
292 #pragma GCC diagnostic ignored "-Wattribute-alias"
293 #define _GLIBCXX_LDBL_COMPAT(dbl, ldbl) \
294   extern "C" void ldbl (void) __attribute__ ((alias (#dbl)))
295 _GLIBCXX_LDBL_COMPAT(_ZSt14__convert_to_vIdEvPKcRT_RSt12_Ios_IostateRKP15__locale_struct, _ZSt14__convert_to_vIeEvPKcRT_RSt12_Ios_IostateRKP15__locale_struct);
296 #endif // _GLIBCXX_LONG_DOUBLE_COMPAT
297