| // |
| // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) |
| // |
| // Distributed under the Boost Software License, Version 1.0. (See |
| // accompanying file LICENSE_1_0.txt or copy at |
| // http://www.boost.org/LICENSE_1_0.txt) |
| // |
| #define BOOST_LOCALE_SOURCE |
| #include <locale> |
| #include <string> |
| #include <ios> |
| #include <boost/locale/formatting.hpp> |
| #include <boost/locale/generator.hpp> |
| #include <boost/locale/encoding.hpp> |
| #include <sstream> |
| #include <stdlib.h> |
| |
| #include "../util/numeric.hpp" |
| #include "all_generator.hpp" |
| |
| namespace boost { |
| namespace locale { |
| namespace impl_std { |
| |
| template<typename CharType> |
| class time_put_from_base : public std::time_put<CharType> { |
| public: |
| time_put_from_base(std::locale const &base, size_t refs = 0) : |
| std::time_put<CharType>(refs), |
| base_(base) |
| { |
| } |
| typedef typename std::time_put<CharType>::iter_type iter_type; |
| |
| virtual iter_type do_put(iter_type out,std::ios_base &/*ios*/,CharType fill,std::tm const *tm,char format,char modifier) const |
| { |
| std::basic_stringstream<CharType> ss; |
| ss.imbue(base_); |
| return std::use_facet<std::time_put<CharType> >(base_).put(out,ss,fill,tm,format,modifier); |
| } |
| private: |
| std::locale base_; |
| }; |
| |
| class utf8_time_put_from_wide : public std::time_put<char> { |
| public: |
| utf8_time_put_from_wide(std::locale const &base, size_t refs = 0) : |
| std::time_put<char>(refs), |
| base_(base) |
| { |
| } |
| virtual iter_type do_put(iter_type out,std::ios_base &/*ios*/,char fill,std::tm const *tm,char format,char modifier = 0) const |
| { |
| std::basic_ostringstream<wchar_t> wtmps; |
| wtmps.imbue(base_); |
| std::use_facet<std::time_put<wchar_t> >(base_).put(wtmps,wtmps,wchar_t(fill),tm,wchar_t(format),wchar_t(modifier)); |
| std::wstring wtmp=wtmps.str(); |
| std::string const tmp = conv::from_utf<wchar_t>(wtmp,"UTF-8"); |
| for(unsigned i=0;i<tmp.size();i++) { |
| *out++ = tmp[i]; |
| } |
| return out; |
| } |
| private: |
| std::locale base_; |
| }; |
| |
| class utf8_numpunct_from_wide : public std::numpunct<char> { |
| public: |
| utf8_numpunct_from_wide(std::locale const &base,size_t refs = 0) : std::numpunct<char>(refs) |
| { |
| typedef std::numpunct<wchar_t> wfacet_type; |
| wfacet_type const &wfacet = std::use_facet<wfacet_type>(base); |
| |
| truename_ = conv::from_utf<wchar_t>(wfacet.truename(),"UTF-8"); |
| falsename_ = conv::from_utf<wchar_t>(wfacet.falsename(),"UTF-8"); |
| |
| wchar_t tmp_decimal_point = wfacet.decimal_point(); |
| wchar_t tmp_thousands_sep = wfacet.thousands_sep(); |
| std::string tmp_grouping = wfacet.grouping(); |
| |
| if( 32 <= tmp_thousands_sep && tmp_thousands_sep <=126 && |
| 32 <= tmp_decimal_point && tmp_decimal_point <=126) |
| { |
| thousands_sep_ = static_cast<char>(tmp_thousands_sep); |
| decimal_point_ = static_cast<char>(tmp_decimal_point); |
| grouping_ = tmp_grouping; |
| } |
| else if(32 <= tmp_decimal_point && tmp_decimal_point <=126 && tmp_thousands_sep == 0xA0) { |
| // workaround common bug - substitute NBSP with ordinary space |
| thousands_sep_ = ' '; |
| decimal_point_ = static_cast<char>(tmp_decimal_point); |
| grouping_ = tmp_grouping; |
| } |
| else if(32 <= tmp_decimal_point && tmp_decimal_point <=126) |
| { |
| thousands_sep_=','; |
| decimal_point_ = static_cast<char>(tmp_decimal_point); |
| grouping_=std::string(); |
| } |
| else { |
| thousands_sep_ = ','; |
| decimal_point_ = '.'; |
| grouping_=std::string(); |
| } |
| } |
| |
| virtual char do_decimal_point() const |
| { |
| return decimal_point_; |
| } |
| virtual char do_thousands_sep() const |
| { |
| return thousands_sep_; |
| } |
| virtual std::string do_grouping() const |
| { |
| return grouping_; |
| } |
| virtual std::string do_truename() const |
| { |
| return truename_; |
| } |
| virtual std::string do_falsename() const |
| { |
| return falsename_; |
| } |
| private: |
| std::string truename_; |
| std::string falsename_; |
| char thousands_sep_; |
| char decimal_point_; |
| std::string grouping_; |
| |
| }; |
| |
| template<bool Intl> |
| class utf8_moneypunct_from_wide : public std::moneypunct<char,Intl> { |
| public: |
| utf8_moneypunct_from_wide(std::locale const &base,size_t refs = 0) : std::moneypunct<char,Intl>(refs) |
| { |
| typedef std::moneypunct<wchar_t,Intl> wfacet_type; |
| wfacet_type const &wfacet = std::use_facet<wfacet_type>(base); |
| |
| curr_symbol_ = conv::from_utf<wchar_t>(wfacet.curr_symbol(),"UTF-8"); |
| positive_sign_ = conv::from_utf<wchar_t>(wfacet.positive_sign(),"UTF-8"); |
| negative_sign_ = conv::from_utf<wchar_t>(wfacet.negative_sign(),"UTF-8"); |
| frac_digits_ = wfacet.frac_digits(); |
| pos_format_ = wfacet.pos_format(); |
| neg_format_ = wfacet.neg_format(); |
| |
| wchar_t tmp_decimal_point = wfacet.decimal_point(); |
| wchar_t tmp_thousands_sep = wfacet.thousands_sep(); |
| std::string tmp_grouping = wfacet.grouping(); |
| if( 32 <= tmp_thousands_sep && tmp_thousands_sep <=126 && |
| 32 <= tmp_decimal_point && tmp_decimal_point <=126) |
| { |
| thousands_sep_ = static_cast<char>(tmp_thousands_sep); |
| decimal_point_ = static_cast<char>(tmp_decimal_point); |
| grouping_ = tmp_grouping; |
| } |
| else if(32 <= tmp_decimal_point && tmp_decimal_point <=126 && tmp_thousands_sep == 0xA0) { |
| // workaround common bug - substitute NBSP with ordinary space |
| thousands_sep_ = ' '; |
| decimal_point_ = static_cast<char>(tmp_decimal_point); |
| grouping_ = tmp_grouping; |
| } |
| else if(32 <= tmp_decimal_point && tmp_decimal_point <=126) |
| { |
| thousands_sep_=','; |
| decimal_point_ = static_cast<char>(tmp_decimal_point); |
| grouping_=std::string(); |
| } |
| else { |
| thousands_sep_ = ','; |
| decimal_point_ = '.'; |
| grouping_=std::string(); |
| } |
| } |
| |
| virtual char do_decimal_point() const |
| { |
| return decimal_point_; |
| } |
| |
| virtual char do_thousands_sep() const |
| { |
| return thousands_sep_; |
| } |
| |
| virtual std::string do_grouping() const |
| { |
| return grouping_; |
| } |
| |
| virtual std::string do_curr_symbol() const |
| { |
| return curr_symbol_; |
| } |
| virtual std::string do_positive_sign () const |
| { |
| return positive_sign_; |
| } |
| virtual std::string do_negative_sign() const |
| { |
| return negative_sign_; |
| } |
| |
| virtual int do_frac_digits() const |
| { |
| return frac_digits_; |
| } |
| |
| virtual std::money_base::pattern do_pos_format() const |
| { |
| return pos_format_; |
| } |
| |
| virtual std::money_base::pattern do_neg_format() const |
| { |
| return neg_format_; |
| } |
| |
| private: |
| char thousands_sep_; |
| char decimal_point_; |
| std::string grouping_; |
| std::string curr_symbol_; |
| std::string positive_sign_; |
| std::string negative_sign_; |
| int frac_digits_; |
| std::money_base::pattern pos_format_,neg_format_; |
| |
| }; |
| |
| class utf8_numpunct : public std::numpunct_byname<char> { |
| public: |
| typedef std::numpunct_byname<char> base_type; |
| utf8_numpunct(char const *name,size_t refs = 0) : |
| std::numpunct_byname<char>(name,refs) |
| { |
| } |
| virtual char do_thousands_sep() const |
| { |
| unsigned char bs = base_type::do_thousands_sep(); |
| if(bs > 127) |
| if(bs == 0xA0) |
| return ' '; |
| else |
| return 0; |
| else |
| return bs; |
| } |
| virtual std::string do_grouping() const |
| { |
| unsigned char bs = base_type::do_thousands_sep(); |
| if(bs > 127 && bs != 0xA0) |
| return std::string(); |
| return base_type::do_grouping(); |
| } |
| }; |
| |
| template<bool Intl> |
| class utf8_moneypunct : public std::moneypunct_byname<char,Intl> { |
| public: |
| typedef std::moneypunct_byname<char,Intl> base_type; |
| utf8_moneypunct(char const *name,size_t refs = 0) : |
| std::moneypunct_byname<char,Intl>(name,refs) |
| { |
| } |
| virtual char do_thousands_sep() const |
| { |
| unsigned char bs = base_type::do_thousands_sep(); |
| if(bs > 127) |
| if(bs == 0xA0) |
| return ' '; |
| else |
| return 0; |
| else |
| return bs; |
| } |
| virtual std::string do_grouping() const |
| { |
| unsigned char bs = base_type::do_thousands_sep(); |
| if(bs > 127 && bs != 0xA0) |
| return std::string(); |
| return base_type::do_grouping(); |
| } |
| }; |
| |
| |
| template<typename CharType> |
| std::locale create_basic_parsing(std::locale const &in,std::string const &locale_name) |
| { |
| std::locale tmp = std::locale(in,new std::numpunct_byname<CharType>(locale_name.c_str())); |
| tmp = std::locale(tmp,new std::moneypunct_byname<CharType,true>(locale_name.c_str())); |
| tmp = std::locale(tmp,new std::moneypunct_byname<CharType,false>(locale_name.c_str())); |
| tmp = std::locale(tmp,new std::ctype_byname<CharType>(locale_name.c_str())); |
| return tmp; |
| } |
| |
| template<typename CharType> |
| std::locale create_basic_formatting(std::locale const &in,std::string const &locale_name) |
| { |
| std::locale tmp = create_basic_parsing<CharType>(in,locale_name); |
| std::locale base(locale_name.c_str()); |
| tmp = std::locale(tmp,new time_put_from_base<CharType>(base)); |
| return tmp; |
| } |
| |
| |
| std::locale create_formatting( std::locale const &in, |
| std::string const &locale_name, |
| character_facet_type type, |
| utf8_support utf) |
| { |
| switch(type) { |
| case char_facet: |
| { |
| if(utf == utf8_from_wide ) { |
| std::locale base = std::locale(locale_name.c_str()); |
| |
| std::locale tmp = std::locale(in,new utf8_time_put_from_wide(base)); |
| tmp = std::locale(tmp,new utf8_numpunct_from_wide(base)); |
| tmp = std::locale(tmp,new utf8_moneypunct_from_wide<true>(base)); |
| tmp = std::locale(tmp,new utf8_moneypunct_from_wide<false>(base)); |
| return std::locale(tmp,new util::base_num_format<char>()); |
| } |
| else if(utf == utf8_native) { |
| std::locale base = std::locale(locale_name.c_str()); |
| |
| std::locale tmp = std::locale(in,new time_put_from_base<char>(base)); |
| tmp = std::locale(tmp,new utf8_numpunct(locale_name.c_str())); |
| tmp = std::locale(tmp,new utf8_moneypunct<true>(locale_name.c_str())); |
| tmp = std::locale(tmp,new utf8_moneypunct<false>(locale_name.c_str())); |
| return std::locale(tmp,new util::base_num_format<char>()); |
| } |
| else if(utf == utf8_native_with_wide) { |
| std::locale base = std::locale(locale_name.c_str()); |
| |
| std::locale tmp = std::locale(in,new time_put_from_base<char>(base)); |
| tmp = std::locale(tmp,new utf8_numpunct_from_wide(base)); |
| tmp = std::locale(tmp,new utf8_moneypunct_from_wide<true>(base)); |
| tmp = std::locale(tmp,new utf8_moneypunct_from_wide<false>(base)); |
| return std::locale(tmp,new util::base_num_format<char>()); |
| } |
| else |
| { |
| std::locale tmp = create_basic_formatting<char>(in,locale_name); |
| tmp = std::locale(tmp,new util::base_num_format<char>()); |
| return tmp; |
| } |
| } |
| case wchar_t_facet: |
| { |
| std::locale tmp = create_basic_formatting<wchar_t>(in,locale_name); |
| tmp = std::locale(tmp,new util::base_num_format<wchar_t>()); |
| return tmp; |
| } |
| #ifdef BOOST_HAS_CHAR16_T |
| case char16_t_facet: |
| { |
| std::locale tmp = create_basic_formatting<char16_t>(in,locale_name); |
| tmp = std::locale(tmp,new util::base_num_format<char16_t>()); |
| return tmp; |
| } |
| #endif |
| #ifdef BOOST_HAS_CHAR32_T |
| case char32_t_facet: |
| { |
| std::locale tmp = create_basic_formatting<char32_t>(in,locale_name); |
| tmp = std::locale(tmp,new util::base_num_format<char32_t>()); |
| return tmp; |
| } |
| #endif |
| default: |
| return in; |
| } |
| } |
| |
| std::locale create_parsing( std::locale const &in, |
| std::string const &locale_name, |
| character_facet_type type, |
| utf8_support utf) |
| { |
| switch(type) { |
| case char_facet: |
| { |
| if(utf == utf8_from_wide ) { |
| std::locale base = std::locale::classic(); |
| |
| base = std::locale(base,new std::numpunct_byname<wchar_t>(locale_name.c_str())); |
| base = std::locale(base,new std::moneypunct_byname<wchar_t,true>(locale_name.c_str())); |
| base = std::locale(base,new std::moneypunct_byname<wchar_t,false>(locale_name.c_str())); |
| |
| std::locale tmp = std::locale(in,new utf8_numpunct_from_wide(base)); |
| tmp = std::locale(tmp,new utf8_moneypunct_from_wide<true>(base)); |
| tmp = std::locale(tmp,new utf8_moneypunct_from_wide<false>(base)); |
| return std::locale(tmp,new util::base_num_parse<char>()); |
| } |
| else if(utf == utf8_native) { |
| std::locale tmp = std::locale(in,new utf8_numpunct(locale_name.c_str())); |
| tmp = std::locale(tmp,new utf8_moneypunct<true>(locale_name.c_str())); |
| tmp = std::locale(tmp,new utf8_moneypunct<false>(locale_name.c_str())); |
| return std::locale(tmp,new util::base_num_parse<char>()); |
| } |
| else if(utf == utf8_native_with_wide) { |
| std::locale base = std::locale(locale_name.c_str()); |
| |
| std::locale tmp = std::locale(in,new utf8_numpunct_from_wide(base)); |
| tmp = std::locale(tmp,new utf8_moneypunct_from_wide<true>(base)); |
| tmp = std::locale(tmp,new utf8_moneypunct_from_wide<false>(base)); |
| return std::locale(tmp,new util::base_num_parse<char>()); |
| } |
| else |
| { |
| std::locale tmp = create_basic_parsing<char>(in,locale_name); |
| tmp = std::locale(in,new util::base_num_parse<char>()); |
| return tmp; |
| } |
| } |
| case wchar_t_facet: |
| { |
| std::locale tmp = create_basic_parsing<wchar_t>(in,locale_name); |
| tmp = std::locale(in,new util::base_num_parse<wchar_t>()); |
| return tmp; |
| } |
| #ifdef BOOST_HAS_CHAR16_T |
| case char16_t_facet: |
| { |
| std::locale tmp = create_basic_parsing<char16_t>(in,locale_name); |
| tmp = std::locale(in,new util::base_num_parse<char16_t>()); |
| return tmp; |
| } |
| #endif |
| #ifdef BOOST_HAS_CHAR32_T |
| case char32_t_facet: |
| { |
| std::locale tmp = create_basic_parsing<char32_t>(in,locale_name); |
| tmp = std::locale(in,new util::base_num_parse<char32_t>()); |
| return tmp; |
| } |
| #endif |
| default: |
| return in; |
| } |
| } |
| |
| |
| } // impl_std |
| } // locale |
| } //boost |
| |
| |
| |
| // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 |