annotate DEPENDENCIES/generic/include/boost/locale/format.hpp @ 133:4acb5d8d80b6 tip

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