diff --git a/include/boost/locale.hpp b/include/boost/locale.hpp index 989bba6c..0094827f 100644 --- a/include/boost/locale.hpp +++ b/include/boost/locale.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/locale/numpunct.hpp b/include/boost/locale/numpunct.hpp new file mode 100644 index 00000000..076dba09 --- /dev/null +++ b/include/boost/locale/numpunct.hpp @@ -0,0 +1,100 @@ +// +// Copyright (c) 2021-2021 Salvo Miosi +// +// 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) +// + +#ifndef BOOST_LOCALE_NUMPUNCT_HPP_INCLUDED +#define BOOST_LOCALE_NUMPUNCT_HPP_INCLUDED +#include +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable : 4275 4251 4231 4660) +#endif +#include +#include + +namespace boost { + namespace locale { + + template + class BOOST_LOCALE_DECL numpunct_base : public std::numpunct + { + typedef std::basic_string string_type; + public: + numpunct_base(size_t refs = 0) : std::numpunct(refs) {} + + string_type decimal_point_full() const { + return do_decimal_point_full(); + } + + string_type thousands_sep_full() const { + return do_thousands_sep_full(); + } + + protected: + virtual CharType do_decimal_point() const { + string_type dec = do_decimal_point_full(); + if (dec.size() > 1) { + return '.'; + } else { + return dec[0]; + } + } + + virtual string_type do_decimal_point_full() const { + static const char t[] = "."; + return string_type(t, t + sizeof(t) - 1); + } + + virtual CharType do_thousands_sep() const { + string_type thous = do_thousands_sep_full(); + if (thous.size() > 1) { + return ','; + } else { + return thous[0]; + } + } + + virtual string_type do_thousands_sep_full() const { + static const char t[] = ","; + return string_type(t, t + sizeof(t) - 1); + } + + virtual string_type do_truename() const { + static const char t[] = "true"; + return string_type(t, t + sizeof(t) - 1); + } + + virtual string_type do_falsename() const { + static const char t[] = "false"; + return string_type(t, t + sizeof(t) - 1); + } + }; + + template struct numpunct {}; + + template<> struct numpunct : numpunct_base { + numpunct (size_t refs = 0) : numpunct_base(refs) {} + }; + + template<> struct numpunct : numpunct_base { + numpunct (size_t refs = 0) : numpunct_base(refs) {} + }; + + #ifdef BOOST_LOCALE_ENABLE_CHAR16_T + template<> struct numpunct : numpunct_base { + numpunct (size_t refs = 0) : numpunct_base(refs) {} + }; + #endif + #ifdef BOOST_LOCALE_ENABLE_CHAR32_T + template<> struct numpunct : numpunct_base { + numpunct (size_t refs = 0) : numpunct_base(refs) {} + }; + #endif + } +} + +#endif \ No newline at end of file diff --git a/src/icu/numeric.cpp b/src/icu/numeric.cpp index debecfb8..7a078ff4 100644 --- a/src/icu/numeric.cpp +++ b/src/icu/numeric.cpp @@ -13,10 +13,12 @@ #include "formatter.hpp" #include #include +#include #include "all_generator.hpp" #include "cdata.hpp" #include #include "predefined_formatters.hpp" +#include "uconv.hpp" namespace boost { namespace locale { @@ -354,6 +356,46 @@ class num_parse : public std::num_get, protected num_base }; +template +struct icu_numpunct : public numpunct { + typedef std::basic_string string_type; +public: + icu_numpunct(icu::Locale const &loc) + { + UErrorCode err; + icu::NumberFormat *fmt = icu::NumberFormat::createInstance(loc, UNUM_DECIMAL, err); + if (icu::DecimalFormat *dec = dynamic_cast(fmt)) { + boost::locale::impl_icu::icu_std_converter cnv("UTF-8"); + const icu::DecimalFormatSymbols *syms = dec->getDecimalFormatSymbols(); + decimal_point_ = cnv.std(syms->getSymbol(icu::DecimalFormatSymbols::kDecimalSeparatorSymbol)); + thousands_sep_ = cnv.std(syms->getSymbol(icu::DecimalFormatSymbols::kGroupingSeparatorSymbol)); + if (dec->isGroupingUsed()) { + int32_t grouping_size = dec->getGroupingSize(); + grouping_ = std::string(reinterpret_cast(&grouping_size), 1); + int32_t grouping_size_2 = dec->getSecondaryGroupingSize(); + if (grouping_size_2 > 0 && grouping_size_2 != grouping_size) { + grouping_ = static_cast(grouping_size_2) + grouping_; + } + } + } + } +protected: + virtual string_type do_decimal_point_full() const { + return decimal_point_; + } + virtual string_type do_thousands_sep_full() const { + return thousands_sep_; + } + virtual std::string do_grouping() const { + return grouping_; + } + +private: + string_type decimal_point_; + string_type thousands_sep_; + std::string grouping_; +}; + template std::locale install_formatting_facets(std::locale const &in,cdata const &cd) @@ -362,6 +404,7 @@ std::locale install_formatting_facets(std::locale const &in,cdata const &cd) if(!std::has_facet(in)) { tmp=std::locale(tmp,new icu_formatters_cache(cd.locale)); } + tmp=std::locale(tmp, new icu_numpunct(cd.locale)); return tmp; } diff --git a/src/posix/numeric.cpp b/src/posix/numeric.cpp index 2bef81e2..0735fdf7 100644 --- a/src/posix/numeric.cpp +++ b/src/posix/numeric.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -404,20 +405,16 @@ struct basic_numpunct { }; template -class num_punct_posix : public std::numpunct { +class num_punct_posix : public numpunct { public: typedef std::basic_string string_type; num_punct_posix(locale_t lc,size_t refs = 0) : - std::numpunct(refs) + numpunct(refs) { basic_numpunct np(lc); to_str(np.thousands_sep,thousands_sep_,lc); to_str(np.decimal_point,decimal_point_,lc); grouping_ = np.grouping; - if(thousands_sep_.size() > 1) - grouping_ = std::string(); - if(decimal_point_.size() > 1) - decimal_point_ = CharType('.'); } void to_str(std::string &s1,std::string &s2,locale_t /*lc*/) { @@ -427,13 +424,13 @@ class num_punct_posix : public std::numpunct { { s2=conv::to_utf(s1,nl_langinfo_l(CODESET,lc)); } - virtual CharType do_decimal_point() const + virtual string_type do_decimal_point_full() const { - return *decimal_point_.c_str(); + return decimal_point_; } - virtual CharType do_thousands_sep() const + virtual string_type do_thousands_sep_full() const { - return *thousands_sep_.c_str(); + return thousands_sep_; } virtual std::string do_grouping() const { diff --git a/src/win32/numeric.cpp b/src/win32/numeric.cpp index 00bc94fd..209715b9 100644 --- a/src/win32/numeric.cpp +++ b/src/win32/numeric.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -119,11 +120,11 @@ class time_put_win : public std::time_put { template -class num_punct_win : public std::numpunct { +class num_punct_win : public numpunct { public: typedef std::basic_string string_type; num_punct_win(winlocale const &lc,size_t refs = 0) : - std::numpunct(refs) + numpunct(refs) { numeric_info np = wcsnumformat_l(lc) ; if(sizeof(CharType) == 1 && np.thousands_sep == L"\xA0") @@ -132,10 +133,6 @@ class num_punct_win : public std::numpunct { to_str(np.thousands_sep,thousands_sep_); to_str(np.decimal_point,decimal_point_); grouping_ = np.grouping; - if(thousands_sep_.size() > 1) - grouping_ = std::string(); - if(decimal_point_.size() > 1) - decimal_point_ = CharType('.'); } void to_str(std::wstring &s1,std::wstring &s2) @@ -147,28 +144,18 @@ class num_punct_win : public std::numpunct { { s2=conv::from_utf(s1,"UTF-8"); } - virtual CharType do_decimal_point() const + virtual string_type do_decimal_point_full() const { - return *decimal_point_.c_str(); + return decimal_point_; } - virtual CharType do_thousands_sep() const + virtual string_type do_thousands_sep_full() const { - return *thousands_sep_.c_str(); + return thousands_sep_; } virtual std::string do_grouping() const { return grouping_; } - virtual string_type do_truename() const - { - static const char t[]="true"; - return string_type(t,t+sizeof(t)-1); - } - virtual string_type do_falsename() const - { - static const char t[]="false"; - return string_type(t,t+sizeof(t)-1); - } private: string_type decimal_point_; string_type thousands_sep_; @@ -179,7 +166,7 @@ template std::locale create_formatting_impl(std::locale const &in,winlocale const &lc) { if(lc.is_c()) { - std::locale tmp(in,new std::numpunct_byname("C")); + std::locale tmp(in, new numpunct()); tmp=std::locale(tmp,new std::time_put_byname("C")); tmp = std::locale(tmp,new num_format(lc)); return tmp; @@ -193,14 +180,12 @@ std::locale create_formatting_impl(std::locale const &in,winlocale const &lc) } template -std::locale create_parsing_impl(std::locale const &in,winlocale const &lc) +std::locale create_parsing_impl(std::locale tmp,winlocale const &lc) { - std::numpunct *np = 0; if(lc.is_c()) - np = new std::numpunct_byname("C"); + tmp = std::locale(tmp, new numpunct()); else - np = new num_punct_win(lc); - std::locale tmp(in,np); + tmp = std::locale(tmp, new num_punct_win(lc)); tmp = std::locale(tmp,new util::base_num_parse()); return tmp; }