Boost.Locale
format.hpp
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_FORMAT_HPP_INCLUDED
9 #define BOOST_LOCALE_FORMAT_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/locale/message.hpp>
17 #include <boost/locale/formatting.hpp>
18 
19 #include <sstream>
20 
21 
22 namespace boost {
23  namespace locale {
24 
32 
34  namespace details {
35 
36  template<typename CharType>
37  struct formattible {
38  typedef std::basic_ostream<CharType> stream_type;
39  typedef void (*writer_type)(stream_type &output,void const *ptr);
40 
41  formattible() :
42  pointer_(0),
43  writer_(&formattible::void_write)
44  {
45  }
46 
47  formattible(formattible const &other) :
48  pointer_(other.pointer_),
49  writer_(other.writer_)
50  {
51  }
52 
53  formattible const &operator=(formattible const &other)
54  {
55  if(this != &other) {
56  pointer_=other.pointer_;
57  writer_=other.writer_;
58  }
59  return *this;
60  }
61 
62  template<typename Type>
63  formattible(Type const &value)
64  {
65  pointer_ = static_cast<void const *>(&value);
66  writer_ = &write<Type>;
67  }
68 
69  template<typename Type>
70  formattible const &operator=(Type const &other)
71  {
72  *this = formattible(other);
73  return *this;
74  }
75 
76  friend stream_type &operator<<(stream_type &out,formattible const &fmt)
77  {
78  fmt.writer_(out,fmt.pointer_);
79  return out;
80  }
81 
82  private:
83  static void void_write(stream_type &output,void const * /*ptr*/)
84  {
85  CharType empty_string[1]={0};
86  output<<empty_string;
87  }
88 
89  template<typename Type>
90  static void write(stream_type &output,void const *ptr)
91  {
92  output << *static_cast<Type const *>(ptr);
93  }
94 
95  void const *pointer_;
96  writer_type writer_;
97  }; // formattible
98 
99  class BOOST_LOCALE_DECL format_parser {
100  public:
101  format_parser(std::ios_base &ios,void *,void (*imbuer)(void *,std::locale const &));
102  ~format_parser();
103 
104  unsigned get_position();
105 
106  void set_one_flag(std::string const &key,std::string const &value);
107 
108  template<typename CharType>
109  void set_flag_with_str(std::string const &key,std::basic_string<CharType> const &value)
110  {
111  if(key=="ftime" || key=="strftime") {
112  as::strftime(ios_);
113  ios_info::get(ios_).date_time_pattern(value);
114  }
115  }
116  void restore();
117  private:
118  void imbue(std::locale const &);
119  format_parser(format_parser const &);
120  void operator=(format_parser const &);
121 
122  std::ios_base &ios_;
123  struct data;
124  std::auto_ptr<data> d;
125  };
126 
127  }
128 
130 
203  template<typename CharType>
204  class basic_format {
205  public:
206  typedef CharType char_type;
208  typedef details::formattible<CharType> formattible_type;
211 
212  typedef std::basic_string<CharType> string_type;
213  typedef std::basic_ostream<CharType> stream_type;
214 
215 
219  basic_format(string_type format_string) :
220  format_(format_string),
221  translate_(false),
222  parameters_count_(0)
223  {
224  }
229  basic_format(message_type const &trans) :
230  message_(trans),
231  translate_(true),
232  parameters_count_(0)
233  {
234  }
235 
240  template<typename Formattible>
241  basic_format &operator % (Formattible const &object)
242  {
243  add(formattible_type(object));
244  return *this;
245  }
246 
250  string_type str(std::locale const &loc = std::locale()) const
251  {
252  std::basic_ostringstream<CharType> buffer;
253  buffer.imbue(loc);
254  write(buffer);
255  return buffer.str();
256  }
257 
261  void write(stream_type &out) const
262  {
264  if(translate_)
265  format = message_.str(out.getloc(),ios_info::get(out).domain_id());
266  else
267  format = format_;
268 
269  format_output(out,format);
270 
271  }
272 
273 
274  private:
275 
276  class format_guard {
277  public:
278  format_guard(details::format_parser &fmt) :
279  fmt_(&fmt),
280  restored_(false)
281  {
282  }
283  void restore()
284  {
285  if(restored_)
286  return;
287  fmt_->restore();
288  restored_ = true;
289  }
290  ~format_guard()
291  {
292  try {
293  restore();
294  }
295  catch(...) {
296  }
297  }
298  private:
299  details::format_parser *fmt_;
300  bool restored_;
301  };
302 
303  void format_output(stream_type &out,string_type const &sformat) const
304  {
305  char_type obrk='{';
306  char_type cbrk='}';
307  char_type eq='=';
308  char_type comma=',';
309  char_type quote='\'';
310 
311  size_t pos = 0;
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) {
317  out << cbrk;
318  pos+=2;
319  }
320  else {
321  out<<format[pos];
322  pos++;
323  }
324  continue;
325  }
326 
327  if(pos+1 < size && format[pos+1]==obrk) {
328  out << obrk;
329  pos+=2;
330  continue;
331  }
332  pos++;
333 
334  details::format_parser fmt(out,static_cast<void *>(&out),&basic_format::imbue_locale);
335 
336  format_guard guard(fmt);
337 
338  while(pos < size) {
339  std::string key;
340  std::string svalue;
341  string_type value;
342  bool use_svalue = true;
343  for(;format[pos];pos++) {
344  char_type c=format[pos];
345  if(c==comma || c==eq || c==cbrk)
346  break;
347  else {
348  key+=static_cast<char>(c);
349  }
350  }
351 
352  if(format[pos]==eq) {
353  pos++;
354  if(format[pos]==quote) {
355  pos++;
356  use_svalue = false;
357  while(format[pos]) {
358  if(format[pos]==quote) {
359  if(format[pos+1]==quote) {
360  value+=quote;
361  pos+=2;
362  }
363  else {
364  pos++;
365  break;
366  }
367  }
368  else {
369  value+=format[pos];
370  pos++;
371  }
372  }
373  }
374  else {
375  char_type c;
376  while((c=format[pos])!=0 && c!=comma && c!=cbrk) {
377  svalue+=static_cast<char>(c);
378  pos++;
379  }
380  }
381  }
382 
383  if(use_svalue) {
384  fmt.set_one_flag(key,svalue);
385  }
386  else
387  fmt.set_flag_with_str(key,value);
388 
389  if(format[pos]==comma) {
390  pos++;
391  continue;
392  }
393  else if(format[pos]==cbrk) {
394  unsigned position = fmt.get_position();
395  out << get(position);
396  guard.restore();
397  pos++;
398  break;
399  }
400  else {
401  guard.restore();
402  break;
403  }
404  }
405  }
406  }
407 
408 
409  //
410  // Non-copyable
411  //
412  basic_format(basic_format const &other);
413  void operator=(basic_format const &other);
414 
415  void add(formattible_type const &param)
416  {
417  if(parameters_count_ >= base_params_)
418  ext_params_.push_back(param);
419  else
420  parameters_[parameters_count_] = param;
421  parameters_count_++;
422  }
423 
424  formattible_type get(unsigned id) const
425  {
426  if(id >= parameters_count_)
427  return formattible_type();
428  else if(id >= base_params_)
429  return ext_params_[id - base_params_];
430  else
431  return parameters_[id];
432  }
433 
434  static void imbue_locale(void *ptr,std::locale const &l)
435  {
436  reinterpret_cast<stream_type *>(ptr)->imbue(l);
437  }
438 
439 
440 
441  static unsigned const base_params_ = 8;
442 
443  message_type message_;
444  string_type format_;
445  bool translate_;
446 
447 
448  formattible_type parameters_[base_params_];
449  unsigned parameters_count_;
450  std::vector<formattible_type> ext_params_;
451  };
452 
458  template<typename CharType>
459  std::basic_ostream<CharType> &operator<<(std::basic_ostream<CharType> &out,basic_format<CharType> const &fmt)
460  {
461  fmt.write(out);
462  return out;
463  }
464 
465 
470 
475 
476  #ifdef BOOST_LOCALE_ENABLE_CHAR16_T
481  #endif
482 
483  #ifdef BOOST_LOCALE_ENABLE_CHAR32_T
488  #endif
489 
493 
494  }
495 }
496 
497 #ifdef BOOST_MSVC
498 #pragma warning(pop)
499 #endif
500 
501 #endif
502 
513 
514 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
515 
basic_format< char32_t > u32format
Definition: format.hpp:487
a printf like class that allows type-safe and locale aware message formatting
Definition: format.hpp:204
basic_format & operator%(Formattible const &object)
Definition: format.hpp:241
std::basic_string< CharType > string_type
string type for this type of character
Definition: format.hpp:212
std::ios_base & strftime(std::ios_base &ios)
Definition: formatting.hpp:347
basic_format(message_type const &trans)
Definition: format.hpp:229
string_type str() const
Definition: message.hpp:353
basic_format(string_type format_string)
Definition: format.hpp:219
static ios_info & get(std::ios_base &ios)
std::basic_ostream< CharType > stream_type
output stream type for this type of character
Definition: format.hpp:213
std::basic_ostream< CharType > & operator<<(std::basic_ostream< CharType > &out, date_time const &t)
Definition: date_time.hpp:874
CharType char_type
Underlying character type.
Definition: format.hpp:206
basic_format< wchar_t > wformat
Definition: format.hpp:474
string_type str(std::locale const &loc=std::locale()) const
Definition: format.hpp:250
basic_format< char16_t > u16format
Definition: format.hpp:480
basic_format< char > format
Definition: format.hpp:469
basic_message< char_type > message_type
Definition: format.hpp:207
void date_time_pattern(std::basic_string< CharType > const &str)
Definition: formatting.hpp:155
void write(stream_type &out) const
Definition: format.hpp:261