formatting.hpp 21 KB

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