CppCMS
|
00001 // 00002 // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) 00003 // 00004 // Distributed under the Boost Software License, Version 1.0. (See 00005 // accompanying file LICENSE_1_0.txt or copy at 00006 // http://www.boost.org/LICENSE_1_0.txt) 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 * /*ptr*/) 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 }; // formattible 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 // Non-copyable 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 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 00515