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 #define BOOST_LOCALE_SOURCE
9 #include <locale>
10 #include <string>
11 #include <ios>
12 #include <limits>
13 #include "formatter.hpp"
14 #include <boost/locale/formatting.hpp>
15 #include "all_generator.hpp"
16 #include "cdata.hpp"
17 #include <algorithm>
18 #include "predefined_formatters.hpp"
19 
20 namespace boost {
21 namespace locale {
22 namespace impl_icu {
23 
24 namespace details {
25     template<typename V,int n=std::numeric_limits<V>::digits,bool integer=std::numeric_limits<V>::is_integer>
26     struct cast_traits;
27 
28     template<typename v>
29     struct cast_traits<v,7,true> {
30         typedef int32_t cast_type;
31     };
32     template<typename v>
33     struct cast_traits<v,8,true> {
34         typedef int32_t cast_type;
35     };
36 
37     template<typename v>
38     struct cast_traits<v,15,true> {
39         typedef int32_t cast_type;
40     };
41     template<typename v>
42     struct cast_traits<v,16,true> {
43         typedef int32_t cast_type;
44     };
45     template<typename v>
46     struct cast_traits<v,31,true> {
47         typedef int32_t cast_type;
48     };
49     template<typename v>
50     struct cast_traits<v,32,true> {
51         typedef int64_t cast_type;
52     };
53     template<typename v>
54     struct cast_traits<v,63,true> {
55         typedef int64_t cast_type;
56     };
57     template<typename v>
58     struct cast_traits<v,64,true> {
59         typedef int64_t cast_type;
60     };
61     template<typename V,int u>
62     struct cast_traits<V,u,false> {
63         typedef double cast_type;
64     };
65 
66     // ICU does not support uint64_t values so fallback
67     // to POSIX formatting
68     template<   typename V,
69                 bool Sig=std::numeric_limits<V>::is_signed,
70                 bool Int=std::numeric_limits<V>::is_integer,
71                 bool Big=(sizeof(V) >= 8)
72             >
73     struct use_parent_traits
74     {
useboost::locale::impl_icu::details::use_parent_traits75         static bool use(V /*v*/) { return false; }
76     };
77     template<typename V>
78     struct use_parent_traits<V,false,true,true>
79     {
useboost::locale::impl_icu::details::use_parent_traits80         static bool use(V v) { return static_cast<int64_t>(v) < 0; }
81     };
82 
83 }
84 
85 
86 
87 class num_base {
88 protected:
89 
90     template<typename ValueType>
use_parent(std::ios_base & ios,ValueType v)91     static bool use_parent(std::ios_base &ios,ValueType v)
92     {
93         uint64_t flg = ios_info::get(ios).display_flags();
94         if(flg == flags::posix)
95             return true;
96         if(details::use_parent_traits<ValueType>::use(v))
97             return true;
98 
99         if(!std::numeric_limits<ValueType>::is_integer)
100             return false;
101 
102         if(flg == flags::number && (ios.flags() & std::ios_base::basefield) != std::ios_base::dec) {
103             return true;
104         }
105         return false;
106     }
107 };
108 
109 
110 template<typename CharType>
111 class num_format : public std::num_put<CharType>, protected num_base
112 {
113 public:
114     typedef typename std::num_put<CharType>::iter_type iter_type;
115     typedef std::basic_string<CharType> string_type;
116     typedef CharType char_type;
117     typedef formatter<CharType> formatter_type;
118     typedef std::auto_ptr<formatter_type> formatter_ptr;
119 
num_format(cdata const & d,size_t refs=0)120     num_format(cdata const &d,size_t refs = 0) :
121         std::num_put<CharType>(refs),
122         loc_(d.locale),
123         enc_(d.encoding)
124     {
125     }
126 protected:
127 
128 
do_put(iter_type out,std::ios_base & ios,char_type fill,long val) const129     virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, long val) const
130     {
131         return do_real_put(out,ios,fill,val);
132     }
do_put(iter_type out,std::ios_base & ios,char_type fill,unsigned long val) const133     virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, unsigned long val) const
134     {
135         return do_real_put(out,ios,fill,val);
136     }
do_put(iter_type out,std::ios_base & ios,char_type fill,double val) const137     virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, double val) const
138     {
139         return do_real_put(out,ios,fill,val);
140     }
do_put(iter_type out,std::ios_base & ios,char_type fill,long double val) const141     virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, long double val) const
142     {
143         return do_real_put(out,ios,fill,val);
144     }
145 
146     #ifndef BOOST_NO_LONG_LONG
do_put(iter_type out,std::ios_base & ios,char_type fill,long long val) const147     virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, long long val) const
148     {
149         return do_real_put(out,ios,fill,val);
150     }
do_put(iter_type out,std::ios_base & ios,char_type fill,unsigned long long val) const151     virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, unsigned long long val) const
152     {
153         return do_real_put(out,ios,fill,val);
154     }
155     #endif
156 
157 
158 private:
159 
160 
161 
162     template<typename ValueType>
do_real_put(iter_type out,std::ios_base & ios,char_type fill,ValueType val) const163     iter_type do_real_put (iter_type out, std::ios_base &ios, char_type fill, ValueType val) const
164     {
165         formatter_ptr formatter;
166 
167         if(use_parent<ValueType>(ios,val) || (formatter = formatter_type::create(ios,loc_,enc_)).get() == 0) {
168             return std::num_put<char_type>::do_put(out,ios,fill,val);
169         }
170 
171         size_t code_points;
172         typedef typename details::cast_traits<ValueType>::cast_type cast_type;
173         string_type const &str = formatter->format(static_cast<cast_type>(val),code_points);
174         std::streamsize on_left=0,on_right = 0,points = code_points;
175         if(points < ios.width()) {
176             std::streamsize n = ios.width() - points;
177 
178             std::ios_base::fmtflags flags = ios.flags() & std::ios_base::adjustfield;
179 
180             //
181             // We do not really know internal point, so we assume that it does not
182             // exist. So according to the standard field should be right aligned
183             //
184             if(flags != std::ios_base::left)
185                 on_left = n;
186             on_right = n - on_left;
187         }
188         while(on_left > 0) {
189             *out++ = fill;
190             on_left--;
191         }
192         std::copy(str.begin(),str.end(),out);
193         while(on_right > 0) {
194             *out++ = fill;
195             on_right--;
196         }
197         ios.width(0);
198         return out;
199 
200     }
201 
202     icu::Locale loc_;
203     std::string enc_;
204 
205 };  /// num_format
206 
207 
208 template<typename CharType>
209 class num_parse : public std::num_get<CharType>, protected num_base
210 {
211 public:
num_parse(cdata const & d,size_t refs=0)212     num_parse(cdata const &d,size_t refs = 0) :
213         std::num_get<CharType>(refs),
214         loc_(d.locale),
215         enc_(d.encoding)
216     {
217     }
218 protected:
219     typedef typename std::num_get<CharType>::iter_type iter_type;
220     typedef std::basic_string<CharType> string_type;
221     typedef CharType char_type;
222     typedef formatter<CharType> formatter_type;
223     typedef std::auto_ptr<formatter_type> formatter_ptr;
224     typedef std::basic_istream<CharType> stream_type;
225 
do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,long & val) const226     virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,long &val) const
227     {
228         return do_real_get(in,end,ios,err,val);
229     }
230 
do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,unsigned short & val) const231     virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,unsigned short &val) const
232     {
233         return do_real_get(in,end,ios,err,val);
234     }
235 
do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,unsigned int & val) const236     virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,unsigned int &val) const
237     {
238         return do_real_get(in,end,ios,err,val);
239     }
240 
do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,unsigned long & val) const241     virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,unsigned long &val) const
242     {
243         return do_real_get(in,end,ios,err,val);
244     }
245 
do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,float & val) const246     virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,float &val) const
247     {
248         return do_real_get(in,end,ios,err,val);
249     }
250 
do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,double & val) const251     virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,double &val) const
252     {
253         return do_real_get(in,end,ios,err,val);
254     }
255 
do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,long double & val) const256     virtual iter_type do_get (iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,long double &val) const
257     {
258         return do_real_get(in,end,ios,err,val);
259     }
260 
261     #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) const262     virtual iter_type do_get (iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,long long &val) const
263     {
264         return do_real_get(in,end,ios,err,val);
265     }
266 
do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,unsigned long long & val) const267     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
268     {
269         return do_real_get(in,end,ios,err,val);
270     }
271 
272     #endif
273 
274 private:
275 
276 
277     //
278     // This is not really an efficient solution, but it works
279     //
280     template<typename ValueType>
do_real_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,ValueType & val) const281     iter_type do_real_get(iter_type in,iter_type end,std::ios_base &ios,std::ios_base::iostate &err,ValueType &val) const
282     {
283         formatter_ptr formatter;
284         stream_type *stream_ptr = dynamic_cast<stream_type *>(&ios);
285 
286         if(!stream_ptr || use_parent<ValueType>(ios,0) || (formatter = formatter_type::create(ios,loc_,enc_)).get()==0) {
287             return std::num_get<CharType>::do_get(in,end,ios,err,val);
288         }
289 
290         typedef typename details::cast_traits<ValueType>::cast_type cast_type;
291         string_type tmp;
292         tmp.reserve(64);
293 
294         CharType c;
295         while(in!=end && (((c=*in)<=32 && (c>0)) || c==127)) // Assuming that ASCII is a subset
296             ++in;
297 
298         while(tmp.size() < 4096 && in!=end && *in!='\n') {
299             tmp += *in++;
300         }
301 
302         cast_type value;
303         size_t parsed_chars;
304 
305         if((parsed_chars = formatter->parse(tmp,value))==0 || !valid<ValueType>(value)) {
306             err |= std::ios_base::failbit;
307         }
308         else {
309             val=static_cast<ValueType>(value);
310         }
311 
312         for(size_t n=tmp.size();n>parsed_chars;n--) {
313             stream_ptr->putback(tmp[n-1]);
314         }
315 
316         in = iter_type(*stream_ptr);
317 
318         if(in==end)
319             err |=std::ios_base::eofbit;
320         return in;
321     }
322 
323     template<typename ValueType,typename CastedType>
valid(CastedType v) const324     bool valid(CastedType v) const
325     {
326         typedef std::numeric_limits<ValueType> value_limits;
327         typedef std::numeric_limits<CastedType> casted_limits;
328         if(v < 0 && value_limits::is_signed == false)
329             return false;
330 
331         static const CastedType max_val = value_limits::max();
332 
333         if(sizeof(CastedType) > sizeof(ValueType) && v > max_val)
334             return false;
335 
336         if(value_limits::is_integer == casted_limits::is_integer) {
337             return true;
338         }
339         if(value_limits::is_integer) { // and casted is not
340             if(static_cast<CastedType>(static_cast<ValueType>(v))!=v)
341                 return false;
342         }
343         return true;
344     }
345 
346     icu::Locale loc_;
347     std::string enc_;
348 
349 };
350 
351 
352 template<typename CharType>
install_formatting_facets(std::locale const & in,cdata const & cd)353 std::locale install_formatting_facets(std::locale const &in,cdata const &cd)
354 {
355     std::locale tmp=std::locale(in,new num_format<CharType>(cd));
356     if(!std::has_facet<icu_formatters_cache>(in)) {
357         tmp=std::locale(tmp,new icu_formatters_cache(cd.locale));
358     }
359     return tmp;
360 }
361 
362 template<typename CharType>
install_parsing_facets(std::locale const & in,cdata const & cd)363 std::locale install_parsing_facets(std::locale const &in,cdata const &cd)
364 {
365     std::locale tmp=std::locale(in,new num_parse<CharType>(cd));
366     if(!std::has_facet<icu_formatters_cache>(in)) {
367         tmp=std::locale(tmp,new icu_formatters_cache(cd.locale));
368     }
369     return tmp;
370 }
371 
create_formatting(std::locale const & in,cdata const & cd,character_facet_type type)372 std::locale create_formatting(std::locale const &in,cdata const &cd,character_facet_type type)
373 {
374         switch(type) {
375         case char_facet:
376             return install_formatting_facets<char>(in,cd);
377         case wchar_t_facet:
378             return install_formatting_facets<wchar_t>(in,cd);
379         #ifdef BOOST_HAS_CHAR16_T
380         case char16_t_facet:
381             return install_formatting_facets<char16_t>(in,cd);
382         #endif
383         #ifdef BOOST_HAS_CHAR32_T
384         case char32_t_facet:
385             return install_formatting_facets<char32_t>(in,cd);
386         #endif
387         default:
388             return in;
389         }
390 }
391 
create_parsing(std::locale const & in,cdata const & cd,character_facet_type type)392 std::locale create_parsing(std::locale const &in,cdata const &cd,character_facet_type type)
393 {
394         switch(type) {
395         case char_facet:
396             return install_parsing_facets<char>(in,cd);
397         case wchar_t_facet:
398             return install_parsing_facets<wchar_t>(in,cd);
399         #ifdef BOOST_HAS_CHAR16_T
400         case char16_t_facet:
401             return install_parsing_facets<char16_t>(in,cd);
402         #endif
403         #ifdef BOOST_HAS_CHAR32_T
404         case char32_t_facet:
405             return install_parsing_facets<char32_t>(in,cd);
406         #endif
407         default:
408             return in;
409         }
410 }
411 
412 
413 } // impl_icu
414 
415 } // locale
416 } //boost
417 
418 
419 
420 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
421