]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/locale/format.hpp
bump version to 18.2.4-pve3
[ceph.git] / ceph / src / boost / 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 #include <boost/locale/hold_ptr.hpp>
19
20 #include <sstream>
21
22
23 namespace boost {
24 namespace locale {
25
26 ///
27 /// \defgroup format Format
28 ///
29 /// This module provides printf like functionality integrated into iostreams and suitable for localization
30 ///
31 /// @{
32 ///
33
34 /// \cond INTERNAL
35 namespace details {
36
37 template<typename CharType>
38 struct formattible {
39 typedef std::basic_ostream<CharType> stream_type;
40 typedef void (*writer_type)(stream_type &output,void const *ptr);
41
42 formattible() :
43 pointer_(0),
44 writer_(&formattible::void_write)
45 {
46 }
47
48 formattible(formattible const &other) :
49 pointer_(other.pointer_),
50 writer_(other.writer_)
51 {
52 }
53
54 formattible const &operator=(formattible const &other)
55 {
56 if(this != &other) {
57 pointer_=other.pointer_;
58 writer_=other.writer_;
59 }
60 return *this;
61 }
62
63 template<typename Type>
64 formattible(Type const &value)
65 {
66 pointer_ = static_cast<void const *>(&value);
67 writer_ = &write<Type>;
68 }
69
70 template<typename Type>
71 formattible const &operator=(Type const &other)
72 {
73 *this = formattible(other);
74 return *this;
75 }
76
77 friend stream_type &operator<<(stream_type &out,formattible const &fmt)
78 {
79 fmt.writer_(out,fmt.pointer_);
80 return out;
81 }
82
83 private:
84 static void void_write(stream_type &output,void const * /*ptr*/)
85 {
86 CharType empty_string[1]={0};
87 output<<empty_string;
88 }
89
90 template<typename Type>
91 static void write(stream_type &output,void const *ptr)
92 {
93 output << *static_cast<Type const *>(ptr);
94 }
95
96 void const *pointer_;
97 writer_type writer_;
98 }; // formattible
99
100 class BOOST_LOCALE_DECL format_parser {
101 public:
102 format_parser(std::ios_base &ios,void *,void (*imbuer)(void *,std::locale const &));
103 ~format_parser();
104
105 unsigned get_position();
106
107 void set_one_flag(std::string const &key,std::string const &value);
108
109 template<typename CharType>
110 void set_flag_with_str(std::string const &key,std::basic_string<CharType> const &value)
111 {
112 if(key=="ftime" || key=="strftime") {
113 as::strftime(ios_);
114 ios_info::get(ios_).date_time_pattern(value);
115 }
116 }
117 void restore();
118 private:
119 void imbue(std::locale const &);
120 format_parser(format_parser const &);
121 void operator=(format_parser const &);
122
123 std::ios_base &ios_;
124 struct data;
125 hold_ptr<data> d;
126 };
127
128 }
129
130 /// \endcond
131
132 ///
133 /// \brief a printf like class that allows type-safe and locale aware message formatting
134 ///
135 /// This class creates a formatted message similar to printf or boost::format and receives
136 /// formatted entries via operator %.
137 ///
138 /// For example
139 /// \code
140 /// cout << format("Hello {1}, you are {2} years old") % name % age << endl;
141 /// \endcode
142 ///
143 /// Formatting is enclosed between curly brackets \c { \c } and defined by a comma separated list of flags in the format key[=value]
144 /// value may also be text included between single quotes \c ' that is used for special purposes where inclusion of non-ASCII
145 /// text is allowed
146 ///
147 /// Including of literal \c { and \c } is possible by specifying double brackets \c {{ and \c }} accordingly.
148 ///
149 ///
150 /// For example:
151 ///
152 /// \code
153 /// cout << format("The height of water at {1,time} is {2,num=fixed,precision=3}") % time % height;
154 /// \endcode
155 ///
156 /// The special key -- a number without a value defines the position of an input parameter.
157 /// List of keys:
158 /// - \c [0-9]+ -- digits, the index of a formatted parameter -- mandatory key.
159 /// - \c num or \c number -- format a number. Optional values are:
160 /// - \c hex -- display hexadecimal number
161 /// - \c oct -- display in octal format
162 /// - \c sci or \c scientific -- display in scientific format
163 /// - \c fix or \c fixed -- display in fixed format
164 /// .
165 /// For example \c number=sci
166 /// - \c cur or \c currency -- format currency. Optional values are:
167 ///
168 /// - \c iso -- display using ISO currency symbol.
169 /// - \c nat or \c national -- display using national currency symbol.
170 /// .
171 /// - \c per or \c percent -- format percent value.
172 /// - \c date, \c time , \c datetime or \c dt -- format date, time or date and time. Optional values are:
173 /// - \c s or \c short -- display in short format
174 /// - \c m or \c medium -- display in medium format.
175 /// - \c l or \c long -- display in long format.
176 /// - \c f or \c full -- display in full format.
177 /// .
178 /// - \c ftime with string (quoted) parameter -- display as with \c strftime see, \c as::ftime manipulator
179 /// - \c spell or \c spellout -- spell the number.
180 /// - \c ord or \c ordinal -- format ordinal number (1st, 2nd... etc)
181 /// - \c left or \c < -- align to left.
182 /// - \c right or \c > -- align to right.
183 /// - \c width or \c w -- set field width (requires parameter).
184 /// - \c precision or \c p -- set precision (requires parameter).
185 /// - \c locale -- with parameter -- switch locale for current operation. This command generates locale
186 /// with formatting facets giving more fine grained control of formatting. For example:
187 /// \code
188 /// cout << format("Today {1,date} ({1,date,locale=he_IL.UTF-8@calendar=hebrew,date} Hebrew Date)") % date;
189 /// \endcode
190 /// - \c timezone or \c tz -- the name of the timezone to display the time in. For example:\n
191 /// \code
192 /// cout << format("Time is: Local {1,time}, ({1,time,tz=EET} Eastern European Time)") % date;
193 /// \endcode
194 /// - \c local - display the time in local time
195 /// - \c gmt - display the time in UTC time scale
196 /// \code
197 /// cout << format("Local time is: {1,time,local}, universal time is {1,time,gmt}") % time;
198 /// \endcode
199 ///
200 ///
201 /// Invalid formatting strings are slightly ignored. This would prevent from translator
202 /// to crash the program in unexpected location.
203 ///
204 template<typename CharType>
205 class basic_format {
206 public:
207 typedef CharType char_type; ///< Underlying character type
208 typedef basic_message<char_type> message_type; ///< The translation message type
209 /// \cond INTERNAL
210 typedef details::formattible<CharType> formattible_type;
211 /// \endcond
212
213 typedef std::basic_string<CharType> string_type; ///< string type for this type of character
214 typedef std::basic_ostream<CharType> stream_type; ///< output stream type for this type of character
215
216
217 ///
218 /// Create a format class for \a format_string
219 ///
220 basic_format(string_type format_string) :
221 format_(format_string),
222 translate_(false),
223 parameters_count_(0)
224 {
225 }
226 ///
227 /// Create a format class using message \a trans. The message if translated first according
228 /// to the rules of target locale and then interpreted as format string
229 ///
230 basic_format(message_type const &trans) :
231 message_(trans),
232 translate_(true),
233 parameters_count_(0)
234 {
235 }
236
237 ///
238 /// Add new parameter to format list. The object should be a type
239 /// with defined expression out << object where \c out is \c std::basic_ostream.
240 ///
241 template<typename Formattible>
242 basic_format &operator % (Formattible const &object)
243 {
244 add(formattible_type(object));
245 return *this;
246 }
247
248 ///
249 /// Format a string using a locale \a loc
250 ///
251 string_type str(std::locale const &loc = std::locale()) const
252 {
253 std::basic_ostringstream<CharType> buffer;
254 buffer.imbue(loc);
255 write(buffer);
256 return buffer.str();
257 }
258
259 ///
260 /// write a formatted string to output stream \a out using out's locale
261 ///
262 void write(stream_type &out) const
263 {
264 string_type format;
265 if(translate_)
266 format = message_.str(out.getloc(),ios_info::get(out).domain_id());
267 else
268 format = format_;
269
270 format_output(out,format);
271
272 }
273
274
275 private:
276
277 class format_guard {
278 public:
279 format_guard(details::format_parser &fmt) :
280 fmt_(&fmt),
281 restored_(false)
282 {
283 }
284 void restore()
285 {
286 if(restored_)
287 return;
288 fmt_->restore();
289 restored_ = true;
290 }
291 ~format_guard()
292 {
293 try {
294 restore();
295 }
296 catch(...) {
297 }
298 }
299 private:
300 details::format_parser *fmt_;
301 bool restored_;
302 };
303
304 void format_output(stream_type &out,string_type const &sformat) const
305 {
306 char_type obrk='{';
307 char_type cbrk='}';
308 char_type eq='=';
309 char_type comma=',';
310 char_type quote='\'';
311
312 size_t pos = 0;
313 size_t size=sformat.size();
314 CharType const *format=sformat.c_str();
315 while(format[pos]!=0) {
316 if(format[pos] != obrk) {
317 if(format[pos]==cbrk && format[pos+1]==cbrk) {
318 out << cbrk;
319 pos+=2;
320 }
321 else {
322 out<<format[pos];
323 pos++;
324 }
325 continue;
326 }
327
328 if(pos+1 < size && format[pos+1]==obrk) {
329 out << obrk;
330 pos+=2;
331 continue;
332 }
333 pos++;
334
335 details::format_parser fmt(out,static_cast<void *>(&out),&basic_format::imbue_locale);
336
337 format_guard guard(fmt);
338
339 while(pos < size) {
340 std::string key;
341 std::string svalue;
342 string_type value;
343 bool use_svalue = true;
344 for(;format[pos];pos++) {
345 char_type c=format[pos];
346 if(c==comma || c==eq || c==cbrk)
347 break;
348 else {
349 key+=static_cast<char>(c);
350 }
351 }
352
353 if(format[pos]==eq) {
354 pos++;
355 if(format[pos]==quote) {
356 pos++;
357 use_svalue = false;
358 while(format[pos]) {
359 if(format[pos]==quote) {
360 if(format[pos+1]==quote) {
361 value+=quote;
362 pos+=2;
363 }
364 else {
365 pos++;
366 break;
367 }
368 }
369 else {
370 value+=format[pos];
371 pos++;
372 }
373 }
374 }
375 else {
376 char_type c;
377 while((c=format[pos])!=0 && c!=comma && c!=cbrk) {
378 svalue+=static_cast<char>(c);
379 pos++;
380 }
381 }
382 }
383
384 if(use_svalue) {
385 fmt.set_one_flag(key,svalue);
386 }
387 else
388 fmt.set_flag_with_str(key,value);
389
390 if(format[pos]==comma) {
391 pos++;
392 continue;
393 }
394 else if(format[pos]==cbrk) {
395 unsigned position = fmt.get_position();
396 out << get(position);
397 guard.restore();
398 pos++;
399 break;
400 }
401 else {
402 guard.restore();
403 break;
404 }
405 }
406 }
407 }
408
409
410 //
411 // Non-copyable
412 //
413 basic_format(basic_format const &other);
414 void operator=(basic_format const &other);
415
416 void add(formattible_type const &param)
417 {
418 if(parameters_count_ >= base_params_)
419 ext_params_.push_back(param);
420 else
421 parameters_[parameters_count_] = param;
422 parameters_count_++;
423 }
424
425 formattible_type get(unsigned id) const
426 {
427 if(id >= parameters_count_)
428 return formattible_type();
429 else if(id >= base_params_)
430 return ext_params_[id - base_params_];
431 else
432 return parameters_[id];
433 }
434
435 static void imbue_locale(void *ptr,std::locale const &l)
436 {
437 reinterpret_cast<stream_type *>(ptr)->imbue(l);
438 }
439
440
441
442 static unsigned const base_params_ = 8;
443
444 message_type message_;
445 string_type format_;
446 bool translate_;
447
448
449 formattible_type parameters_[base_params_];
450 unsigned parameters_count_;
451 std::vector<formattible_type> ext_params_;
452 };
453
454 ///
455 /// Write formatted message to stream.
456 ///
457 /// This operator actually causes actual text formatting. It uses the locale of \a out stream
458 ///
459 template<typename CharType>
460 std::basic_ostream<CharType> &operator<<(std::basic_ostream<CharType> &out,basic_format<CharType> const &fmt)
461 {
462 fmt.write(out);
463 return out;
464 }
465
466
467 ///
468 /// Definition of char based format
469 ///
470 typedef basic_format<char> format;
471
472 ///
473 /// Definition of wchar_t based format
474 ///
475 typedef basic_format<wchar_t> wformat;
476
477 #ifdef BOOST_LOCALE_ENABLE_CHAR16_T
478 ///
479 /// Definition of char16_t based format
480 ///
481 typedef basic_format<char16_t> u16format;
482 #endif
483
484 #ifdef BOOST_LOCALE_ENABLE_CHAR32_T
485 ///
486 /// Definition of char32_t based format
487 ///
488 typedef basic_format<char32_t> u32format;
489 #endif
490
491 ///
492 /// @}
493 ///
494
495 }
496 }
497
498 #ifdef BOOST_MSVC
499 #pragma warning(pop)
500 #endif
501
502 #endif
503
504 ///
505 /// \example hello.cpp
506 ///
507 /// Basic example of using various functions provided by this library
508 ///
509 /// \example whello.cpp
510 ///
511 /// Basic example of using various functions with wide strings provided by this library
512 ///
513 ///
514
515 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
516