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