1// Wrapper for underlying C-language localization -*- C++ -*-
2
3// Copyright (C) 2014-2015 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 <cerrno>  // For errno
32#include <cmath>  // For isinf, finite, finitef, fabs
33#include <cstdlib>  // For strof, strtold
34#include <cstring>
35#include <cstdio>
36#include <locale>
37#include <limits>
38
39#ifdef _GLIBCXX_HAVE_IEEEFP_H
40#include <ieeefp.h>
41#endif
42
43namespace std _GLIBCXX_VISIBILITY(default)
44{
45_GLIBCXX_BEGIN_NAMESPACE_VERSION
46
47  template<>
48    void
49    __convert_to_v(const char* __s, float& __v, ios_base::iostate& __err,
50		   const __c_locale&) throw()
51    {
52      // Assumes __s formatted for "C" locale.
53      char* __old = setlocale(LC_ALL, 0);
54      const size_t __len = strlen(__old) + 1;
55      char* __sav = new char[__len];
56      memcpy(__sav, __old, __len);
57      setlocale(LC_ALL, "C");
58      char* __sanity;
59      bool __overflow = false;
60
61#if !__FLT_HAS_INFINITY__
62      errno = 0;
63#endif
64
65#ifdef _GLIBCXX_HAVE_STRTOF
66      __v = strtof(__s, &__sanity);
67#else
68      double __d = strtod(__s, &__sanity);
69      __v = static_cast<float>(__d);
70#ifdef _GLIBCXX_HAVE_FINITEF
71      if (!finitef (__v))
72	__overflow = true;
73#elif defined (_GLIBCXX_HAVE_FINITE)
74      if (!finite (static_cast<double> (__v)))
75	__overflow = true;
76#elif defined (_GLIBCXX_HAVE_ISINF)
77      if (isinf (static_cast<double> (__v)))
78	__overflow = true;
79#else
80      if (fabs(__d) > numeric_limits<float>::max())
81	__overflow = true;
82#endif
83#endif // _GLIBCXX_HAVE_STRTOF
84
85      // _GLIBCXX_RESOLVE_LIB_DEFECTS
86      // 23. Num_get overflow result.
87      if (__sanity == __s || *__sanity != '\0')
88	{
89	  __v = 0.0f;
90	  __err = ios_base::failbit;
91	}
92      else if (__overflow
93#if __FLT_HAS_INFINITY__
94	       || __v == numeric_limits<float>::infinity()
95	       || __v == -numeric_limits<float>::infinity()
96#else
97	       || ((__v > 1.0f || __v < -1.0f) && errno == ERANGE)
98#endif
99	      )
100	{
101	  if (__v > 0.0f)
102	    __v = numeric_limits<float>::max();
103	  else
104	    __v = -numeric_limits<float>::max();
105	  __err = ios_base::failbit;
106	}
107
108      setlocale(LC_ALL, __sav);
109      delete [] __sav;
110    }
111
112  template<>
113    void
114    __convert_to_v(const char* __s, double& __v, ios_base::iostate& __err,
115		   const __c_locale&) throw()
116    {
117      // Assumes __s formatted for "C" locale.
118      char* __old = setlocale(LC_ALL, 0);
119      const size_t __len = strlen(__old) + 1;
120      char* __sav = new char[__len];
121      memcpy(__sav, __old, __len);
122      setlocale(LC_ALL, "C");
123      char* __sanity;
124
125#if !__DBL_HAS_INFINITY__
126      errno = 0;
127#endif
128
129      __v = strtod(__s, &__sanity);
130
131      // _GLIBCXX_RESOLVE_LIB_DEFECTS
132      // 23. Num_get overflow result.
133      if (__sanity == __s || *__sanity != '\0')
134	{
135	  __v = 0.0;
136	  __err = ios_base::failbit;
137	}
138      else if (
139#if __DBL_HAS_INFINITY__
140	       __v == numeric_limits<double>::infinity()
141	       || __v == -numeric_limits<double>::infinity())
142#else
143	       (__v > 1.0 || __v < -1.0) && errno == ERANGE)
144#endif
145	{
146	  if (__v > 0.0)
147	    __v = numeric_limits<double>::max();
148	  else
149	    __v = -numeric_limits<double>::max();
150	  __err = ios_base::failbit;
151	}
152
153      setlocale(LC_ALL, __sav);
154      delete [] __sav;
155    }
156
157  template<>
158    void
159    __convert_to_v(const char* __s, long double& __v,
160		   ios_base::iostate& __err, const __c_locale&) throw()
161    {
162      // Assumes __s formatted for "C" locale.
163      char* __old = setlocale(LC_ALL, 0);
164      const size_t __len = strlen(__old) + 1;
165      char* __sav = new char[__len];
166      memcpy(__sav, __old, __len);
167      setlocale(LC_ALL, "C");
168
169#if !__LDBL_HAS_INFINITY__
170      errno = 0;
171#endif
172
173#if defined(_GLIBCXX_HAVE_STRTOLD) && !defined(_GLIBCXX_HAVE_BROKEN_STRTOLD)
174      char* __sanity;
175      __v = strtold(__s, &__sanity);
176
177      // _GLIBCXX_RESOLVE_LIB_DEFECTS
178      // 23. Num_get overflow result.
179      if (__sanity == __s || *__sanity != '\0')
180#else
181      typedef char_traits<char>::int_type int_type;
182      int __p = sscanf(__s, "%Lf", &__v);
183
184      if (!__p || static_cast<int_type>(__p) == char_traits<char>::eof())
185#endif
186	{
187	  __v = 0.0l;
188	  __err = ios_base::failbit;
189	}
190       else if (
191#if __LDBL_HAS_INFINITY__
192		__v == numeric_limits<long double>::infinity()
193		|| __v == -numeric_limits<long double>::infinity())
194#else
195		(__v > 1.0l || __v < -1.0l) && errno == ERANGE)
196#endif
197	{
198	  if (__v > 0.0l)
199	    __v = numeric_limits<long double>::max();
200	  else
201	    __v = -numeric_limits<long double>::max();
202	  __err = ios_base::failbit;
203	}
204
205      setlocale(LC_ALL, __sav);
206      delete [] __sav;
207    }
208
209
210  /*  DragonFly's implementation of setlocale won't accept something like
211      "de_DE".  According to nls manpage, the expected format is:
212      language[_territory][.codeset][@modifier], but it seems that both
213      the _territory and .codeset components are required.
214
215      As an attempt to correct for this, we'll tack on ".UTF-8" if
216      a period is not detected in the locale string.
217
218      There are no locales with modifiers on DragonFly so if found, they
219      will just be stripped off silently.  e.g "de_DE@euro" will be reduced
220      to "de_DE".  The UTF-8 default would be added after that.
221  */
222
223  void
224  locale::facet::_S_create_c_locale(__c_locale& __cloc, const char* __s,
225				    __c_locale)
226  {
227    const size_t size__s = (__s == NULL) ? 1 : strlen (__s);
228    const char UTF8[] = ".UTF-8";
229    char localspec[size__s + 6 + 1];
230
231    if (__s == NULL) {
232       localspec[0] = '\0';
233    } else {
234       strcpy (localspec, __s);
235       char * pch = strchr (localspec, '@');
236       if (pch != NULL)
237          *pch = 0;
238
239       if (  (strchr (__s, '.') == NULL)
240          && (strcmp (__s, "C") != 0)
241          && (strcmp (__s, "POSIX") != 0))
242          strncat (localspec, UTF8, 6);
243    }
244
245    const char * result = std::setlocale(LC_ALL, localspec);
246
247    if ((strcmp(result, "C") != 0) && (strcmp (result, localspec) != 0))
248      __throw_runtime_error(__N("locale::facet::_S_create_c_locale "
249			    "name not valid"));
250    __cloc = 0;
251  }
252
253  void
254  locale::facet::_S_destroy_c_locale(__c_locale& __cloc)
255  { __cloc = 0; }
256
257  __c_locale
258  locale::facet::_S_clone_c_locale(__c_locale&) throw()
259  { return __c_locale(); }
260
261  __c_locale
262  locale::facet::_S_lc_ctype_c_locale(__c_locale, const char*)
263  { return __c_locale(); }
264
265_GLIBCXX_END_NAMESPACE_VERSION
266} // namespace
267
268namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
269{
270_GLIBCXX_BEGIN_NAMESPACE_VERSION
271
272  const char* const category_names[6 + _GLIBCXX_NUM_CATEGORIES] =
273    {
274      "LC_CTYPE",
275      "LC_NUMERIC",
276      "LC_TIME",
277      "LC_COLLATE",
278      "LC_MONETARY",
279      "LC_MESSAGES"
280    };
281
282_GLIBCXX_END_NAMESPACE_VERSION
283} // namespace
284
285namespace std _GLIBCXX_VISIBILITY(default)
286{
287_GLIBCXX_BEGIN_NAMESPACE_VERSION
288
289  const char* const* const locale::_S_categories = __gnu_cxx::category_names;
290
291_GLIBCXX_END_NAMESPACE_VERSION
292} // namespace
293
294// XXX GLIBCXX_ABI Deprecated
295#ifdef _GLIBCXX_LONG_DOUBLE_COMPAT
296#define _GLIBCXX_LDBL_COMPAT(dbl, ldbl) \
297  extern "C" void ldbl (void) __attribute__ ((alias (#dbl)))
298_GLIBCXX_LDBL_COMPAT(_ZSt14__convert_to_vIdEvPKcRT_RSt12_Ios_IostateRKPi, _ZSt14__convert_to_vIeEvPKcRT_RSt12_Ios_IostateRKPi);
299#endif // _GLIBCXX_LONG_DOUBLE_COMPAT
300