format.h
//
// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOSTER_LOCALE_FORMAT_H_INCLUDED
#define BOOSTER_LOCALE_FORMAT_H_INCLUDED
#include <booster/config.h>
#ifdef BOOSTER_MSVC
# pragma warning(push)
# pragma warning(disable : 4275 4251 4231 4660)
#endif
#include <booster/locale/message.h>
#include <booster/locale/formatting.h>
#include <sstream>
namespace booster {
namespace locale {
namespace details {
template<typename CharType>
struct formattible {
typedef std::basic_ostream<CharType> stream_type;
typedef void (*writer_type)(stream_type &output,void const *ptr);
formattible() :
pointer_(0),
writer_(&formattible::void_write)
{
}
formattible(formattible const &other) :
pointer_(other.pointer_),
writer_(other.writer_)
{
}
formattible const &operator=(formattible const &other)
{
if(this != &other) {
pointer_=other.pointer_;
writer_=other.writer_;
}
return *this;
}
template<typename Type>
formattible(Type const &value)
{
pointer_ = static_cast<void const *>(&value);
writer_ = &write<Type>;
}
template<typename Type>
formattible const &operator=(Type const &other)
{
*this = formattible(other);
return *this;
}
friend stream_type &operator<<(stream_type &out,formattible const &fmt)
{
fmt.writer_(out,fmt.pointer_);
return out;
}
private:
static void void_write(stream_type &output,void const * /*ptr*/)
{
CharType empty_string[1]={0};
output<<empty_string;
}
template<typename Type>
static void write(stream_type &output,void const *ptr)
{
output << *static_cast<Type const *>(ptr);
}
void const *pointer_;
writer_type writer_;
}; // formattible
class BOOSTER_API format_parser {
public:
format_parser(std::ios_base &ios,void *,void (*imbuer)(void *,std::locale const &));
~format_parser();
unsigned get_position();
void set_one_flag(std::string const &key,std::string const &value);
template<typename CharType>
void set_flag_with_str(std::string const &key,std::basic_string<CharType> const &value)
{
if(key=="ftime" || key=="strftime") {
as::strftime(ios_);
ios_info::get(ios_).date_time_pattern(value);
}
}
void restore();
private:
void imbue(std::locale const &);
format_parser(format_parser const &);
void operator=(format_parser const &);
std::ios_base &ios_;
struct data;
std::auto_ptr<data> d;
};
}
template<typename CharType>
class basic_format {
public:
typedef CharType char_type;
typedef basic_message<char_type> message_type;
typedef details::formattible<CharType> formattible_type;
typedef std::basic_string<CharType> string_type;
typedef std::basic_ostream<CharType> stream_type;
basic_format(string_type format_string) :
format_(format_string),
translate_(false),
parameters_count_(0)
{
}
basic_format(message_type const &trans) :
message_(trans),
translate_(true),
parameters_count_(0)
{
}
template<typename Formattible>
basic_format &operator % (Formattible const &object)
{
add(formattible_type(object));
return *this;
}
string_type str(std::locale const &loc = std::locale()) const
{
std::basic_ostringstream<CharType> buffer;
buffer.imbue(loc);
write(buffer);
return buffer.str();
}
void write(stream_type &out) const
{
string_type format;
if(translate_)
format = message_.str(out.getloc(),ios_info::get(out).domain_id());
else
format = format_;
format_output(out,format);
}
private:
class format_guard {
public:
format_guard(details::format_parser &fmt) :
fmt_(&fmt),
restored_(false)
{
}
void restore()
{
if(restored_)
return;
fmt_->restore();
restored_ = true;
}
~format_guard()
{
try {
restore();
}
catch(...) {
}
}
private:
details::format_parser *fmt_;
bool restored_;
};
void format_output(stream_type &out,string_type const &sformat) const
{
char_type obrk='{';
char_type cbrk='}';
char_type eq='=';
char_type comma=',';
char_type quote='\'';
size_t pos = 0;
size_t size=sformat.size();
CharType const *format=sformat.c_str();
while(format[pos]!=0) {
if(format[pos] != obrk) {
if(format[pos]==cbrk && format[pos+1]==cbrk) {
out << cbrk;
pos+=2;
}
else {
out<<format[pos];
pos++;
}
continue;
}
if(pos+1 < size && format[pos+1]==obrk) {
out << obrk;
pos+=2;
continue;
}
pos++;
details::format_parser fmt(out,static_cast<void *>(&out),&basic_format::imbue_locale);
format_guard guard(fmt);
while(pos < size) {
std::string key;
std::string svalue;
string_type value;
bool use_svalue = true;
for(;format[pos];pos++) {
char_type c=format[pos];
if(c==comma || c==eq || c==cbrk)
break;
else {
key+=static_cast<char>(c);
}
}
if(format[pos]==eq) {
pos++;
if(format[pos]==quote) {
pos++;
use_svalue = false;
while(format[pos]) {
if(format[pos]==quote) {
if(format[pos+1]==quote) {
value+=quote;
pos+=2;
}
else {
pos++;
break;
}
}
else {
value+=format[pos];
pos++;
}
}
}
else {
char_type c;
while((c=format[pos])!=0 && c!=comma && c!=cbrk) {
svalue+=static_cast<char>(c);
pos++;
}
}
}
if(use_svalue) {
fmt.set_one_flag(key,svalue);
}
else
fmt.set_flag_with_str(key,value);
if(format[pos]==comma) {
pos++;
continue;
}
else if(format[pos]==cbrk) {
unsigned position = fmt.get_position();
out << get(position);
guard.restore();
pos++;
break;
}
else {
guard.restore();
break;
}
}
}
}
//
// Non-copyable
//
basic_format(basic_format const &other);
void operator=(basic_format const &other);
void add(formattible_type const &param)
{
if(parameters_count_ >= base_params_)
ext_params_.push_back(param);
else
parameters_[parameters_count_] = param;
parameters_count_++;
}
formattible_type get(unsigned id) const
{
if(id >= parameters_count_)
return formattible_type();
else if(id >= base_params_)
return ext_params_[id - base_params_];
else
return parameters_[id];
}
static void imbue_locale(void *ptr,std::locale const &l)
{
reinterpret_cast< stream_type *>(ptr)->imbue(l);
}
static unsigned const base_params_ = 8;
message_type message_;
string_type format_;
bool translate_;
formattible_type parameters_[base_params_];
unsigned parameters_count_;
std::vector<formattible_type> ext_params_;
};
template<typename CharType>
std::basic_ostream<CharType> &operator<<(std::basic_ostream<CharType> &out,basic_format<CharType> const &fmt)
{
fmt.write(out);
return out;
}
typedef basic_format<char> format;
typedef basic_format<wchar_t> wformat;
#ifdef BOOSTER_HAS_CHAR16_T
typedef basic_format<char16_t> u16format;
#endif
#ifdef BOOSTER_HAS_CHAR32_T
typedef basic_format<char32_t> u32format;
#endif
}
}
#ifdef BOOSTER_MSVC
#pragma warning(pop)
#endif
#endif
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
booster::locale::basic_format::char_type
CharType char_type
Underlying character type.
Definition: format.h:206
booster::locale::basic_format::string_type
std::basic_string< CharType > string_type
string type for this type of character
Definition: format.h:212
booster::locale::ios_info::domain_id
void domain_id(int)
booster::locale::basic_format::basic_format
basic_format(string_type format_string)
Definition: format.h:219
booster::locale::operator<<
std::basic_ostream< CharType > & operator<<(std::basic_ostream< CharType > &out, date_time const &t)
Definition: date_time.h:874
booster::locale::basic_format::stream_type
std::basic_ostream< CharType > stream_type
output stream type for this type of character
Definition: format.h:213
booster::locale::basic_format::basic_format
basic_format(message_type const &trans)
Definition: format.h:229
booster::locale::ios_info::get
static ios_info & get(std::ios_base &ios)
booster::locale::wformat
basic_format< wchar_t > wformat
Definition: format.h:474
booster::locale::basic_format::str
string_type str(std::locale const &loc=std::locale()) const
Definition: format.h:250
booster::locale::basic_format::operator%
basic_format & operator%(Formattible const &object)
Definition: format.h:241
booster::locale::basic_format::message_type
basic_message< char_type > message_type
Definition: format.h:207
booster::locale::ios_info::date_time_pattern
void date_time_pattern(std::basic_string< CharType > const &str)
Definition: formatting.h:155
booster::locale::format
basic_format< char > format
Definition: format.h:469
booster::locale::basic_message< char_type >
booster::locale::as::strftime
std::ios_base & strftime(std::ios_base &ios)
Definition: formatting.h:347
booster::locale::basic_format
a printf like class that allows type-safe and locale aware message formatting
Definition: format.h:204
booster::locale::basic_message::str
string_type str() const
Definition: message.h:353
booster::locale::basic_format::write
void write(stream_type &out) const
Definition: format.h:261