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 #ifndef BOOST_LOCALE_FORMATTING_HPP_INCLUDED 9 #define BOOST_LOCALE_FORMATTING_HPP_INCLUDED 10 11 #include <boost/locale/config.hpp> 12 #ifdef BOOST_MSVC 13 # pragma warning(push) 14 # pragma warning(disable : 4275 4251 4231 4660) 15 #endif 16 #include <boost/cstdint.hpp> 17 #include <boost/locale/time_zone.hpp> 18 #include <ostream> 19 #include <istream> 20 #include <string> 21 #include <string.h> 22 #include <typeinfo> 23 24 namespace boost { 25 namespace locale { 26 /// 27 /// \brief This namespace holds additional formatting 28 /// flags that can be set using ios_info. 29 /// 30 namespace flags { 31 /// 32 /// Formatting flags, each one of them has corresponding manipulation 33 /// in namespace \a as 34 /// 35 typedef enum { 36 posix = 0, 37 number = 1, 38 currency = 2, 39 percent = 3, 40 date = 4, 41 time = 5, 42 datetime = 6, 43 strftime = 7, 44 spellout = 8, 45 ordinal = 9, 46 47 display_flags_mask = 31, 48 49 currency_default = 0 << 5, 50 currency_iso = 1 << 5, 51 currency_national = 2 << 5, 52 53 currency_flags_mask = 3 << 5, 54 55 time_default = 0 << 7, 56 time_short = 1 << 7, 57 time_medium = 2 << 7, 58 time_long = 3 << 7, 59 time_full = 4 << 7, 60 time_flags_mask = 7 << 7, 61 62 date_default = 0 << 10, 63 date_short = 1 << 10, 64 date_medium = 2 << 10, 65 date_long = 3 << 10, 66 date_full = 4 << 10, 67 date_flags_mask = 7 << 10, 68 69 datetime_flags_mask = date_flags_mask | time_flags_mask 70 71 } display_flags_type; 72 73 /// 74 /// Special string patters that can be used 75 /// for text formatting 76 /// 77 typedef enum { 78 datetime_pattern, ///< strftime like formatting 79 time_zone_id ///< time zone name 80 } pattern_type; 81 82 /// 83 /// Special integer values that can be used for formatting 84 /// 85 typedef enum { 86 domain_id ///< Domain code - for message formatting 87 } value_type; 88 89 90 } // flags 91 92 /// 93 /// \brief This class holds an external data - beyond existing fmtflags that std::ios_base holds 94 /// 95 /// You should almost never create this object directly. Instead, you should access it via ios_info::get(stream_object) 96 /// static member function. It automatically creates default formatting data for that stream 97 /// 98 class BOOST_LOCALE_DECL ios_info { 99 public: 100 101 /// \cond INTERNAL 102 103 ios_info(); 104 ios_info(ios_info const &); 105 ios_info const &operator=(ios_info const &); 106 ~ios_info(); 107 108 /// \endcond 109 110 /// 111 /// Get ios_info instance for specific stream object 112 /// 113 static ios_info &get(std::ios_base &ios); 114 115 /// 116 /// Set a flags that define a way for format data like number, spell, currency etc. 117 /// 118 void display_flags(uint64_t flags); 119 120 /// 121 /// Set a flags that define how to format currency 122 /// 123 void currency_flags(uint64_t flags); 124 125 /// 126 /// Set a flags that define how to format date 127 /// 128 void date_flags(uint64_t flags); 129 130 /// 131 /// Set a flags that define how to format time 132 /// 133 void time_flags(uint64_t flags); 134 135 /// 136 /// Set a flags that define how to format both date and time 137 /// 138 void datetime_flags(uint64_t flags); 139 140 /// 141 /// Set special message domain identification 142 /// 143 void domain_id(int); 144 145 /// 146 /// Set time zone for formatting dates and time 147 /// 148 void time_zone(std::string const &); 149 150 151 /// 152 /// Set date/time pattern (strftime like) 153 /// 154 template<typename CharType> date_time_pattern(std::basic_string<CharType> const & str)155 void date_time_pattern(std::basic_string<CharType> const &str) 156 { 157 string_set &s = date_time_pattern_set(); 158 s.set<CharType>(str.c_str()); 159 } 160 161 162 /// 163 /// Get a flags that define a way for format data like number, spell, currency etc. 164 /// 165 uint64_t display_flags() const; 166 167 /// 168 /// Get a flags that define how to format currency 169 /// 170 uint64_t currency_flags() const; 171 172 173 /// 174 /// Get a flags that define how to format date 175 /// 176 uint64_t date_flags() const; 177 178 /// 179 /// Get a flags that define how to format time 180 /// 181 uint64_t time_flags() const; 182 183 /// 184 /// Get a flags that define how to format both date and time 185 /// 186 uint64_t datetime_flags() const; 187 188 /// 189 /// Get special message domain identification 190 /// 191 int domain_id() const; 192 193 /// 194 /// Get time zone for formatting dates and time 195 /// 196 std::string time_zone() const; 197 198 /// 199 /// Get date/time pattern (strftime like) 200 /// 201 template<typename CharType> date_time_pattern() const202 std::basic_string<CharType> date_time_pattern() const 203 { 204 string_set const &s = date_time_pattern_set(); 205 return s.get<CharType>(); 206 } 207 208 /// \cond INTERNAL 209 void on_imbue(); 210 /// \endcond 211 212 private: 213 214 class string_set; 215 216 string_set const &date_time_pattern_set() const; 217 string_set &date_time_pattern_set(); 218 219 class BOOST_LOCALE_DECL string_set { 220 public: 221 string_set(); 222 ~string_set(); 223 string_set(string_set const &other); 224 string_set const &operator=(string_set const &other); 225 void swap(string_set &other); 226 227 template<typename Char> set(Char const * s)228 void set(Char const *s) 229 { 230 delete [] ptr; 231 ptr = 0; 232 type=&typeid(Char); 233 Char const *end = s; 234 while(*end!=0) end++; 235 // if ptr = 0 it does not matter what is value of size 236 size = sizeof(Char)*(end - s+1); 237 ptr = new char[size]; 238 memcpy(ptr,s,size); 239 } 240 241 template<typename Char> get() const242 std::basic_string<Char> get() const 243 { 244 if(type==0 || *type!=typeid(Char)) 245 throw std::bad_cast(); 246 std::basic_string<Char> result = reinterpret_cast<Char const *>(ptr); 247 return result; 248 } 249 250 private: 251 std::type_info const *type; 252 size_t size; 253 char *ptr; 254 }; 255 256 uint64_t flags_; 257 int domain_id_; 258 std::string time_zone_; 259 string_set datetime_; 260 261 struct data; 262 data *d; 263 264 }; 265 266 267 /// 268 /// \brief This namespace includes all manipulators that can be used on IO streams 269 /// 270 namespace as { 271 /// 272 /// \defgroup manipulators I/O Stream manipulators 273 /// 274 /// @{ 275 /// 276 277 /// 278 /// Format values with "POSIX" or "C" locale. Note, if locale was created with additional non-classic locale then 279 /// These numbers may be localized 280 /// 281 posix(std::ios_base & ios)282 inline std::ios_base & posix(std::ios_base & ios) 283 { 284 ios_info::get(ios).display_flags(flags::posix); 285 return ios; 286 } 287 288 /// 289 /// Format a number. Note, unlike standard number formatting, integers would be treated like real numbers when std::fixed or 290 /// std::scientific manipulators were applied 291 /// number(std::ios_base & ios)292 inline std::ios_base & number(std::ios_base & ios) 293 { 294 ios_info::get(ios).display_flags(flags::number); 295 return ios; 296 } 297 298 /// 299 /// Format currency, number is treated like amount of money 300 /// currency(std::ios_base & ios)301 inline std::ios_base & currency(std::ios_base & ios) 302 { 303 ios_info::get(ios).display_flags(flags::currency); 304 return ios; 305 } 306 307 /// 308 /// Format percent, value 0.3 is treated as 30%. 309 /// percent(std::ios_base & ios)310 inline std::ios_base & percent(std::ios_base & ios) 311 { 312 ios_info::get(ios).display_flags(flags::percent); 313 return ios; 314 } 315 316 /// 317 /// Format a date, number is treated as POSIX time 318 /// date(std::ios_base & ios)319 inline std::ios_base & date(std::ios_base & ios) 320 { 321 ios_info::get(ios).display_flags(flags::date); 322 return ios; 323 } 324 325 /// 326 /// Format a time, number is treated as POSIX time 327 /// time(std::ios_base & ios)328 inline std::ios_base & time(std::ios_base & ios) 329 { 330 ios_info::get(ios).display_flags(flags::time); 331 return ios; 332 } 333 334 /// 335 /// Format a date and time, number is treated as POSIX time 336 /// datetime(std::ios_base & ios)337 inline std::ios_base & datetime(std::ios_base & ios) 338 { 339 ios_info::get(ios).display_flags(flags::datetime); 340 return ios; 341 } 342 343 /// 344 /// Create formatted date time, Please note, this manipulator only changes formatting mode, 345 /// and not format itself, so you are probably looking for ftime manipulator 346 /// strftime(std::ios_base & ios)347 inline std::ios_base & strftime(std::ios_base & ios) 348 { 349 ios_info::get(ios).display_flags(flags::strftime); 350 return ios; 351 } 352 353 /// 354 /// Spell the number, like "one hundred and ten" 355 /// spellout(std::ios_base & ios)356 inline std::ios_base & spellout(std::ios_base & ios) 357 { 358 ios_info::get(ios).display_flags(flags::spellout); 359 return ios; 360 } 361 362 /// 363 /// Write an order of the number like 4th. 364 /// ordinal(std::ios_base & ios)365 inline std::ios_base & ordinal(std::ios_base & ios) 366 { 367 ios_info::get(ios).display_flags(flags::ordinal); 368 return ios; 369 } 370 371 /// 372 /// Set default currency formatting style -- national, like "$" 373 /// currency_default(std::ios_base & ios)374 inline std::ios_base & currency_default(std::ios_base & ios) 375 { 376 ios_info::get(ios).currency_flags(flags::currency_default); 377 return ios; 378 } 379 380 /// 381 /// Set ISO currency formatting style, like "USD", (requires ICU >= 4.2) 382 /// currency_iso(std::ios_base & ios)383 inline std::ios_base & currency_iso(std::ios_base & ios) 384 { 385 ios_info::get(ios).currency_flags(flags::currency_iso); 386 return ios; 387 } 388 389 /// 390 /// Set national currency formatting style, like "$" 391 /// currency_national(std::ios_base & ios)392 inline std::ios_base & currency_national(std::ios_base & ios) 393 { 394 ios_info::get(ios).currency_flags(flags::currency_national); 395 return ios; 396 } 397 398 /// 399 /// set default (medium) time formatting style 400 /// time_default(std::ios_base & ios)401 inline std::ios_base & time_default(std::ios_base & ios) 402 { 403 ios_info::get(ios).time_flags(flags::time_default); 404 return ios; 405 } 406 407 /// 408 /// set short time formatting style 409 /// time_short(std::ios_base & ios)410 inline std::ios_base & time_short(std::ios_base & ios) 411 { 412 ios_info::get(ios).time_flags(flags::time_short); 413 return ios; 414 } 415 416 /// 417 /// set medium time formatting style 418 /// time_medium(std::ios_base & ios)419 inline std::ios_base & time_medium(std::ios_base & ios) 420 { 421 ios_info::get(ios).time_flags(flags::time_medium); 422 return ios; 423 } 424 425 /// 426 /// set long time formatting style 427 /// time_long(std::ios_base & ios)428 inline std::ios_base & time_long(std::ios_base & ios) 429 { 430 ios_info::get(ios).time_flags(flags::time_long); 431 return ios; 432 } 433 434 /// 435 /// set full time formatting style 436 /// time_full(std::ios_base & ios)437 inline std::ios_base & time_full(std::ios_base & ios) 438 { 439 ios_info::get(ios).time_flags(flags::time_full); 440 return ios; 441 } 442 443 /// 444 /// set default (medium) date formatting style 445 /// date_default(std::ios_base & ios)446 inline std::ios_base & date_default(std::ios_base & ios) 447 { 448 ios_info::get(ios).date_flags(flags::date_default); 449 return ios; 450 } 451 452 /// 453 /// set short date formatting style 454 /// date_short(std::ios_base & ios)455 inline std::ios_base & date_short(std::ios_base & ios) 456 { 457 ios_info::get(ios).date_flags(flags::date_short); 458 return ios; 459 } 460 461 /// 462 /// set medium date formatting style 463 /// date_medium(std::ios_base & ios)464 inline std::ios_base & date_medium(std::ios_base & ios) 465 { 466 ios_info::get(ios).date_flags(flags::date_medium); 467 return ios; 468 } 469 470 /// 471 /// set long date formatting style 472 /// date_long(std::ios_base & ios)473 inline std::ios_base & date_long(std::ios_base & ios) 474 { 475 ios_info::get(ios).date_flags(flags::date_long); 476 return ios; 477 } 478 479 /// 480 /// set full date formatting style 481 /// date_full(std::ios_base & ios)482 inline std::ios_base & date_full(std::ios_base & ios) 483 { 484 ios_info::get(ios).date_flags(flags::date_full); 485 return ios; 486 } 487 488 489 /// \cond INTERNAL 490 namespace details { 491 template<typename CharType> 492 struct add_ftime { 493 494 std::basic_string<CharType> ftime; 495 applyboost::locale::as::details::add_ftime496 void apply(std::basic_ios<CharType> &ios) const 497 { 498 ios_info::get(ios).date_time_pattern(ftime); 499 as::strftime(ios); 500 } 501 502 }; 503 504 template<typename CharType> operator <<(std::basic_ostream<CharType> & out,add_ftime<CharType> const & fmt)505 std::basic_ostream<CharType> &operator<<(std::basic_ostream<CharType> &out,add_ftime<CharType> const &fmt) 506 { 507 fmt.apply(out); 508 return out; 509 } 510 511 template<typename CharType> operator >>(std::basic_istream<CharType> & in,add_ftime<CharType> const & fmt)512 std::basic_istream<CharType> &operator>>(std::basic_istream<CharType> &in,add_ftime<CharType> const &fmt) 513 { 514 fmt.apply(in); 515 return in; 516 } 517 518 } 519 /// \endcond 520 521 /// 522 /// Set strftime like formatting string 523 /// 524 /// Please note, formatting flags are very similar but not exactly the same as flags for C function strftime. 525 /// Differences: some flags as "%e" do not add blanks to fill text up to two spaces, not all flags supported. 526 /// 527 /// Flags: 528 /// - "%a" -- Abbreviated weekday (Sun.) 529 /// - "%A" -- Full weekday (Sunday) 530 /// - "%b" -- Abbreviated month (Jan.) 531 /// - "%B" -- Full month (January) 532 /// - "%c" -- Locale date-time format. **Note:** prefer using "as::datetime" 533 /// - "%d" -- Day of Month [01,31] 534 /// - "%e" -- Day of Month [1,31] 535 /// - "%h" -- Same as "%b" 536 /// - "%H" -- 24 clock hour [00,23] 537 /// - "%I" -- 12 clock hour [01,12] 538 /// - "%j" -- Day of year [1,366] 539 /// - "%m" -- Month [01,12] 540 /// - "%M" -- Minute [00,59] 541 /// - "%n" -- New Line 542 /// - "%p" -- AM/PM in locale representation 543 /// - "%r" -- Time with AM/PM, same as "%I:%M:%S %p" 544 /// - "%R" -- Same as "%H:%M" 545 /// - "%S" -- Second [00,61] 546 /// - "%t" -- Tab character 547 /// - "%T" -- Same as "%H:%M:%S" 548 /// - "%x" -- Local date representation. **Note:** prefer using "as::date" 549 /// - "%X" -- Local time representation. **Note:** prefer using "as::time" 550 /// - "%y" -- Year [00,99] 551 /// - "%Y" -- 4 digits year. (2009) 552 /// - "%Z" -- Time Zone 553 /// - "%%" -- Percent symbol 554 /// 555 556 557 template<typename CharType> 558 #ifdef BOOST_LOCALE_DOXYGEN 559 unspecified_type 560 #else 561 details::add_ftime<CharType> 562 #endif ftime(std::basic_string<CharType> const & format)563 ftime(std::basic_string<CharType> const &format) 564 { 565 details::add_ftime<CharType> fmt; 566 fmt.ftime=format; 567 return fmt; 568 } 569 570 /// 571 /// See ftime(std::basic_string<CharType> const &format) 572 /// 573 template<typename CharType> 574 #ifdef BOOST_LOCALE_DOXYGEN 575 unspecified_type 576 #else 577 details::add_ftime<CharType> 578 #endif ftime(CharType const * format)579 ftime(CharType const *format) 580 { 581 details::add_ftime<CharType> fmt; 582 fmt.ftime=format; 583 return fmt; 584 } 585 586 /// \cond INTERNAL 587 namespace details { 588 struct set_timezone { 589 std::string id; 590 }; 591 template<typename CharType> operator <<(std::basic_ostream<CharType> & out,set_timezone const & fmt)592 std::basic_ostream<CharType> &operator<<(std::basic_ostream<CharType> &out,set_timezone const &fmt) 593 { 594 ios_info::get(out).time_zone(fmt.id); 595 return out; 596 } 597 598 template<typename CharType> operator >>(std::basic_istream<CharType> & in,set_timezone const & fmt)599 std::basic_istream<CharType> &operator>>(std::basic_istream<CharType> &in,set_timezone const &fmt) 600 { 601 ios_info::get(in).time_zone(fmt.id); 602 return in; 603 } 604 } 605 /// \endcond 606 607 /// 608 /// Set GMT time zone to stream 609 /// gmt(std::ios_base & ios)610 inline std::ios_base &gmt(std::ios_base &ios) 611 { 612 ios_info::get(ios).time_zone("GMT"); 613 return ios; 614 } 615 616 /// 617 /// Set local time zone to stream 618 /// local_time(std::ios_base & ios)619 inline std::ios_base &local_time(std::ios_base &ios) 620 { 621 ios_info::get(ios).time_zone(time_zone::global()); 622 return ios; 623 } 624 625 /// 626 /// Set time zone using \a id 627 /// 628 inline 629 #ifdef BOOST_LOCALE_DOXYGEN 630 unspecified_type 631 #else 632 details::set_timezone 633 #endif time_zone(char const * id)634 time_zone(char const *id) 635 { 636 details::set_timezone tz; 637 tz.id=id; 638 return tz; 639 } 640 641 /// 642 /// Set time zone using \a id 643 /// 644 inline 645 #ifdef BOOST_LOCALE_DOXYGEN 646 unspecified_type 647 #else 648 details::set_timezone 649 #endif time_zone(std::string const & id)650 time_zone(std::string const &id) 651 { 652 details::set_timezone tz; 653 tz.id=id; 654 return tz; 655 } 656 657 658 /// 659 /// @} 660 /// 661 662 } // as manipulators 663 664 } // locale 665 } // boost 666 667 #ifdef BOOST_MSVC 668 #pragma warning(pop) 669 #endif 670 671 672 #endif 673 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 674