1 // Wrapper for underlying C-language localization -*- C++ -*-
2 
3 // Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
4 // Free Software Foundation, Inc.
5 //
6 // This file is part of the GNU ISO C++ Library.  This library is free
7 // software; you can redistribute it and/or modify it under the
8 // terms of the GNU General Public License as published by the
9 // Free Software Foundation; either version 3, or (at your option)
10 // any later version.
11 
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 // GNU General Public License for more details.
16 
17 // Under Section 7 of GPL version 3, you are granted additional
18 // permissions described in the GCC Runtime Library Exception, version
19 // 3.1, as published by the Free Software Foundation.
20 
21 // You should have received a copy of the GNU General Public License and
22 // a copy of the GCC Runtime Library Exception along with this program;
23 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24 // <http://www.gnu.org/licenses/>.
25 
26 //
27 // ISO C++ 14882: 22.8  Standard locale categories.
28 //
29 
30 // Written by Benjamin Kosnik <bkoz@redhat.com>
31 
32 #include <cerrno>  // For errno
33 #include <cmath>  // For isinf, finite, finitef, fabs
34 #include <cstdlib>  // For strof, strtold
35 #include <cstring>
36 #include <cstdio>
37 #include <locale>
38 #include <limits>
39 
40 #ifdef _GLIBCXX_HAVE_IEEEFP_H
41 #include <ieeefp.h>
42 #endif
43 
44 namespace std _GLIBCXX_VISIBILITY(default)
45 {
46 _GLIBCXX_BEGIN_NAMESPACE_VERSION
47 
48   template<>
49     void
50     __convert_to_v(const char* __s, float& __v, ios_base::iostate& __err,
51 		   const __c_locale&) throw()
52     {
53       // Assumes __s formatted for "C" locale.
54       char* __old = setlocale(LC_ALL, 0);
55       const size_t __len = strlen(__old) + 1;
56       char* __sav = new char[__len];
57       memcpy(__sav, __old, __len);
58       setlocale(LC_ALL, "C");
59       char* __sanity;
60       bool __overflow = false;
61 
62 #if !__FLT_HAS_INFINITY__
63       errno = 0;
64 #endif
65 
66 #ifdef _GLIBCXX_HAVE_STRTOF
67       __v = strtof(__s, &__sanity);
68 #else
69       double __d = strtod(__s, &__sanity);
70       __v = static_cast<float>(__d);
71 #ifdef _GLIBCXX_HAVE_FINITEF
72       if (!finitef (__v))
73 	__overflow = true;
74 #elif defined (_GLIBCXX_HAVE_FINITE)
75       if (!finite (static_cast<double> (__v)))
76 	__overflow = true;
77 #elif defined (_GLIBCXX_HAVE_ISINF)
78       if (isinf (static_cast<double> (__v)))
79 	__overflow = true;
80 #else
81       if (fabs(__d) > numeric_limits<float>::max())
82 	__overflow = true;
83 #endif
84 #endif // _GLIBCXX_HAVE_STRTOF
85 
86       // _GLIBCXX_RESOLVE_LIB_DEFECTS
87       // 23. Num_get overflow result.
88       if (__sanity == __s || *__sanity != '\0')
89 	{
90 	  __v = 0.0f;
91 	  __err = ios_base::failbit;
92 	}
93       else if (__overflow
94 #if __FLT_HAS_INFINITY__
95 	       || __v == numeric_limits<float>::infinity()
96 	       || __v == -numeric_limits<float>::infinity()
97 #else
98 	       || ((__v > 1.0f || __v < -1.0f) && errno == ERANGE)
99 #endif
100 	      )
101 	{
102 	  if (__v > 0.0f)
103 	    __v = numeric_limits<float>::max();
104 	  else
105 	    __v = -numeric_limits<float>::max();
106 	  __err = ios_base::failbit;
107 	}
108 
109       setlocale(LC_ALL, __sav);
110       delete [] __sav;
111     }
112 
113   template<>
114     void
115     __convert_to_v(const char* __s, double& __v, ios_base::iostate& __err,
116 		   const __c_locale&) throw()
117     {
118       // Assumes __s formatted for "C" locale.
119       char* __old = setlocale(LC_ALL, 0);
120       const size_t __len = strlen(__old) + 1;
121       char* __sav = new char[__len];
122       memcpy(__sav, __old, __len);
123       setlocale(LC_ALL, "C");
124       char* __sanity;
125 
126 #if !__DBL_HAS_INFINITY__
127       errno = 0;
128 #endif
129 
130       __v = strtod(__s, &__sanity);
131 
132       // _GLIBCXX_RESOLVE_LIB_DEFECTS
133       // 23. Num_get overflow result.
134       if (__sanity == __s || *__sanity != '\0')
135 	{
136 	  __v = 0.0;
137 	  __err = ios_base::failbit;
138 	}
139       else if (
140 #if __DBL_HAS_INFINITY__
141 	       __v == numeric_limits<double>::infinity()
142 	       || __v == -numeric_limits<double>::infinity())
143 #else
144 	       (__v > 1.0 || __v < -1.0) && errno == ERANGE)
145 #endif
146 	{
147 	  if (__v > 0.0)
148 	    __v = numeric_limits<double>::max();
149 	  else
150 	    __v = -numeric_limits<double>::max();
151 	  __err = ios_base::failbit;
152 	}
153 
154       setlocale(LC_ALL, __sav);
155       delete [] __sav;
156     }
157 
158   template<>
159     void
160     __convert_to_v(const char* __s, long double& __v,
161 		   ios_base::iostate& __err, const __c_locale&) throw()
162     {
163       // Assumes __s formatted for "C" locale.
164       char* __old = setlocale(LC_ALL, 0);
165       const size_t __len = strlen(__old) + 1;
166       char* __sav = new char[__len];
167       memcpy(__sav, __old, __len);
168       setlocale(LC_ALL, "C");
169 
170 #if !__LDBL_HAS_INFINITY__
171       errno = 0;
172 #endif
173 
174 #if defined(_GLIBCXX_HAVE_STRTOLD) && !defined(_GLIBCXX_HAVE_BROKEN_STRTOLD)
175       char* __sanity;
176       __v = strtold(__s, &__sanity);
177 
178       // _GLIBCXX_RESOLVE_LIB_DEFECTS
179       // 23. Num_get overflow result.
180       if (__sanity == __s || *__sanity != '\0')
181 #else
182       typedef char_traits<char>::int_type int_type;
183       int __p = sscanf(__s, "%Lf", &__v);
184 
185       if (!__p || static_cast<int_type>(__p) == char_traits<char>::eof())
186 #endif
187 	{
188 	  __v = 0.0l;
189 	  __err = ios_base::failbit;
190 	}
191        else if (
192 #if __LDBL_HAS_INFINITY__
193 		__v == numeric_limits<long double>::infinity()
194 		|| __v == -numeric_limits<long double>::infinity())
195 #else
196 		(__v > 1.0l || __v < -1.0l) && errno == ERANGE)
197 #endif
198 	{
199 	  if (__v > 0.0l)
200 	    __v = numeric_limits<long double>::max();
201 	  else
202 	    __v = -numeric_limits<long double>::max();
203 	  __err = ios_base::failbit;
204 	}
205 
206       setlocale(LC_ALL, __sav);
207       delete [] __sav;
208     }
209 
210 
211   /*  DragonFly's implementation of setlocale won't accept something like
212       "de_DE".  According to nls manpage, the expected format is:
213       language[_territory][.codeset][@modifier], but it seems that both
214       the _territory and .codeset components are required.
215 
216       As an attempt to correct for this, we'll tack on ".UTF-8" if
217       a period is not detected in the locale string.
218 
219       There are no locales with modifiers on DragonFly so if found, they
220       will just be stripped off silently.  e.g "de_DE@euro" will be reduced
221       to "de_DE".  The UTF-8 default would be added after that.
222   */
223 
224   void
225   locale::facet::_S_create_c_locale(__c_locale& __cloc, const char* __s,
226 				    __c_locale)
227   {
228     const size_t size__s = (__s == NULL) ? 1 : strlen (__s);
229     const char UTF8[] = ".UTF-8";
230     char localspec[size__s + 6 + 1];
231 
232     if (__s == NULL) {
233        localspec[0] = '\0';
234     } else {
235        strcpy (localspec, __s);
236        char * pch = strchr (localspec, '@');
237        if (pch != NULL)
238           *pch = 0;
239 
240        if (  (strchr (__s, '.') == NULL)
241           && (strcmp (__s, "C") != 0)
242           && (strcmp (__s, "POSIX") != 0))
243           strncat (localspec, UTF8, 6);
244     }
245 
246     const char * result = std::setlocale(LC_ALL, localspec);
247 
248     if ((strcmp(result, "C") != 0) && (strcmp (result, localspec) != 0))
249       __throw_runtime_error(__N("locale::facet::_S_create_c_locale "
250 			    "name not valid"));
251     __cloc = 0;
252   }
253 
254   void
255   locale::facet::_S_destroy_c_locale(__c_locale& __cloc)
256   { __cloc = 0; }
257 
258   __c_locale
259   locale::facet::_S_clone_c_locale(__c_locale&) throw()
260   { return __c_locale(); }
261 
262   __c_locale
263   locale::facet::_S_lc_ctype_c_locale(__c_locale, const char*)
264   { return __c_locale(); }
265 
266 _GLIBCXX_END_NAMESPACE_VERSION
267 } // namespace
268 
269 namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
270 {
271 _GLIBCXX_BEGIN_NAMESPACE_VERSION
272 
273   const char* const category_names[6 + _GLIBCXX_NUM_CATEGORIES] =
274     {
275       "LC_CTYPE",
276       "LC_NUMERIC",
277       "LC_TIME",
278       "LC_COLLATE",
279       "LC_MONETARY",
280       "LC_MESSAGES"
281     };
282 
283 _GLIBCXX_END_NAMESPACE_VERSION
284 } // namespace
285 
286 namespace std _GLIBCXX_VISIBILITY(default)
287 {
288 _GLIBCXX_BEGIN_NAMESPACE_VERSION
289 
290   const char* const* const locale::_S_categories = __gnu_cxx::category_names;
291 
292 _GLIBCXX_END_NAMESPACE_VERSION
293 } // namespace
294 
295 // XXX GLIBCXX_ABI Deprecated
296 #ifdef _GLIBCXX_LONG_DOUBLE_COMPAT
297 #define _GLIBCXX_LDBL_COMPAT(dbl, ldbl) \
298   extern "C" void ldbl (void) __attribute__ ((alias (#dbl)))
299 _GLIBCXX_LDBL_COMPAT(_ZSt14__convert_to_vIdEvPKcRT_RSt12_Ios_IostateRKPi, _ZSt14__convert_to_vIeEvPKcRT_RSt12_Ios_IostateRKPi);
300 #endif // _GLIBCXX_LONG_DOUBLE_COMPAT
301