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