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 #ifndef BOOST_LOCALE_FORMAT_HPP_INCLUDED
9 #define BOOST_LOCALE_FORMAT_HPP_INCLUDED
11 #include <boost/locale/config.hpp>
13 # pragma warning(push)
14 # pragma warning(disable : 4275 4251 4231 4660)
16 #include <boost/locale/message.hpp>
17 #include <boost/locale/formatting.hpp>
26 /// \defgroup format Format
28 /// This module provides printf like functionality integrated into iostreams and suitable for localization
36 template<typename CharType>
38 typedef std::basic_ostream<CharType> stream_type;
39 typedef void (*writer_type)(stream_type &output,void const *ptr);
43 writer_(&formattible::void_write)
47 formattible(formattible const &other) :
48 pointer_(other.pointer_),
49 writer_(other.writer_)
53 formattible const &operator=(formattible const &other)
56 pointer_=other.pointer_;
57 writer_=other.writer_;
62 template<typename Type>
63 formattible(Type const &value)
65 pointer_ = static_cast<void const *>(&value);
66 writer_ = &write<Type>;
69 template<typename Type>
70 formattible const &operator=(Type const &other)
72 *this = formattible(other);
76 friend stream_type &operator<<(stream_type &out,formattible const &fmt)
78 fmt.writer_(out,fmt.pointer_);
83 static void void_write(stream_type &output,void const * /*ptr*/)
85 CharType empty_string[1]={0};
89 template<typename Type>
90 static void write(stream_type &output,void const *ptr)
92 output << *static_cast<Type const *>(ptr);
99 class BOOST_LOCALE_DECL format_parser {
101 format_parser(std::ios_base &ios,void *,void (*imbuer)(void *,std::locale const &));
104 unsigned get_position();
106 void set_one_flag(std::string const &key,std::string const &value);
108 template<typename CharType>
109 void set_flag_with_str(std::string const &key,std::basic_string<CharType> const &value)
111 if(key=="ftime" || key=="strftime") {
113 ios_info::get(ios_).date_time_pattern(value);
118 void imbue(std::locale const &);
119 format_parser(format_parser const &);
120 void operator=(format_parser const &);
124 std::auto_ptr<data> d;
132 /// \brief a printf like class that allows type-safe and locale aware message formatting
134 /// This class creates a formatted message similar to printf or boost::format and receives
135 /// formatted entries via operator %.
139 /// cout << format("Hello {1}, you are {2} years old") % name % age << endl;
142 /// Formatting is enclosed between curly brackets \c { \c } and defined by a comma separated list of flags in the format key[=value]
143 /// value may also be text included between single quotes \c ' that is used for special purposes where inclusion of non-ASCII
146 /// Including of literal \c { and \c } is possible by specifying double brackets \c {{ and \c }} accordingly.
152 /// cout << format("The height of water at {1,time} is {2,num=fixed,precision=3}") % time % height;
155 /// The special key -- a number without a value defines the position of an input parameter.
157 /// - \c [0-9]+ -- digits, the index of a formatted parameter -- mandatory key.
158 /// - \c num or \c number -- format a number. Optional values are:
159 /// - \c hex -- display hexadecimal number
160 /// - \c oct -- display in octal format
161 /// - \c sci or \c scientific -- display in scientific format
162 /// - \c fix or \c fixed -- display in fixed format
164 /// For example \c number=sci
165 /// - \c cur or \c currency -- format currency. Optional values are:
167 /// - \c iso -- display using ISO currency symbol.
168 /// - \c nat or \c national -- display using national currency symbol.
170 /// - \c per or \c percent -- format percent value.
171 /// - \c date, \c time , \c datetime or \c dt -- format date, time or date and time. Optional values are:
172 /// - \c s or \c short -- display in short format
173 /// - \c m or \c medium -- display in medium format.
174 /// - \c l or \c long -- display in long format.
175 /// - \c f or \c full -- display in full format.
177 /// - \c ftime with string (quoted) parameter -- display as with \c strftime see, \c as::ftime manipulator
178 /// - \c spell or \c spellout -- spell the number.
179 /// - \c ord or \c ordinal -- format ordinal number (1st, 2nd... etc)
180 /// - \c left or \c < -- align to left.
181 /// - \c right or \c > -- align to right.
182 /// - \c width or \c w -- set field width (requires parameter).
183 /// - \c precision or \c p -- set precision (requires parameter).
184 /// - \c locale -- with parameter -- switch locale for current operation. This command generates locale
185 /// with formatting facets giving more fine grained control of formatting. For example:
187 /// cout << format("Today {1,date} ({1,date,locale=he_IL.UTF-8@calendar=hebrew,date} Hebrew Date)") % date;
189 /// - \c timezone or \c tz -- the name of the timezone to display the time in. For example:\n
191 /// cout << format("Time is: Local {1,time}, ({1,time,tz=EET} Eastern European Time)") % date;
193 /// - \c local - display the time in local time
194 /// - \c gmt - display the time in UTC time scale
196 /// cout << format("Local time is: {1,time,local}, universal time is {1,time,gmt}") % time;
200 /// Invalid formatting strings are slightly ignored. This would prevent from translator
201 /// to crash the program in unexpected location.
203 template<typename CharType>
206 typedef CharType char_type; ///< Underlying character type
207 typedef basic_message<char_type> message_type; ///< The translation message type
209 typedef details::formattible<CharType> formattible_type;
212 typedef std::basic_string<CharType> string_type; ///< string type for this type of character
213 typedef std::basic_ostream<CharType> stream_type; ///< output stream type for this type of character
217 /// Create a format class for \a format_string
219 basic_format(string_type format_string) :
220 format_(format_string),
226 /// Create a format class using message \a trans. The message if translated first according
227 /// to the rules of target locale and then interpreted as format string
229 basic_format(message_type const &trans) :
237 /// Add new parameter to format list. The object should be a type
238 /// with defined expression out << object where \c out is \c std::basic_ostream.
240 template<typename Formattible>
241 basic_format &operator % (Formattible const &object)
243 add(formattible_type(object));
248 /// Format a string using a locale \a loc
250 string_type str(std::locale const &loc = std::locale()) const
252 std::basic_ostringstream<CharType> buffer;
259 /// write a formatted string to output stream \a out using out's locale
261 void write(stream_type &out) const
265 format = message_.str(out.getloc(),ios_info::get(out).domain_id());
269 format_output(out,format);
278 format_guard(details::format_parser &fmt) :
299 details::format_parser *fmt_;
303 void format_output(stream_type &out,string_type const &sformat) const
309 char_type quote='\'';
312 size_t size=sformat.size();
313 CharType const *format=sformat.c_str();
314 while(format[pos]!=0) {
315 if(format[pos] != obrk) {
316 if(format[pos]==cbrk && format[pos+1]==cbrk) {
327 if(pos+1 < size && format[pos+1]==obrk) {
334 details::format_parser fmt(out,static_cast<void *>(&out),&basic_format::imbue_locale);
336 format_guard guard(fmt);
342 bool use_svalue = true;
343 for(;format[pos];pos++) {
344 char_type c=format[pos];
345 if(c==comma || c==eq || c==cbrk)
348 key+=static_cast<char>(c);
352 if(format[pos]==eq) {
354 if(format[pos]==quote) {
358 if(format[pos]==quote) {
359 if(format[pos+1]==quote) {
376 while((c=format[pos])!=0 && c!=comma && c!=cbrk) {
377 svalue+=static_cast<char>(c);
384 fmt.set_one_flag(key,svalue);
387 fmt.set_flag_with_str(key,value);
389 if(format[pos]==comma) {
393 else if(format[pos]==cbrk) {
394 unsigned position = fmt.get_position();
395 out << get(position);
412 basic_format(basic_format const &other);
413 void operator=(basic_format const &other);
415 void add(formattible_type const ¶m)
417 if(parameters_count_ >= base_params_)
418 ext_params_.push_back(param);
420 parameters_[parameters_count_] = param;
424 formattible_type get(unsigned id) const
426 if(id >= parameters_count_)
427 return formattible_type();
428 else if(id >= base_params_)
429 return ext_params_[id - base_params_];
431 return parameters_[id];
434 static void imbue_locale(void *ptr,std::locale const &l)
436 reinterpret_cast<stream_type *>(ptr)->imbue(l);
441 static unsigned const base_params_ = 8;
443 message_type message_;
448 formattible_type parameters_[base_params_];
449 unsigned parameters_count_;
450 std::vector<formattible_type> ext_params_;
454 /// Write formatted message to stream.
456 /// This operator actually causes actual text formatting. It uses the locale of \a out stream
458 template<typename CharType>
459 std::basic_ostream<CharType> &operator<<(std::basic_ostream<CharType> &out,basic_format<CharType> const &fmt)
467 /// Definition of char based format
469 typedef basic_format<char> format;
472 /// Definition of wchar_t based format
474 typedef basic_format<wchar_t> wformat;
476 #ifdef BOOST_LOCALE_ENABLE_CHAR16_T
478 /// Definition of char16_t based format
480 typedef basic_format<char16_t> u16format;
483 #ifdef BOOST_LOCALE_ENABLE_CHAR32_T
485 /// Definition of char32_t based format
487 typedef basic_format<char32_t> u32format;
504 /// \example hello.cpp
506 /// Basic example of using various functions provided by this library
508 /// \example whello.cpp
510 /// Basic example of using various functions with wide strings provided by this library
514 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4