Imported Upstream version 1.57.0
[platform/upstream/boost.git] / libs / locale / src / util / numeric.hpp
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 {
34     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> {
42     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
72     base_num_format(size_t refs = 0) : 
73         std::num_put<CharType>(refs)
74     {
75     }
76 protected: 
77     
78
79     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     }
83     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     }
87     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     }
91     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 
97     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     }
101     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>
113     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
157     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>
166     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
181     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
189     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:
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
271     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
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
277     {
278         return do_real_get(in,end,ios,err,val);
279     }
280
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
282     {
283         return do_real_get(in,end,ios,err,val);
284     }
285
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
287     {
288         return do_real_get(in,end,ios,err,val);
289     }
290
291     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
296     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
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
302     {
303         return do_real_get(in,end,ios,err,val);
304     }
305
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
308     {
309         return do_real_get(in,end,ios,err,val);
310     }
311
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
313     {
314         return do_real_get(in,end,ios,err,val);
315     }
316
317     #endif
318
319 private:
320     
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
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>
366     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