00001
00002
00003
00004
00005
00006
00007
00008 #ifndef BOOSTER_LOCALE_FORMAT_H_INCLUDED
00009 #define BOOSTER_LOCALE_FORMAT_H_INCLUDED
00010
00011 #include <booster/config.h>
00012 #ifdef BOOSTER_MSVC
00013 # pragma warning(push)
00014 # pragma warning(disable : 4275 4251 4231 4660)
00015 #endif
00016 #include <booster/locale/message.h>
00017 #include <booster/locale/formatting.h>
00018
00019 #include <sstream>
00020
00021
00022 namespace booster {
00023 namespace locale {
00024
00032
00034 namespace details {
00035
00036 template<typename CharType>
00037 struct formattible {
00038 typedef std::basic_ostream<CharType> stream_type;
00039 typedef void (*writer_type)(stream_type &output,void const *ptr);
00040
00041 formattible() :
00042 pointer_(0),
00043 writer_(&formattible::void_write)
00044 {
00045 }
00046
00047 formattible(formattible const &other) :
00048 pointer_(other.pointer_),
00049 writer_(other.writer_)
00050 {
00051 }
00052
00053 formattible const &operator=(formattible const &other)
00054 {
00055 if(this != &other) {
00056 pointer_=other.pointer_;
00057 writer_=other.writer_;
00058 }
00059 return *this;
00060 }
00061
00062 template<typename Type>
00063 formattible(Type const &value)
00064 {
00065 pointer_ = static_cast<void const *>(&value);
00066 writer_ = &write<Type>;
00067 }
00068
00069 template<typename Type>
00070 formattible const &operator=(Type const &other)
00071 {
00072 *this = formattible(other);
00073 return *this;
00074 }
00075
00076 friend stream_type &operator<<(stream_type &out,formattible const &fmt)
00077 {
00078 fmt.writer_(out,fmt.pointer_);
00079 return out;
00080 }
00081
00082 private:
00083 static void void_write(stream_type &output,void const * )
00084 {
00085 CharType empty_string[1]={0};
00086 output<<empty_string;
00087 }
00088
00089 template<typename Type>
00090 static void write(stream_type &output,void const *ptr)
00091 {
00092 output << *static_cast<Type const *>(ptr);
00093 }
00094
00095 void const *pointer_;
00096 writer_type writer_;
00097 };
00098
00099 class BOOSTER_API format_parser {
00100 public:
00101 format_parser(std::ios_base &ios,void *,void (*imbuer)(void *,std::locale const &));
00102 ~format_parser();
00103
00104 unsigned get_position();
00105
00106 void set_one_flag(std::string const &key,std::string const &value);
00107
00108 template<typename CharType>
00109 void set_flag_with_str(std::string const &key,std::basic_string<CharType> const &value)
00110 {
00111 if(key=="ftime" || key=="strftime") {
00112 as::strftime(ios_);
00113 ios_info::get(ios_).date_time_pattern(value);
00114 }
00115 }
00116 void restore();
00117 private:
00118 void imbue(std::locale const &);
00119 format_parser(format_parser const &);
00120 void operator=(format_parser const &);
00121
00122 std::ios_base &ios_;
00123 struct data;
00124 std::auto_ptr<data> d;
00125 };
00126
00127 }
00128
00130
00203 template<typename CharType>
00204 class basic_format {
00205 public:
00206 typedef CharType char_type;
00207 typedef basic_message<char_type> message_type;
00208
00209 typedef details::formattible<CharType> formattible_type;
00211
00212 typedef std::basic_string<CharType> string_type;
00213 typedef std::basic_ostream<CharType> stream_type;
00214
00215
00219 basic_format(string_type format_string) :
00220 format_(format_string),
00221 translate_(false),
00222 parameters_count_(0)
00223 {
00224 }
00229 basic_format(message_type const &trans) :
00230 message_(trans),
00231 translate_(true),
00232 parameters_count_(0)
00233 {
00234 }
00235
00240 template<typename Formattible>
00241 basic_format &operator % (Formattible const &object)
00242 {
00243 add(formattible_type(object));
00244 return *this;
00245 }
00246
00250 string_type str(std::locale const &loc = std::locale()) const
00251 {
00252 std::basic_ostringstream<CharType> buffer;
00253 buffer.imbue(loc);
00254 write(buffer);
00255 return buffer.str();
00256 }
00257
00261 void write(stream_type &out) const
00262 {
00263 string_type format;
00264 if(translate_)
00265 format = message_.str(out.getloc(),ios_info::get(out).domain_id());
00266 else
00267 format = format_;
00268
00269 format_output(out,format);
00270
00271 }
00272
00273
00274 private:
00275
00276 class format_guard {
00277 public:
00278 format_guard(details::format_parser &fmt) :
00279 fmt_(&fmt),
00280 restored_(false)
00281 {
00282 }
00283 void restore()
00284 {
00285 if(restored_)
00286 return;
00287 fmt_->restore();
00288 restored_ = true;
00289 }
00290 ~format_guard()
00291 {
00292 try {
00293 restore();
00294 }
00295 catch(...) {
00296 }
00297 }
00298 private:
00299 details::format_parser *fmt_;
00300 bool restored_;
00301 };
00302
00303 void format_output(stream_type &out,string_type const &sformat) const
00304 {
00305 char_type obrk='{';
00306 char_type cbrk='}';
00307 char_type eq='=';
00308 char_type comma=',';
00309 char_type quote='\'';
00310
00311 size_t pos = 0;
00312 size_t size=sformat.size();
00313 CharType const *format=sformat.c_str();
00314 while(format[pos]!=0) {
00315 if(format[pos] != obrk) {
00316 if(format[pos]==cbrk && format[pos+1]==cbrk) {
00317 out << cbrk;
00318 pos+=2;
00319 }
00320 else {
00321 out<<format[pos];
00322 pos++;
00323 }
00324 continue;
00325 }
00326
00327 if(pos+1 < size && format[pos+1]==obrk) {
00328 out << obrk;
00329 pos+=2;
00330 continue;
00331 }
00332 pos++;
00333
00334 details::format_parser fmt(out,static_cast<void *>(&out),&basic_format::imbue_locale);
00335
00336 format_guard guard(fmt);
00337
00338 while(pos < size) {
00339 std::string key;
00340 std::string svalue;
00341 string_type value;
00342 bool use_svalue = true;
00343 for(;format[pos];pos++) {
00344 char_type c=format[pos];
00345 if(c==comma || c==eq || c==cbrk)
00346 break;
00347 else {
00348 key+=static_cast<char>(c);
00349 }
00350 }
00351
00352 if(format[pos]==eq) {
00353 pos++;
00354 if(format[pos]==quote) {
00355 pos++;
00356 use_svalue = false;
00357 while(format[pos]) {
00358 if(format[pos]==quote) {
00359 if(format[pos+1]==quote) {
00360 value+=quote;
00361 pos+=2;
00362 }
00363 else {
00364 pos++;
00365 break;
00366 }
00367 }
00368 else {
00369 value+=format[pos];
00370 pos++;
00371 }
00372 }
00373 }
00374 else {
00375 char_type c;
00376 while((c=format[pos])!=0 && c!=comma && c!=cbrk) {
00377 svalue+=static_cast<char>(c);
00378 pos++;
00379 }
00380 }
00381 }
00382
00383 if(use_svalue) {
00384 fmt.set_one_flag(key,svalue);
00385 }
00386 else
00387 fmt.set_flag_with_str(key,value);
00388
00389 if(format[pos]==comma) {
00390 pos++;
00391 continue;
00392 }
00393 else if(format[pos]==cbrk) {
00394 unsigned position = fmt.get_position();
00395 out << get(position);
00396 guard.restore();
00397 pos++;
00398 break;
00399 }
00400 else {
00401 guard.restore();
00402 break;
00403 }
00404 }
00405 }
00406 }
00407
00408
00409
00410
00411
00412 basic_format(basic_format const &other);
00413 void operator=(basic_format const &other);
00414
00415 void add(formattible_type const ¶m)
00416 {
00417 if(parameters_count_ >= base_params_)
00418 ext_params_.push_back(param);
00419 else
00420 parameters_[parameters_count_] = param;
00421 parameters_count_++;
00422 }
00423
00424 formattible_type get(unsigned id) const
00425 {
00426 if(id >= parameters_count_)
00427 return formattible_type();
00428 else if(id >= base_params_)
00429 return ext_params_[id - base_params_];
00430 else
00431 return parameters_[id];
00432 }
00433
00434 static void imbue_locale(void *ptr,std::locale const &l)
00435 {
00436 reinterpret_cast<stream_type *>(ptr)->imbue(l);
00437 }
00438
00439
00440
00441 static unsigned const base_params_ = 8;
00442
00443 message_type message_;
00444 string_type format_;
00445 bool translate_;
00446
00447
00448 formattible_type parameters_[base_params_];
00449 unsigned parameters_count_;
00450 std::vector<formattible_type> ext_params_;
00451 };
00452
00458 template<typename CharType>
00459 std::basic_ostream<CharType> &operator<<(std::basic_ostream<CharType> &out,basic_format<CharType> const &fmt)
00460 {
00461 fmt.write(out);
00462 return out;
00463 }
00464
00465
00469 typedef basic_format<char> format;
00470
00474 typedef basic_format<wchar_t> wformat;
00475
00476 #ifdef BOOSTER_HAS_CHAR16_T
00477
00478
00479
00480 typedef basic_format<char16_t> u16format;
00481 #endif
00482
00483 #ifdef BOOSTER_HAS_CHAR32_T
00484
00485
00486
00487 typedef basic_format<char32_t> u32format;
00488 #endif
00489
00493
00494 }
00495 }
00496
00497 #ifdef BOOSTER_MSVC
00498 #pragma warning(pop)
00499 #endif
00500
00501 #endif
00502
00513
00514
00515