]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/locale/src/icu/formatter.cpp
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / boost / libs / locale / src / icu / formatter.cpp
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 <boost/locale/formatting.hpp>
10 #include "formatter.hpp"
11 #include <boost/locale/info.hpp>
12 #include "uconv.hpp"
13
14
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>
20
21 #include <limits>
22
23 #include <iostream>
24
25 #include "predefined_formatters.hpp"
26 #include "time_zone.hpp"
27
28 #ifdef BOOST_MSVC
29 # pragma warning(disable : 4244) // lose data
30 #endif
31
32
33 namespace boost {
34 namespace locale {
35 namespace impl_icu {
36
37
38 std::locale::id icu_formatters_cache::id;
39
40 namespace {
41 struct init { init() { std::has_facet<icu_formatters_cache>(std::locale::classic()); } } instance;
42 }
43
44
45 template<typename CharType>
46 class number_format : public formatter<CharType> {
47 public:
48 typedef CharType char_type;
49 typedef std::basic_string<CharType> string_type;
50
51 virtual string_type format(double value,size_t &code_points) const
52 {
53 icu::UnicodeString tmp;
54 icu_fmt_->format(value,tmp);
55 code_points=tmp.countChar32();
56 return cvt_.std(tmp);
57 }
58 virtual string_type format(int64_t value,size_t &code_points) const
59 {
60 icu::UnicodeString tmp;
61 icu_fmt_->format(static_cast< ::int64_t>(value),tmp);
62 code_points=tmp.countChar32();
63 return cvt_.std(tmp);
64 }
65
66 virtual string_type format(int32_t value,size_t &code_points) const
67 {
68 icu::UnicodeString tmp;
69 #ifdef __SUNPRO_CC
70 icu_fmt_->format(static_cast<int>(value),tmp);
71 #else
72 icu_fmt_->format(::int32_t(value),tmp);
73 #endif
74 code_points=tmp.countChar32();
75 return cvt_.std(tmp);
76 }
77
78 virtual size_t parse(string_type const &str,double &value) const
79 {
80 return do_parse(str,value);
81 }
82
83 virtual size_t parse(string_type const &str,int64_t &value) const
84 {
85 return do_parse(str,value);
86 }
87 virtual size_t parse(string_type const &str,int32_t &value) const
88 {
89 return do_parse(str,value);
90 }
91
92 number_format(icu::NumberFormat *fmt,std::string codepage) :
93 cvt_(codepage),
94 icu_fmt_(fmt)
95 {
96 }
97
98 private:
99
100 bool get_value(double &v,icu::Formattable &fmt) const
101 {
102 UErrorCode err=U_ZERO_ERROR;
103 v=fmt.getDouble(err);
104 if(U_FAILURE(err))
105 return false;
106 return true;
107 }
108
109 bool get_value(int64_t &v,icu::Formattable &fmt) const
110 {
111 UErrorCode err=U_ZERO_ERROR;
112 v=fmt.getInt64(err);
113 if(U_FAILURE(err))
114 return false;
115 return true;
116 }
117
118 bool get_value(int32_t &v,icu::Formattable &fmt) const
119 {
120 UErrorCode err=U_ZERO_ERROR;
121 v=fmt.getLong(err);
122 if(U_FAILURE(err))
123 return false;
124 return true;
125 }
126
127 template<typename ValueType>
128 size_t do_parse(string_type const &str,ValueType &v) const
129 {
130 icu::Formattable val;
131 icu::ParsePosition pp;
132 icu::UnicodeString tmp = cvt_.icu(str.data(),str.data()+str.size());
133
134 icu_fmt_->parse(tmp,val,pp);
135
136 ValueType tmp_v;
137
138 if(pp.getIndex() == 0 || !get_value(tmp_v,val))
139 return 0;
140 size_t cut = cvt_.cut(tmp,str.data(),str.data()+str.size(),pp.getIndex());
141 if(cut==0)
142 return 0;
143 v=tmp_v;
144 return cut;
145 }
146
147 icu_std_converter<CharType> cvt_;
148 icu::NumberFormat *icu_fmt_;
149 };
150
151
152 template<typename CharType>
153 class date_format : public formatter<CharType> {
154 public:
155 typedef CharType char_type;
156 typedef std::basic_string<CharType> string_type;
157
158 virtual string_type format(double value,size_t &code_points) const
159 {
160 return do_format(value,code_points);
161 }
162 virtual string_type format(int64_t value,size_t &code_points) const
163 {
164 return do_format(value,code_points);
165 }
166
167 virtual string_type format(int32_t value,size_t &code_points) const
168 {
169 return do_format(value,code_points);
170 }
171
172 virtual size_t parse(string_type const &str,double &value) const
173 {
174 return do_parse(str,value);
175 }
176 virtual size_t parse(string_type const &str,int64_t &value) const
177 {
178 return do_parse(str,value);
179 }
180 virtual size_t parse(string_type const &str,int32_t &value) const
181 {
182 return do_parse(str,value);
183 }
184
185 date_format(icu::DateFormat *fmt,bool transfer_owneship,std::string codepage) :
186 cvt_(codepage)
187 {
188 if(transfer_owneship) {
189 aicu_fmt_.reset(fmt);
190 icu_fmt_ = aicu_fmt_.get();
191 }
192 else {
193 icu_fmt_ = fmt;
194 }
195 }
196
197 private:
198
199 template<typename ValueType>
200 size_t do_parse(string_type const &str,ValueType &value) const
201 {
202 icu::ParsePosition pp;
203 icu::UnicodeString tmp = cvt_.icu(str.data(),str.data() + str.size());
204
205 UDate udate = icu_fmt_->parse(tmp,pp);
206 if(pp.getIndex() == 0)
207 return 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())
211 return 0;
212 size_t cut = cvt_.cut(tmp,str.data(),str.data()+str.size(),pp.getIndex());
213 if(cut==0)
214 return 0;
215 value=static_cast<ValueType>(date);
216 return cut;
217
218 }
219
220 string_type do_format(double value,size_t &codepoints) const
221 {
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);
227 }
228
229 icu_std_converter<CharType> cvt_;
230 hold_ptr<icu::DateFormat> aicu_fmt_;
231 icu::DateFormat *icu_fmt_;
232 };
233
234 icu::UnicodeString strftime_to_icu_full(icu::DateFormat *dfin,char const *alt)
235 {
236 hold_ptr<icu::DateFormat> df(dfin);
237 icu::SimpleDateFormat *sdf=dynamic_cast<icu::SimpleDateFormat *>(df.get());
238 icu::UnicodeString tmp;
239 if(sdf) {
240 sdf->toPattern(tmp);
241 }
242 else {
243 tmp=alt;
244 }
245 return tmp;
246
247 }
248
249 icu::UnicodeString strftime_to_icu_symbol(char c,icu::Locale const &locale,icu_formatters_cache const *cache=0)
250 {
251 switch(c) {
252 case 'a': // Abbr Weekday
253 return "EE";
254 case 'A': // Full Weekday
255 return "EEEE";
256 case 'b': // Abbr Month
257 return "MMM";
258 case 'B': // Full Month
259 return "MMMM";
260 case 'c': // DateTile Full
261 {
262 if(cache)
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"
267 );
268 }
269 // not supported by ICU ;(
270 // case 'C': // Century -> 1980 -> 19
271 // retur
272 case 'd': // Day of Month [01,31]
273 return "dd";
274 case 'D': // %m/%d/%y
275 return "MM/dd/yy";
276 case 'e': // Day of Month [1,31]
277 return "d";
278 case 'h': // == b
279 return "MMM";
280 case 'H': // 24 clock hour 00,23
281 return "HH";
282 case 'I': // 12 clock hour 01,12
283 return "hh";
284 case 'j': // day of year 001,366
285 return "D";
286 case 'm': // month as [01,12]
287 return "MM";
288 case 'M': // minute [00,59]
289 return "mm";
290 case 'n': // \n
291 return "\n";
292 case 'p': // am-pm
293 return "a";
294 case 'r': // time with AM/PM %I:%M:%S %p
295 return "hh:mm:ss a";
296 case 'R': // %H:%M
297 return "HH:mm";
298 case 'S': // second [00,61]
299 return "ss";
300 case 't': // \t
301 return "\t";
302 case 'T': // %H:%M:%S
303 return "HH:mm:ss";
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, */
309 case 'x': // Date
310 {
311 if(cache)
312 return cache->date_format_[1];
313 return strftime_to_icu_full(
314 icu::DateFormat::createDateInstance(icu::DateFormat::kMedium,locale),
315 "yyyy-MM-dd"
316 );
317 }
318 case 'X': // Time
319 {
320 if(cache)
321 return cache->time_format_[1];
322 return strftime_to_icu_full(
323 icu::DateFormat::createTimeInstance(icu::DateFormat::kMedium,locale),
324 "HH:mm:ss"
325 );
326 }
327 case 'y': // Year [00-99]
328 return "yy";
329 case 'Y': // Year 1998
330 return "yyyy";
331 case 'Z': // timezone
332 return "vvvv";
333 case '%': // %
334 return "%";
335 default:
336 return "";
337 }
338 }
339
340 icu::UnicodeString strftime_to_icu(icu::UnicodeString const &ftime,icu::Locale const &locale)
341 {
342 unsigned len=ftime.length();
343 icu::UnicodeString result;
344 bool escaped=false;
345 for(unsigned i=0;i<len;i++) {
346 UChar c=ftime[i];
347 if(c=='%') {
348 i++;
349 c=ftime[i];
350 if(c=='E' || c=='O') {
351 i++;
352 c=ftime[i];
353 }
354 if(escaped) {
355 result+="'";
356 escaped=false;
357 }
358 result+=strftime_to_icu_symbol(c,locale);
359 }
360 else if(c=='\'') {
361 result+="''";
362 }
363 else {
364 if(!escaped) {
365 result+="'";
366 escaped=true;
367 }
368 result+=c;
369 }
370 }
371 if(escaped)
372 result+="'";
373 return result;
374 }
375
376 template<typename CharType>
377 formatter<CharType> *generate_formatter(
378 std::ios_base &ios,
379 icu::Locale const &locale,
380 std::string const &encoding)
381 {
382 using namespace boost::locale::flags;
383
384 hold_ptr<formatter<CharType> > fmt;
385 ios_info &info=ios_info::get(ios);
386 uint64_t disp = info.display_flags();
387
388 icu_formatters_cache const &cache = std::use_facet<icu_formatters_cache>(ios.getloc());
389
390
391 if(disp == posix)
392 return fmt.release();
393
394 UErrorCode err=U_ZERO_ERROR;
395
396 switch(disp) {
397 case number:
398 {
399 std::ios_base::fmtflags how = (ios.flags() & std::ios_base::floatfield);
400 icu::NumberFormat *nf = 0;
401
402 if(how == std::ios_base::scientific)
403 nf = cache.number_format(icu_formatters_cache::fmt_sci);
404 else
405 nf = cache.number_format(icu_formatters_cache::fmt_number);
406
407 nf->setMaximumFractionDigits(ios.precision());
408 if(how == std::ios_base::scientific || how == std::ios_base::fixed ) {
409 nf->setMinimumFractionDigits(ios.precision());
410 }
411 else {
412 nf->setMinimumFractionDigits(0);
413 }
414 fmt.reset(new number_format<CharType>(nf,encoding));
415 }
416 break;
417 case currency:
418 {
419 icu::NumberFormat *nf;
420
421 uint64_t curr = info.currency_flags();
422
423 if(curr == currency_default || curr == currency_national)
424 nf = cache.number_format(icu_formatters_cache::fmt_curr_nat);
425 else
426 nf = cache.number_format(icu_formatters_cache::fmt_curr_iso);
427
428 fmt.reset(new number_format<CharType>(nf,encoding));
429 }
430 break;
431 case percent:
432 {
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());
438 }
439 else {
440 nf->setMinimumFractionDigits(0);
441 }
442 fmt.reset(new number_format<CharType>(nf,encoding));
443
444 }
445 break;
446 case spellout:
447 fmt.reset(new number_format<CharType>(cache.number_format(icu_formatters_cache::fmt_spell),encoding));
448 break;
449 case ordinal:
450 fmt.reset(new number_format<CharType>(cache.number_format(icu_formatters_cache::fmt_ord),encoding));
451 break;
452 case date:
453 case time:
454 case datetime:
455 case strftime:
456 {
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
462 if(sdf) {
463 int tmf=info.time_flags();
464 switch(tmf) {
465 case time_short:
466 tmf=0;
467 break;
468 case time_long:
469 tmf=2;
470 break;
471 case time_full:
472 tmf=3;
473 break;
474 case time_default:
475 case time_medium:
476 default:
477 tmf=1;
478 }
479 int dtf=info.date_flags();
480 switch(dtf) {
481 case date_short:
482 dtf=0;
483 break;
484 case date_long:
485 dtf=2;
486 break;
487 case date_full:
488 dtf=3;
489 break;
490 case date_default:
491 case date_medium:
492 default:
493 dtf=1;
494 }
495
496 icu::UnicodeString pattern;
497 switch(disp) {
498 case date:
499 pattern = cache.date_format_[dtf];
500 break;
501 case time:
502 pattern = cache.time_format_[tmf];
503 break;
504 case datetime:
505 pattern = cache.date_time_format_[dtf][tmf];
506 break;
507 case strftime:
508 {
509 if( !cache.date_format_[1].isEmpty()
510 && !cache.time_format_[1].isEmpty()
511 && !cache.date_time_format_[1][1].isEmpty())
512 {
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);
516 }
517 }
518 break;
519 }
520 if(!pattern.isEmpty()) {
521 sdf->applyPattern(pattern);
522 df = sdf;
523 sdf = 0;
524 }
525 sdf = 0;
526 }
527
528 if(!df) {
529 icu::DateFormat::EStyle dstyle = icu::DateFormat::kDefault;
530 icu::DateFormat::EStyle tstyle = icu::DateFormat::kDefault;
531
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;
537 }
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;
543 }
544
545 if(disp==date)
546 adf.reset(icu::DateFormat::createDateInstance(dstyle,locale));
547 else if(disp==time)
548 adf.reset(icu::DateFormat::createTimeInstance(tstyle,locale));
549 else if(disp==datetime)
550 adf.reset(icu::DateFormat::createDateTimeInstance(dstyle,tstyle,locale));
551 else {// strftime
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));
556 }
557 if(U_FAILURE(err))
558 return fmt.release();
559 df = adf.get();
560 }
561
562 df->adoptTimeZone(get_time_zone(info.time_zone()));
563
564 // Depending if we own formatter or not
565 if(adf.get())
566 fmt.reset(new date_format<CharType>(adf.release(),true,encoding));
567 else
568 fmt.reset(new date_format<CharType>(df,false,encoding));
569 }
570 break;
571 }
572
573 return fmt.release();
574 }
575
576
577
578 template<>
579 formatter<char> *formatter<char>::create(std::ios_base &ios,icu::Locale const &l,std::string const &e)
580 {
581 return generate_formatter<char>(ios,l,e);
582 }
583
584 template<>
585 formatter<wchar_t> *formatter<wchar_t>::create(std::ios_base &ios,icu::Locale const &l,std::string const &e)
586 {
587 return generate_formatter<wchar_t>(ios,l,e);
588 }
589
590
591 #ifdef BOOST_LOCALE_ENABLE_CHAR16_T
592 template<>
593 formatter<char16_t> *formatter<char16_t>::create(std::ios_base &ios,icu::Locale const &l,std::string const &e)
594 {
595 return generate_formatter<char16_t>(ios,l,e);
596 }
597
598 #endif
599
600 #ifdef BOOST_LOCALE_ENABLE_CHAR32_T
601 template<>
602 formatter<char32_t> *formatter<char32_t>::create(std::ios_base &ios,icu::Locale const &l,std::string const &e)
603 {
604 return generate_formatter<char32_t>(ios,l,e);
605 }
606
607 #endif
608
609 } // impl_icu
610
611 } // locale
612 } // boost
613
614
615 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
616
617
618