]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/locale/src/icu/formatter.cpp
2 // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
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)
8 #define BOOST_LOCALE_SOURCE
9 #include <boost/locale/formatting.hpp>
10 #include "formatter.hpp"
11 #include <boost/locale/info.hpp>
15 #include <unicode/numfmt.h>
16 #include <unicode/rbnf.h>
17 #include <unicode/datefmt.h>
18 #include <unicode/smpdtfmt.h>
19 #include <unicode/decimfmt.h>
25 #include "predefined_formatters.hpp"
26 #include "time_zone.hpp"
29 # pragma warning(disable : 4244) // lose data
38 std::locale::id
icu_formatters_cache::id
;
41 struct init
{ init() { std::has_facet
<icu_formatters_cache
>(std::locale::classic()); } } instance
;
45 template<typename CharType
>
46 class number_format
: public formatter
<CharType
> {
48 typedef CharType char_type
;
49 typedef std::basic_string
<CharType
> string_type
;
51 virtual string_type
format(double value
,size_t &code_points
) const
53 icu::UnicodeString tmp
;
54 icu_fmt_
->format(value
,tmp
);
55 code_points
=tmp
.countChar32();
58 virtual string_type
format(int64_t value
,size_t &code_points
) const
60 icu::UnicodeString tmp
;
61 icu_fmt_
->format(static_cast< ::int64_t>(value
),tmp
);
62 code_points
=tmp
.countChar32();
66 virtual string_type
format(int32_t value
,size_t &code_points
) const
68 icu::UnicodeString tmp
;
70 icu_fmt_
->format(static_cast<int>(value
),tmp
);
72 icu_fmt_
->format(::int32_t(value
),tmp
);
74 code_points
=tmp
.countChar32();
78 virtual size_t parse(string_type
const &str
,double &value
) const
80 return do_parse(str
,value
);
83 virtual size_t parse(string_type
const &str
,int64_t &value
) const
85 return do_parse(str
,value
);
87 virtual size_t parse(string_type
const &str
,int32_t &value
) const
89 return do_parse(str
,value
);
92 number_format(icu::NumberFormat
*fmt
,std::string codepage
) :
100 bool get_value(double &v
,icu::Formattable
&fmt
) const
102 UErrorCode err
=U_ZERO_ERROR
;
103 v
=fmt
.getDouble(err
);
109 bool get_value(int64_t &v
,icu::Formattable
&fmt
) const
111 UErrorCode err
=U_ZERO_ERROR
;
118 bool get_value(int32_t &v
,icu::Formattable
&fmt
) const
120 UErrorCode err
=U_ZERO_ERROR
;
127 template<typename ValueType
>
128 size_t do_parse(string_type
const &str
,ValueType
&v
) const
130 icu::Formattable val
;
131 icu::ParsePosition pp
;
132 icu::UnicodeString tmp
= cvt_
.icu(str
.data(),str
.data()+str
.size());
134 icu_fmt_
->parse(tmp
,val
,pp
);
138 if(pp
.getIndex() == 0 || !get_value(tmp_v
,val
))
140 size_t cut
= cvt_
.cut(tmp
,str
.data(),str
.data()+str
.size(),pp
.getIndex());
147 icu_std_converter
<CharType
> cvt_
;
148 icu::NumberFormat
*icu_fmt_
;
152 template<typename CharType
>
153 class date_format
: public formatter
<CharType
> {
155 typedef CharType char_type
;
156 typedef std::basic_string
<CharType
> string_type
;
158 virtual string_type
format(double value
,size_t &code_points
) const
160 return do_format(value
,code_points
);
162 virtual string_type
format(int64_t value
,size_t &code_points
) const
164 return do_format(value
,code_points
);
167 virtual string_type
format(int32_t value
,size_t &code_points
) const
169 return do_format(value
,code_points
);
172 virtual size_t parse(string_type
const &str
,double &value
) const
174 return do_parse(str
,value
);
176 virtual size_t parse(string_type
const &str
,int64_t &value
) const
178 return do_parse(str
,value
);
180 virtual size_t parse(string_type
const &str
,int32_t &value
) const
182 return do_parse(str
,value
);
185 date_format(icu::DateFormat
*fmt
,bool transfer_owneship
,std::string codepage
) :
188 if(transfer_owneship
) {
189 aicu_fmt_
.reset(fmt
);
190 icu_fmt_
= aicu_fmt_
.get();
199 template<typename ValueType
>
200 size_t do_parse(string_type
const &str
,ValueType
&value
) const
202 icu::ParsePosition pp
;
203 icu::UnicodeString tmp
= cvt_
.icu(str
.data(),str
.data() + str
.size());
205 UDate udate
= icu_fmt_
->parse(tmp
,pp
);
206 if(pp
.getIndex() == 0)
208 double date
= udate
/ 1000.0;
209 typedef std::numeric_limits
<ValueType
> limits_type
;
210 if(date
> limits_type::max() || date
< limits_type::min())
212 size_t cut
= cvt_
.cut(tmp
,str
.data(),str
.data()+str
.size(),pp
.getIndex());
215 value
=static_cast<ValueType
>(date
);
220 string_type
do_format(double value
,size_t &codepoints
) const
222 UDate date
= value
* 1000.0; /// UDate is time_t in miliseconds
223 icu::UnicodeString tmp
;
224 icu_fmt_
->format(date
,tmp
);
225 codepoints
=tmp
.countChar32();
226 return cvt_
.std(tmp
);
229 icu_std_converter
<CharType
> cvt_
;
230 hold_ptr
<icu::DateFormat
> aicu_fmt_
;
231 icu::DateFormat
*icu_fmt_
;
234 icu::UnicodeString
strftime_to_icu_full(icu::DateFormat
*dfin
,char const *alt
)
236 hold_ptr
<icu::DateFormat
> df(dfin
);
237 icu::SimpleDateFormat
*sdf
=dynamic_cast<icu::SimpleDateFormat
*>(df
.get());
238 icu::UnicodeString tmp
;
249 icu::UnicodeString
strftime_to_icu_symbol(char c
,icu::Locale
const &locale
,icu_formatters_cache
const *cache
=0)
252 case 'a': // Abbr Weekday
254 case 'A': // Full Weekday
256 case 'b': // Abbr Month
258 case 'B': // Full Month
260 case 'c': // DateTile Full
263 return cache
->date_time_format_
[1][1];
264 return strftime_to_icu_full(
265 icu::DateFormat::createDateTimeInstance(icu::DateFormat::kFull
,icu::DateFormat::kFull
,locale
),
266 "yyyy-MM-dd HH:mm:ss"
269 // not supported by ICU ;(
270 // case 'C': // Century -> 1980 -> 19
272 case 'd': // Day of Month [01,31]
274 case 'D': // %m/%d/%y
276 case 'e': // Day of Month [1,31]
280 case 'H': // 24 clock hour 00,23
282 case 'I': // 12 clock hour 01,12
284 case 'j': // day of year 001,366
286 case 'm': // month as [01,12]
288 case 'M': // minute [00,59]
294 case 'r': // time with AM/PM %I:%M:%S %p
298 case 'S': // second [00,61]
302 case 'T': // %H:%M:%S
304 /* case 'u': // weekday 1,7 1=Monday
305 case 'U': // week number of year [00,53] Sunday first
306 case 'V': // week number of year [01,53] Moday first
307 case 'w': // weekday 0,7 0=Sunday
308 case 'W': // week number of year [00,53] Moday first, */
312 return cache
->date_format_
[1];
313 return strftime_to_icu_full(
314 icu::DateFormat::createDateInstance(icu::DateFormat::kMedium
,locale
),
321 return cache
->time_format_
[1];
322 return strftime_to_icu_full(
323 icu::DateFormat::createTimeInstance(icu::DateFormat::kMedium
,locale
),
327 case 'y': // Year [00-99]
329 case 'Y': // Year 1998
331 case 'Z': // timezone
340 icu::UnicodeString
strftime_to_icu(icu::UnicodeString
const &ftime
,icu::Locale
const &locale
)
342 unsigned len
=ftime
.length();
343 icu::UnicodeString result
;
345 for(unsigned i
=0;i
<len
;i
++) {
350 if(c
=='E' || c
=='O') {
358 result
+=strftime_to_icu_symbol(c
,locale
);
376 template<typename CharType
>
377 formatter
<CharType
> *generate_formatter(
379 icu::Locale
const &locale
,
380 std::string
const &encoding
)
382 using namespace boost::locale::flags
;
384 hold_ptr
<formatter
<CharType
> > fmt
;
385 ios_info
&info
=ios_info::get(ios
);
386 uint64_t disp
= info
.display_flags();
388 icu_formatters_cache
const &cache
= std::use_facet
<icu_formatters_cache
>(ios
.getloc());
392 return fmt
.release();
394 UErrorCode err
=U_ZERO_ERROR
;
399 std::ios_base::fmtflags how
= (ios
.flags() & std::ios_base::floatfield
);
400 icu::NumberFormat
*nf
= 0;
402 if(how
== std::ios_base::scientific
)
403 nf
= cache
.number_format(icu_formatters_cache::fmt_sci
);
405 nf
= cache
.number_format(icu_formatters_cache::fmt_number
);
407 nf
->setMaximumFractionDigits(ios
.precision());
408 if(how
== std::ios_base::scientific
|| how
== std::ios_base::fixed
) {
409 nf
->setMinimumFractionDigits(ios
.precision());
412 nf
->setMinimumFractionDigits(0);
414 fmt
.reset(new number_format
<CharType
>(nf
,encoding
));
419 icu::NumberFormat
*nf
;
421 uint64_t curr
= info
.currency_flags();
423 if(curr
== currency_default
|| curr
== currency_national
)
424 nf
= cache
.number_format(icu_formatters_cache::fmt_curr_nat
);
426 nf
= cache
.number_format(icu_formatters_cache::fmt_curr_iso
);
428 fmt
.reset(new number_format
<CharType
>(nf
,encoding
));
433 icu::NumberFormat
*nf
= cache
.number_format(icu_formatters_cache::fmt_per
);
434 nf
->setMaximumFractionDigits(ios
.precision());
435 std::ios_base::fmtflags how
= (ios
.flags() & std::ios_base::floatfield
);
436 if(how
== std::ios_base::scientific
|| how
== std::ios_base::fixed
) {
437 nf
->setMinimumFractionDigits(ios
.precision());
440 nf
->setMinimumFractionDigits(0);
442 fmt
.reset(new number_format
<CharType
>(nf
,encoding
));
447 fmt
.reset(new number_format
<CharType
>(cache
.number_format(icu_formatters_cache::fmt_spell
),encoding
));
450 fmt
.reset(new number_format
<CharType
>(cache
.number_format(icu_formatters_cache::fmt_ord
),encoding
));
457 using namespace flags
;
458 hold_ptr
<icu::DateFormat
> adf
;
459 icu::DateFormat
*df
= 0;
460 icu::SimpleDateFormat
*sdf
= cache
.date_formatter();
461 // try to use cached first
463 int tmf
=info
.time_flags();
479 int dtf
=info
.date_flags();
496 icu::UnicodeString pattern
;
499 pattern
= cache
.date_format_
[dtf
];
502 pattern
= cache
.time_format_
[tmf
];
505 pattern
= cache
.date_time_format_
[dtf
][tmf
];
509 if( !cache
.date_format_
[1].isEmpty()
510 && !cache
.time_format_
[1].isEmpty()
511 && !cache
.date_time_format_
[1][1].isEmpty())
513 icu_std_converter
<CharType
> cvt_(encoding
);
514 std::basic_string
<CharType
> const &f
=info
.date_time_pattern
<CharType
>();
515 pattern
= strftime_to_icu(cvt_
.icu(f
.c_str(),f
.c_str()+f
.size()),locale
);
520 if(!pattern
.isEmpty()) {
521 sdf
->applyPattern(pattern
);
529 icu::DateFormat::EStyle dstyle
= icu::DateFormat::kDefault
;
530 icu::DateFormat::EStyle tstyle
= icu::DateFormat::kDefault
;
532 switch(info
.time_flags()) {
533 case time_short
: tstyle
=icu::DateFormat::kShort
; break;
534 case time_medium
: tstyle
=icu::DateFormat::kMedium
; break;
535 case time_long
: tstyle
=icu::DateFormat::kLong
; break;
536 case time_full
: tstyle
=icu::DateFormat::kFull
; break;
538 switch(info
.date_flags()) {
539 case date_short
: dstyle
=icu::DateFormat::kShort
; break;
540 case date_medium
: dstyle
=icu::DateFormat::kMedium
; break;
541 case date_long
: dstyle
=icu::DateFormat::kLong
; break;
542 case date_full
: dstyle
=icu::DateFormat::kFull
; break;
546 adf
.reset(icu::DateFormat::createDateInstance(dstyle
,locale
));
548 adf
.reset(icu::DateFormat::createTimeInstance(tstyle
,locale
));
549 else if(disp
==datetime
)
550 adf
.reset(icu::DateFormat::createDateTimeInstance(dstyle
,tstyle
,locale
));
552 icu_std_converter
<CharType
> cvt_(encoding
);
553 std::basic_string
<CharType
> const &f
=info
.date_time_pattern
<CharType
>();
554 icu::UnicodeString fmt
= strftime_to_icu(cvt_
.icu(f
.data(),f
.data()+f
.size()),locale
);
555 adf
.reset(new icu::SimpleDateFormat(fmt
,locale
,err
));
558 return fmt
.release();
562 df
->adoptTimeZone(get_time_zone(info
.time_zone()));
564 // Depending if we own formatter or not
566 fmt
.reset(new date_format
<CharType
>(adf
.release(),true,encoding
));
568 fmt
.reset(new date_format
<CharType
>(df
,false,encoding
));
573 return fmt
.release();
579 formatter
<char> *formatter
<char>::create(std::ios_base
&ios
,icu::Locale
const &l
,std::string
const &e
)
581 return generate_formatter
<char>(ios
,l
,e
);
585 formatter
<wchar_t> *formatter
<wchar_t>::create(std::ios_base
&ios
,icu::Locale
const &l
,std::string
const &e
)
587 return generate_formatter
<wchar_t>(ios
,l
,e
);
591 #ifdef BOOST_LOCALE_ENABLE_CHAR16_T
593 formatter
<char16_t
> *formatter
<char16_t
>::create(std::ios_base
&ios
,icu::Locale
const &l
,std::string
const &e
)
595 return generate_formatter
<char16_t
>(ios
,l
,e
);
600 #ifdef BOOST_LOCALE_ENABLE_CHAR32_T
602 formatter
<char32_t
> *formatter
<char32_t
>::create(std::ios_base
&ios
,icu::Locale
const &l
,std::string
const &e
)
604 return generate_formatter
<char32_t
>(ios
,l
,e
);
615 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4