CppCMS
booster/locale/format.h
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 &param)
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