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 <boost/locale/formatting.hpp>
13 #include <boost/locale/generator.hpp>
14 #include <boost/locale/encoding.hpp>
15 #include <sstream>
16 #include <stdlib.h>
17 
18 #include "../util/numeric.hpp"
19 #include "all_generator.hpp"
20 
21 namespace boost {
22 namespace locale {
23 namespace impl_std {
24 
25 template<typename CharType>
26 class time_put_from_base : public std::time_put<CharType> {
27 public:
time_put_from_base(std::locale const & base,size_t refs=0)28     time_put_from_base(std::locale const &base, size_t refs = 0) :
29         std::time_put<CharType>(refs),
30         base_(base)
31     {
32     }
33     typedef typename std::time_put<CharType>::iter_type iter_type;
34 
do_put(iter_type out,std::ios_base &,CharType fill,std::tm const * tm,char format,char modifier) const35     virtual iter_type do_put(iter_type out,std::ios_base &/*ios*/,CharType fill,std::tm const *tm,char format,char modifier) const
36     {
37         std::basic_stringstream<CharType> ss;
38         ss.imbue(base_);
39         return std::use_facet<std::time_put<CharType> >(base_).put(out,ss,fill,tm,format,modifier);
40     }
41 private:
42     std::locale base_;
43 };
44 
45 class utf8_time_put_from_wide : public std::time_put<char> {
46 public:
utf8_time_put_from_wide(std::locale const & base,size_t refs=0)47     utf8_time_put_from_wide(std::locale const &base, size_t refs = 0) :
48         std::time_put<char>(refs),
49         base_(base)
50     {
51     }
do_put(iter_type out,std::ios_base &,char fill,std::tm const * tm,char format,char modifier=0) const52     virtual iter_type do_put(iter_type out,std::ios_base &/*ios*/,char fill,std::tm const *tm,char format,char modifier = 0) const
53     {
54         std::basic_ostringstream<wchar_t> wtmps;
55         wtmps.imbue(base_);
56         std::use_facet<std::time_put<wchar_t> >(base_).put(wtmps,wtmps,wchar_t(fill),tm,wchar_t(format),wchar_t(modifier));
57         std::wstring wtmp=wtmps.str();
58         std::string const tmp = conv::from_utf<wchar_t>(wtmp,"UTF-8");
59         for(unsigned i=0;i<tmp.size();i++) {
60             *out++ = tmp[i];
61         }
62         return out;
63     }
64 private:
65     std::locale base_;
66 };
67 
68 class utf8_numpunct_from_wide : public std::numpunct<char> {
69 public:
utf8_numpunct_from_wide(std::locale const & base,size_t refs=0)70     utf8_numpunct_from_wide(std::locale const &base,size_t refs = 0) : std::numpunct<char>(refs)
71     {
72         typedef std::numpunct<wchar_t> wfacet_type;
73         wfacet_type const &wfacet = std::use_facet<wfacet_type>(base);
74 
75         truename_ = conv::from_utf<wchar_t>(wfacet.truename(),"UTF-8");
76         falsename_ = conv::from_utf<wchar_t>(wfacet.falsename(),"UTF-8");
77 
78         wchar_t tmp_decimal_point = wfacet.decimal_point();
79         wchar_t tmp_thousands_sep = wfacet.thousands_sep();
80         std::string tmp_grouping = wfacet.grouping();
81 
82         if( 32 <= tmp_thousands_sep && tmp_thousands_sep <=126 &&
83             32 <= tmp_decimal_point && tmp_decimal_point <=126)
84         {
85             thousands_sep_ = static_cast<char>(tmp_thousands_sep);
86             decimal_point_ = static_cast<char>(tmp_decimal_point);
87             grouping_ = tmp_grouping;
88         }
89         else if(32 <= tmp_decimal_point && tmp_decimal_point <=126 && tmp_thousands_sep == 0xA0) {
90             // workaround common bug - substitute NBSP with ordinary space
91             thousands_sep_ = ' ';
92             decimal_point_ = static_cast<char>(tmp_decimal_point);
93             grouping_ = tmp_grouping;
94         }
95         else if(32 <= tmp_decimal_point && tmp_decimal_point <=126)
96         {
97             thousands_sep_=',';
98             decimal_point_ = static_cast<char>(tmp_decimal_point);
99             grouping_=std::string();
100         }
101         else {
102             thousands_sep_ = ',';
103             decimal_point_ = '.';
104             grouping_=std::string();
105         }
106     }
107 
do_decimal_point() const108     virtual char do_decimal_point() const
109     {
110         return decimal_point_;
111     }
do_thousands_sep() const112     virtual char do_thousands_sep() const
113     {
114         return thousands_sep_;
115     }
do_grouping() const116     virtual std::string do_grouping() const
117     {
118         return grouping_;
119     }
do_truename() const120     virtual std::string do_truename() const
121     {
122         return truename_;
123     }
do_falsename() const124     virtual std::string do_falsename() const
125     {
126         return falsename_;
127     }
128 private:
129     std::string truename_;
130     std::string falsename_;
131     char thousands_sep_;
132     char decimal_point_;
133     std::string grouping_;
134 
135 };
136 
137 template<bool Intl>
138 class utf8_moneypunct_from_wide : public std::moneypunct<char,Intl> {
139 public:
utf8_moneypunct_from_wide(std::locale const & base,size_t refs=0)140     utf8_moneypunct_from_wide(std::locale const &base,size_t refs = 0) : std::moneypunct<char,Intl>(refs)
141     {
142         typedef std::moneypunct<wchar_t,Intl> wfacet_type;
143         wfacet_type const &wfacet = std::use_facet<wfacet_type>(base);
144 
145         curr_symbol_ = conv::from_utf<wchar_t>(wfacet.curr_symbol(),"UTF-8");
146         positive_sign_ = conv::from_utf<wchar_t>(wfacet.positive_sign(),"UTF-8");
147         negative_sign_ = conv::from_utf<wchar_t>(wfacet.negative_sign(),"UTF-8");
148         frac_digits_ = wfacet.frac_digits();
149         pos_format_ = wfacet.pos_format();
150         neg_format_ = wfacet.neg_format();
151 
152         wchar_t tmp_decimal_point = wfacet.decimal_point();
153         wchar_t tmp_thousands_sep = wfacet.thousands_sep();
154         std::string tmp_grouping = wfacet.grouping();
155         if( 32 <= tmp_thousands_sep && tmp_thousands_sep <=126 &&
156             32 <= tmp_decimal_point && tmp_decimal_point <=126)
157         {
158             thousands_sep_ = static_cast<char>(tmp_thousands_sep);
159             decimal_point_ = static_cast<char>(tmp_decimal_point);
160             grouping_ = tmp_grouping;
161         }
162         else if(32 <= tmp_decimal_point && tmp_decimal_point <=126 && tmp_thousands_sep == 0xA0) {
163             // workaround common bug - substitute NBSP with ordinary space
164             thousands_sep_ = ' ';
165             decimal_point_ = static_cast<char>(tmp_decimal_point);
166             grouping_ = tmp_grouping;
167         }
168         else if(32 <= tmp_decimal_point && tmp_decimal_point <=126)
169         {
170             thousands_sep_=',';
171             decimal_point_ = static_cast<char>(tmp_decimal_point);
172             grouping_=std::string();
173         }
174         else {
175             thousands_sep_ = ',';
176             decimal_point_ = '.';
177             grouping_=std::string();
178         }
179     }
180 
do_decimal_point() const181     virtual char do_decimal_point() const
182     {
183         return decimal_point_;
184     }
185 
do_thousands_sep() const186     virtual char do_thousands_sep() const
187     {
188         return thousands_sep_;
189     }
190 
do_grouping() const191     virtual std::string do_grouping() const
192     {
193         return grouping_;
194     }
195 
do_curr_symbol() const196     virtual std::string do_curr_symbol() const
197     {
198         return curr_symbol_;
199     }
do_positive_sign() const200     virtual std::string do_positive_sign () const
201     {
202         return positive_sign_;
203     }
do_negative_sign() const204     virtual std::string do_negative_sign() const
205     {
206         return negative_sign_;
207     }
208 
do_frac_digits() const209     virtual int do_frac_digits() const
210     {
211         return frac_digits_;
212     }
213 
do_pos_format() const214     virtual std::money_base::pattern do_pos_format() const
215     {
216         return pos_format_;
217     }
218 
do_neg_format() const219     virtual std::money_base::pattern do_neg_format() const
220     {
221         return neg_format_;
222     }
223 
224 private:
225     char thousands_sep_;
226     char decimal_point_;
227     std::string grouping_;
228     std::string curr_symbol_;
229     std::string positive_sign_;
230     std::string negative_sign_;
231     int frac_digits_;
232     std::money_base::pattern pos_format_,neg_format_;
233 
234 };
235 
236 class utf8_numpunct : public std::numpunct_byname<char> {
237 public:
238     typedef std::numpunct_byname<char> base_type;
utf8_numpunct(char const * name,size_t refs=0)239     utf8_numpunct(char const *name,size_t refs = 0) :
240         std::numpunct_byname<char>(name,refs)
241     {
242     }
do_thousands_sep() const243     virtual char do_thousands_sep() const
244     {
245         unsigned char bs = base_type::do_thousands_sep();
246         if(bs > 127)
247             if(bs == 0xA0)
248                 return ' ';
249             else
250                 return 0;
251         else
252             return bs;
253     }
do_grouping() const254     virtual std::string do_grouping() const
255     {
256         unsigned char bs = base_type::do_thousands_sep();
257         if(bs > 127 && bs != 0xA0)
258             return std::string();
259         return base_type::do_grouping();
260     }
261 };
262 
263 template<bool Intl>
264 class utf8_moneypunct : public std::moneypunct_byname<char,Intl> {
265 public:
266     typedef std::moneypunct_byname<char,Intl> base_type;
utf8_moneypunct(char const * name,size_t refs=0)267     utf8_moneypunct(char const *name,size_t refs = 0) :
268         std::moneypunct_byname<char,Intl>(name,refs)
269     {
270     }
do_thousands_sep() const271     virtual char do_thousands_sep() const
272     {
273         unsigned char bs = base_type::do_thousands_sep();
274         if(bs > 127)
275             if(bs == 0xA0)
276                 return ' ';
277             else
278                 return 0;
279         else
280             return bs;
281     }
do_grouping() const282     virtual std::string do_grouping() const
283     {
284         unsigned char bs = base_type::do_thousands_sep();
285         if(bs > 127 && bs != 0xA0)
286             return std::string();
287         return base_type::do_grouping();
288     }
289 };
290 
291 
292 template<typename CharType>
create_basic_parsing(std::locale const & in,std::string const & locale_name)293 std::locale create_basic_parsing(std::locale const &in,std::string const &locale_name)
294 {
295     std::locale tmp = std::locale(in,new std::numpunct_byname<CharType>(locale_name.c_str()));
296     tmp = std::locale(tmp,new std::moneypunct_byname<CharType,true>(locale_name.c_str()));
297     tmp = std::locale(tmp,new std::moneypunct_byname<CharType,false>(locale_name.c_str()));
298     tmp = std::locale(tmp,new std::ctype_byname<CharType>(locale_name.c_str()));
299     return tmp;
300 }
301 
302 template<typename CharType>
create_basic_formatting(std::locale const & in,std::string const & locale_name)303 std::locale create_basic_formatting(std::locale const &in,std::string const &locale_name)
304 {
305     std::locale tmp = create_basic_parsing<CharType>(in,locale_name);
306     std::locale base(locale_name.c_str());
307     tmp = std::locale(tmp,new time_put_from_base<CharType>(base));
308     return tmp;
309 }
310 
311 
create_formatting(std::locale const & in,std::string const & locale_name,character_facet_type type,utf8_support utf)312 std::locale create_formatting(  std::locale const &in,
313                                 std::string const &locale_name,
314                                 character_facet_type type,
315                                 utf8_support utf)
316 {
317         switch(type) {
318         case char_facet:
319             {
320                 if(utf == utf8_from_wide ) {
321                     std::locale base = std::locale(locale_name.c_str());
322 
323                     std::locale tmp = std::locale(in,new utf8_time_put_from_wide(base));
324                     tmp = std::locale(tmp,new utf8_numpunct_from_wide(base));
325                     tmp = std::locale(tmp,new utf8_moneypunct_from_wide<true>(base));
326                     tmp = std::locale(tmp,new utf8_moneypunct_from_wide<false>(base));
327                     return std::locale(tmp,new util::base_num_format<char>());
328                 }
329                 else if(utf == utf8_native) {
330                     std::locale base = std::locale(locale_name.c_str());
331 
332                     std::locale tmp = std::locale(in,new time_put_from_base<char>(base));
333                     tmp = std::locale(tmp,new utf8_numpunct(locale_name.c_str()));
334                     tmp = std::locale(tmp,new utf8_moneypunct<true>(locale_name.c_str()));
335                     tmp = std::locale(tmp,new utf8_moneypunct<false>(locale_name.c_str()));
336                     return std::locale(tmp,new util::base_num_format<char>());
337                 }
338                 else if(utf == utf8_native_with_wide) {
339                     std::locale base = std::locale(locale_name.c_str());
340 
341                     std::locale tmp = std::locale(in,new time_put_from_base<char>(base));
342                     tmp = std::locale(tmp,new utf8_numpunct_from_wide(base));
343                     tmp = std::locale(tmp,new utf8_moneypunct_from_wide<true>(base));
344                     tmp = std::locale(tmp,new utf8_moneypunct_from_wide<false>(base));
345                     return std::locale(tmp,new util::base_num_format<char>());
346                 }
347                 else
348                 {
349                     std::locale tmp = create_basic_formatting<char>(in,locale_name);
350                     tmp = std::locale(tmp,new util::base_num_format<char>());
351                     return tmp;
352                 }
353             }
354         case wchar_t_facet:
355             {
356                 std::locale tmp = create_basic_formatting<wchar_t>(in,locale_name);
357                 tmp = std::locale(tmp,new util::base_num_format<wchar_t>());
358                 return tmp;
359             }
360         #ifdef BOOST_HAS_CHAR16_T
361         case char16_t_facet:
362             {
363                 std::locale tmp = create_basic_formatting<char16_t>(in,locale_name);
364                 tmp = std::locale(tmp,new util::base_num_format<char16_t>());
365                 return tmp;
366             }
367         #endif
368         #ifdef BOOST_HAS_CHAR32_T
369         case char32_t_facet:
370             {
371                 std::locale tmp = create_basic_formatting<char32_t>(in,locale_name);
372                 tmp = std::locale(tmp,new util::base_num_format<char32_t>());
373                 return tmp;
374             }
375         #endif
376         default:
377             return in;
378         }
379 }
380 
create_parsing(std::locale const & in,std::string const & locale_name,character_facet_type type,utf8_support utf)381 std::locale create_parsing( std::locale const &in,
382                             std::string const &locale_name,
383                             character_facet_type type,
384                             utf8_support utf)
385 {
386         switch(type) {
387         case char_facet:
388             {
389                 if(utf == utf8_from_wide ) {
390                     std::locale base = std::locale::classic();
391 
392                     base = std::locale(base,new std::numpunct_byname<wchar_t>(locale_name.c_str()));
393                     base = std::locale(base,new std::moneypunct_byname<wchar_t,true>(locale_name.c_str()));
394                     base = std::locale(base,new std::moneypunct_byname<wchar_t,false>(locale_name.c_str()));
395 
396                     std::locale tmp = std::locale(in,new utf8_numpunct_from_wide(base));
397                     tmp = std::locale(tmp,new utf8_moneypunct_from_wide<true>(base));
398                     tmp = std::locale(tmp,new utf8_moneypunct_from_wide<false>(base));
399                     return std::locale(tmp,new util::base_num_parse<char>());
400                 }
401                 else if(utf == utf8_native) {
402                     std::locale tmp = std::locale(in,new utf8_numpunct(locale_name.c_str()));
403                     tmp = std::locale(tmp,new utf8_moneypunct<true>(locale_name.c_str()));
404                     tmp = std::locale(tmp,new utf8_moneypunct<false>(locale_name.c_str()));
405                     return std::locale(tmp,new util::base_num_parse<char>());
406                 }
407                 else if(utf == utf8_native_with_wide) {
408                     std::locale base = std::locale(locale_name.c_str());
409 
410                     std::locale tmp = std::locale(in,new utf8_numpunct_from_wide(base));
411                     tmp = std::locale(tmp,new utf8_moneypunct_from_wide<true>(base));
412                     tmp = std::locale(tmp,new utf8_moneypunct_from_wide<false>(base));
413                     return std::locale(tmp,new util::base_num_parse<char>());
414                 }
415                 else
416                 {
417                     std::locale tmp = create_basic_parsing<char>(in,locale_name);
418                     tmp = std::locale(in,new util::base_num_parse<char>());
419                     return tmp;
420                 }
421             }
422         case wchar_t_facet:
423                 {
424                     std::locale tmp = create_basic_parsing<wchar_t>(in,locale_name);
425                     tmp = std::locale(in,new util::base_num_parse<wchar_t>());
426                     return tmp;
427                 }
428         #ifdef BOOST_HAS_CHAR16_T
429         case char16_t_facet:
430                 {
431                     std::locale tmp = create_basic_parsing<char16_t>(in,locale_name);
432                     tmp = std::locale(in,new util::base_num_parse<char16_t>());
433                     return tmp;
434                 }
435         #endif
436         #ifdef BOOST_HAS_CHAR32_T
437         case char32_t_facet:
438                 {
439                     std::locale tmp = create_basic_parsing<char32_t>(in,locale_name);
440                     tmp = std::locale(in,new util::base_num_parse<char32_t>());
441                     return tmp;
442                 }
443         #endif
444         default:
445             return in;
446         }
447 }
448 
449 
450 } // impl_std
451 } // locale
452 } //boost
453 
454 
455 
456 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
457