2 // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
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)
8 #ifndef BOOST_LOCALE_IMPL_UTIL_NUMERIC_HPP
9 #define BOOST_LOCALE_IMPL_UTIL_NUMERIC_HPP
13 #include <boost/locale/formatting.hpp>
14 #include <boost/locale/info.hpp>
20 #include "timezone.hpp"
22 // This is internal header so disable crappy "unsecure functions" for all
24 # pragma warning(disable : 4996)
32 template<typename CharType>
33 struct formatting_size_traits {
34 static size_t size(std::basic_string<CharType> const &s,std::locale const &/*l*/)
41 struct formatting_size_traits<char> {
42 static size_t size(std::string const &s,std::locale const &l)
44 if(!std::has_facet<info>(l))
46 if(!std::use_facet<info>(l).utf8())
48 // count code points, poor man's text size
50 for(size_t i=0;i<s.size();i++) {
51 unsigned char c = s[i];
54 else if ((c & 0xC0) == 0xC0) { // first UTF-8 byte
64 template<typename CharType>
65 class base_num_format : public std::num_put<CharType>
68 typedef typename std::num_put<CharType>::iter_type iter_type;
69 typedef std::basic_string<CharType> string_type;
70 typedef CharType char_type;
72 base_num_format(size_t refs = 0) :
73 std::num_put<CharType>(refs)
79 virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, long val) const
81 return do_real_put(out,ios,fill,val);
83 virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, unsigned long val) const
85 return do_real_put(out,ios,fill,val);
87 virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, double val) const
89 return do_real_put(out,ios,fill,val);
91 virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, long double val) const
93 return do_real_put(out,ios,fill,val);
96 #ifndef BOOST_NO_LONG_LONG
97 virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, long long val) const
99 return do_real_put(out,ios,fill,val);
101 virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, unsigned long long val) const
103 return do_real_put(out,ios,fill,val);
112 template<typename ValueType>
113 iter_type do_real_put (iter_type out, std::ios_base &ios, char_type fill, ValueType val) const
115 typedef std::num_put<char_type> super;
117 ios_info &info=ios_info::get(ios);
119 switch(info.display_flags()) {
122 typedef std::basic_ostringstream<char_type> sstream_type;
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);
133 return format_time(out,ios,fill,static_cast<std::time_t>(val),'x');
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:
142 bool nat = info.currency_flags()==flags::currency_default
143 || info.currency_flags() == flags::currency_national;
145 return do_format_currency(intl,out,ios,fill,static_cast<long double>(val));
150 case flags::spellout:
153 return super::do_put(out,ios,fill,val);
157 virtual iter_type do_format_currency(bool intl,iter_type out,std::ios_base &ios,char_type fill,long double val) const
160 return format_currency<true>(out,ios,fill,val);
162 return format_currency<false>(out,ios,fill,val);
166 iter_type format_currency(iter_type out,std::ios_base &ios,char_type fill,long double val) const
168 std::locale loc = ios.getloc();
169 int digits = std::use_facet<std::moneypunct<char_type,intl> >(loc).frac_digits();
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);
181 iter_type format_time(iter_type out,std::ios_base &ios,char_type fill,std::time_t time,char c) const
186 return format_time(out,ios,fill,time,fmt);
189 iter_type format_time(iter_type out,std::ios_base &ios,char_type fill,std::time_t time,string_type const &format) const
191 std::string tz = ios_info::get(ios).time_zone();
193 #if defined(__linux) || defined(__FreeBSD__) || defined(__APPLE__)
194 std::vector<char> tmp_buf(tz.c_str(),tz.c_str()+tz.size()+1);
199 tm = *localtime(&time);
201 localtime_r(&time,&tm);
205 int gmtoff = parse_tz(tz);
214 #if defined(__linux) || defined(__FreeBSD__) || defined(__APPLE__)
215 // These have extra fields to specify timezone
217 // bsd and apple want tm_zone be non-const
218 tm.tm_zone=&tmp_buf.front();
219 tm.tm_gmtoff = gmtoff;
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;
232 std::ios_base::fmtflags flags = ios.flags() & std::ios_base::adjustfield;
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
238 if(flags != std::ios_base::left)
240 on_right = n - on_left;
246 std::copy(str.begin(),str.end(),out);
247 while(on_right > 0) {
258 template<typename CharType>
259 class base_num_parse : public std::num_get<CharType>
262 base_num_parse(size_t refs = 0) :
263 std::num_get<CharType>(refs)
267 typedef typename std::num_get<CharType>::iter_type iter_type;
268 typedef std::basic_string<CharType> string_type;
269 typedef CharType char_type;
271 virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,long &val) const
273 return do_real_get(in,end,ios,err,val);
276 virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,unsigned short &val) const
278 return do_real_get(in,end,ios,err,val);
281 virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,unsigned int &val) const
283 return do_real_get(in,end,ios,err,val);
286 virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,unsigned long &val) const
288 return do_real_get(in,end,ios,err,val);
291 virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,float &val) const
293 return do_real_get(in,end,ios,err,val);
296 virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,double &val) const
298 return do_real_get(in,end,ios,err,val);
301 virtual iter_type do_get (iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,long double &val) const
303 return do_real_get(in,end,ios,err,val);
306 #ifndef BOOST_NO_LONG_LONG
307 virtual iter_type do_get (iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,long long &val) const
309 return do_real_get(in,end,ios,err,val);
312 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
314 return do_real_get(in,end,ios,err,val);
321 template<typename ValueType>
322 iter_type do_real_get(iter_type in,iter_type end,std::ios_base &ios,std::ios_base::iostate &err,ValueType &val) const
324 typedef std::num_get<char_type> super;
326 ios_info &info=ios_info::get(ios);
328 switch(info.display_flags()) {
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);
337 case flags::currency:
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);
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);
349 // date-time parsing is not supported
350 // due to buggy standard
353 case flags::datetime:
354 case flags::strftime:
358 case flags::spellout:
361 return super::do_get(in,end,ios,err,val);
366 iter_type parse_currency(iter_type in,iter_type end,std::ios_base &ios,std::ios_base::iostate &err,long double &val) const
368 std::locale loc = ios.getloc();
369 int digits = std::use_facet<std::moneypunct<char_type,intl> >(loc).frac_digits();
371 in = std::use_facet<std::money_get<char_type> >(loc).get(in,end,intl,ios,err,rval);
372 if(!(err & std::ios::failbit)) {
393 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4