1 // 2 // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) 3 // 4 // Distributed under the Boost Software License, Version 1.0. (See 5 // accompanying file LICENSE_1_0.txt or copy at 6 // http://www.boost.org/LICENSE_1_0.txt) 7 // 8 #ifndef BOOST_LOCALE_IMPL_UTIL_NUMERIC_HPP 9 #define BOOST_LOCALE_IMPL_UTIL_NUMERIC_HPP 10 #include <locale> 11 #include <string> 12 #include <ios> 13 #include <boost/locale/formatting.hpp> 14 #include <boost/locale/info.hpp> 15 #include <sstream> 16 #include <vector> 17 #include <ctime> 18 #include <stdlib.h> 19 20 #include "timezone.hpp" 21 22 // This is internal header so disable crappy "unsecure functions" for all 23 #ifdef BOOST_MSVC 24 # pragma warning(disable : 4996) 25 #endif 26 27 28 namespace boost { 29 namespace locale { 30 namespace util { 31 32 template<typename CharType> 33 struct formatting_size_traits { sizeboost::locale::util::formatting_size_traits34 static size_t size(std::basic_string<CharType> const &s,std::locale const &/*l*/) 35 { 36 return s.size(); 37 } 38 }; 39 40 template<> 41 struct formatting_size_traits<char> { sizeboost::locale::util::formatting_size_traits42 static size_t size(std::string const &s,std::locale const &l) 43 { 44 if(!std::has_facet<info>(l)) 45 return s.size(); 46 if(!std::use_facet<info>(l).utf8()) 47 return s.size(); 48 // count code points, poor man's text size 49 size_t res = 0; 50 for(size_t i=0;i<s.size();i++) { 51 unsigned char c = s[i]; 52 if(c <= 127) 53 res ++; 54 else if ((c & 0xC0) == 0xC0) { // first UTF-8 byte 55 res ++; 56 } 57 } 58 return res; 59 } 60 }; 61 62 63 64 template<typename CharType> 65 class base_num_format : public std::num_put<CharType> 66 { 67 public: 68 typedef typename std::num_put<CharType>::iter_type iter_type; 69 typedef std::basic_string<CharType> string_type; 70 typedef CharType char_type; 71 base_num_format(size_t refs=0)72 base_num_format(size_t refs = 0) : 73 std::num_put<CharType>(refs) 74 { 75 } 76 protected: 77 78 do_put(iter_type out,std::ios_base & ios,char_type fill,long val) const79 virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, long val) const 80 { 81 return do_real_put(out,ios,fill,val); 82 } do_put(iter_type out,std::ios_base & ios,char_type fill,unsigned long val) const83 virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, unsigned long val) const 84 { 85 return do_real_put(out,ios,fill,val); 86 } do_put(iter_type out,std::ios_base & ios,char_type fill,double val) const87 virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, double val) const 88 { 89 return do_real_put(out,ios,fill,val); 90 } do_put(iter_type out,std::ios_base & ios,char_type fill,long double val) const91 virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, long double val) const 92 { 93 return do_real_put(out,ios,fill,val); 94 } 95 96 #ifndef BOOST_NO_LONG_LONG do_put(iter_type out,std::ios_base & ios,char_type fill,long long val) const97 virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, long long val) const 98 { 99 return do_real_put(out,ios,fill,val); 100 } do_put(iter_type out,std::ios_base & ios,char_type fill,unsigned long long val) const101 virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, unsigned long long val) const 102 { 103 return do_real_put(out,ios,fill,val); 104 } 105 #endif 106 107 108 private: 109 110 111 112 template<typename ValueType> do_real_put(iter_type out,std::ios_base & ios,char_type fill,ValueType val) const113 iter_type do_real_put (iter_type out, std::ios_base &ios, char_type fill, ValueType val) const 114 { 115 typedef std::num_put<char_type> super; 116 117 ios_info &info=ios_info::get(ios); 118 119 switch(info.display_flags()) { 120 case flags::posix: 121 { 122 typedef std::basic_ostringstream<char_type> sstream_type; 123 sstream_type ss; 124 ss.imbue(std::locale::classic()); 125 ss.flags(ios.flags()); 126 ss.precision(ios.precision()); 127 ss.width(ios.width()); 128 iter_type ret_ptr = super::do_put(out,ss,fill,val); 129 ios.width(0); 130 return ret_ptr; 131 } 132 case flags::date: 133 return format_time(out,ios,fill,static_cast<std::time_t>(val),'x'); 134 case flags::time: 135 return format_time(out,ios,fill,static_cast<std::time_t>(val),'X'); 136 case flags::datetime: 137 return format_time(out,ios,fill,static_cast<std::time_t>(val),'c'); 138 case flags::strftime: 139 return format_time(out,ios,fill,static_cast<std::time_t>(val),info.date_time_pattern<char_type>()); 140 case flags::currency: 141 { 142 bool nat = info.currency_flags()==flags::currency_default 143 || info.currency_flags() == flags::currency_national; 144 bool intl = !nat; 145 return do_format_currency(intl,out,ios,fill,static_cast<long double>(val)); 146 } 147 148 case flags::number: 149 case flags::percent: 150 case flags::spellout: 151 case flags::ordinal: 152 default: 153 return super::do_put(out,ios,fill,val); 154 } 155 } 156 do_format_currency(bool intl,iter_type out,std::ios_base & ios,char_type fill,long double val) const157 virtual iter_type do_format_currency(bool intl,iter_type out,std::ios_base &ios,char_type fill,long double val) const 158 { 159 if(intl) 160 return format_currency<true>(out,ios,fill,val); 161 else 162 return format_currency<false>(out,ios,fill,val); 163 } 164 165 template<bool intl> format_currency(iter_type out,std::ios_base & ios,char_type fill,long double val) const166 iter_type format_currency(iter_type out,std::ios_base &ios,char_type fill,long double val) const 167 { 168 std::locale loc = ios.getloc(); 169 int digits = std::use_facet<std::moneypunct<char_type,intl> >(loc).frac_digits(); 170 while(digits > 0) { 171 val*=10; 172 digits --; 173 } 174 std::ios_base::fmtflags f=ios.flags(); 175 ios.flags(f | std::ios_base::showbase); 176 out = std::use_facet<std::money_put<char_type> >(loc).put(out,intl,ios,fill,val); 177 ios.flags(f); 178 return out; 179 } 180 format_time(iter_type out,std::ios_base & ios,char_type fill,std::time_t time,char c) const181 iter_type format_time(iter_type out,std::ios_base &ios,char_type fill,std::time_t time,char c) const 182 { 183 string_type fmt; 184 fmt+=char_type('%'); 185 fmt+=char_type(c); 186 return format_time(out,ios,fill,time,fmt); 187 } 188 format_time(iter_type out,std::ios_base & ios,char_type fill,std::time_t time,string_type const & format) const189 iter_type format_time(iter_type out,std::ios_base &ios,char_type fill,std::time_t time,string_type const &format) const 190 { 191 std::string tz = ios_info::get(ios).time_zone(); 192 std::tm tm; 193 #if defined(__linux) || defined(__FreeBSD__) || defined(__APPLE__) 194 std::vector<char> tmp_buf(tz.c_str(),tz.c_str()+tz.size()+1); 195 #endif 196 if(tz.empty()) { 197 #ifdef BOOST_WINDOWS 198 /// Windows uses TLS 199 tm = *localtime(&time); 200 #else 201 localtime_r(&time,&tm); 202 #endif 203 } 204 else { 205 int gmtoff = parse_tz(tz); 206 time+=gmtoff; 207 #ifdef BOOST_WINDOWS 208 /// Windows uses TLS 209 tm = *gmtime(&time); 210 #else 211 gmtime_r(&time,&tm); 212 #endif 213 214 #if defined(__linux) || defined(__FreeBSD__) || defined(__APPLE__) 215 // These have extra fields to specify timezone 216 if(gmtoff!=0) { 217 // bsd and apple want tm_zone be non-const 218 tm.tm_zone=&tmp_buf.front(); 219 tm.tm_gmtoff = gmtoff; 220 } 221 #endif 222 } 223 std::basic_ostringstream<char_type> tmp_out; 224 std::use_facet<std::time_put<char_type> >(ios.getloc()).put(tmp_out,tmp_out,fill,&tm,format.c_str(),format.c_str()+format.size()); 225 string_type str = tmp_out.str(); 226 std::streamsize on_left=0,on_right = 0; 227 std::streamsize points = 228 formatting_size_traits<char_type>::size(str,ios.getloc()); 229 if(points < ios.width()) { 230 std::streamsize n = ios.width() - points; 231 232 std::ios_base::fmtflags flags = ios.flags() & std::ios_base::adjustfield; 233 234 // 235 // we do not really know internal point, so we assume that it does not 236 // exist. so according to the standard field should be right aligned 237 // 238 if(flags != std::ios_base::left) 239 on_left = n; 240 on_right = n - on_left; 241 } 242 while(on_left > 0) { 243 *out++ = fill; 244 on_left--; 245 } 246 std::copy(str.begin(),str.end(),out); 247 while(on_right > 0) { 248 *out++ = fill; 249 on_right--; 250 } 251 ios.width(0); 252 return out; 253 } 254 255 }; /// num_format 256 257 258 template<typename CharType> 259 class base_num_parse : public std::num_get<CharType> 260 { 261 public: base_num_parse(size_t refs=0)262 base_num_parse(size_t refs = 0) : 263 std::num_get<CharType>(refs) 264 { 265 } 266 protected: 267 typedef typename std::num_get<CharType>::iter_type iter_type; 268 typedef std::basic_string<CharType> string_type; 269 typedef CharType char_type; 270 do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,long & val) const271 virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,long &val) const 272 { 273 return do_real_get(in,end,ios,err,val); 274 } 275 do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,unsigned short & val) const276 virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,unsigned short &val) const 277 { 278 return do_real_get(in,end,ios,err,val); 279 } 280 do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,unsigned int & val) const281 virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,unsigned int &val) const 282 { 283 return do_real_get(in,end,ios,err,val); 284 } 285 do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,unsigned long & val) const286 virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,unsigned long &val) const 287 { 288 return do_real_get(in,end,ios,err,val); 289 } 290 do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,float & val) const291 virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,float &val) const 292 { 293 return do_real_get(in,end,ios,err,val); 294 } 295 do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,double & val) const296 virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,double &val) const 297 { 298 return do_real_get(in,end,ios,err,val); 299 } 300 do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,long double & val) const301 virtual iter_type do_get (iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,long double &val) const 302 { 303 return do_real_get(in,end,ios,err,val); 304 } 305 306 #ifndef BOOST_NO_LONG_LONG do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,long long & val) const307 virtual iter_type do_get (iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,long long &val) const 308 { 309 return do_real_get(in,end,ios,err,val); 310 } 311 do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,unsigned long long & val) const312 virtual iter_type do_get (iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,unsigned long long &val) const 313 { 314 return do_real_get(in,end,ios,err,val); 315 } 316 317 #endif 318 319 private: 320 321 template<typename ValueType> do_real_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,ValueType & val) const322 iter_type do_real_get(iter_type in,iter_type end,std::ios_base &ios,std::ios_base::iostate &err,ValueType &val) const 323 { 324 typedef std::num_get<char_type> super; 325 326 ios_info &info=ios_info::get(ios); 327 328 switch(info.display_flags()) { 329 case flags::posix: 330 { 331 std::stringstream ss; 332 ss.imbue(std::locale::classic()); 333 ss.flags(ios.flags()); 334 ss.precision(ios.precision()); 335 return super::do_get(in,end,ss,err,val); 336 } 337 case flags::currency: 338 { 339 long double ret_val = 0; 340 if(info.currency_flags()==flags::currency_default || info.currency_flags() == flags::currency_national) 341 in = parse_currency<false>(in,end,ios,err,ret_val); 342 else 343 in = parse_currency<true>(in,end,ios,err,ret_val); 344 if(!(err & std::ios_base::failbit)) 345 val = static_cast<ValueType>(ret_val); 346 return in; 347 } 348 349 // date-time parsing is not supported 350 // due to buggy standard 351 case flags::date: 352 case flags::time: 353 case flags::datetime: 354 case flags::strftime: 355 356 case flags::number: 357 case flags::percent: 358 case flags::spellout: 359 case flags::ordinal: 360 default: 361 return super::do_get(in,end,ios,err,val); 362 } 363 } 364 365 template<bool intl> parse_currency(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,long double & val) const366 iter_type parse_currency(iter_type in,iter_type end,std::ios_base &ios,std::ios_base::iostate &err,long double &val) const 367 { 368 std::locale loc = ios.getloc(); 369 int digits = std::use_facet<std::moneypunct<char_type,intl> >(loc).frac_digits(); 370 long double rval; 371 in = std::use_facet<std::money_get<char_type> >(loc).get(in,end,intl,ios,err,rval); 372 if(!(err & std::ios::failbit)) { 373 while(digits > 0) { 374 rval/=10; 375 digits --; 376 } 377 val = rval; 378 } 379 return in; 380 } 381 382 383 }; 384 385 } // util 386 } // locale 387 } //boost 388 389 390 391 392 #endif 393 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 394