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