Browse Source

Now external locale library is used

master
Artyom Beilis 14 years ago
parent
commit
9c8df7ba46
39 changed files with 150 additions and 4048 deletions
  1. +16
    -18
      CMakeLists.txt
  2. +0
    -16
      application.cpp
  3. +0
    -5
      application.h
  4. +0
    -4
      base_view.cpp
  5. +4
    -13
      config.js
  6. +20
    -127
      filters.cpp
  7. +9
    -362
      filters.h
  8. +6
    -6
      form.cpp
  9. +1
    -2
      form.h
  10. +23
    -50
      hello_world.cpp
  11. +3
    -4
      http_context.cpp
  12. +3
    -2
      http_context.h
  13. +3
    -4
      http_response.cpp
  14. +0
    -144
      locale_charset.cpp
  15. +0
    -143
      locale_charset.h
  16. +0
    -144
      locale_collate.cpp
  17. +0
    -62
      locale_collate.h
  18. +0
    -221
      locale_convert.cpp
  19. +0
    -89
      locale_convert.h
  20. +0
    -88
      locale_environment.cpp
  21. +0
    -40
      locale_environment.h
  22. +0
    -561
      locale_gettext.cpp
  23. +0
    -57
      locale_gettext.h
  24. +0
    -24
      locale_icu_locale.cpp
  25. +0
    -33
      locale_icu_locale.h
  26. +0
    -43
      locale_info.cpp
  27. +0
    -40
      locale_info.h
  28. +0
    -342
      locale_mo_file.cpp
  29. +0
    -30
      locale_mo_file.h
  30. +0
    -287
      locale_numeric.cpp
  31. +0
    -67
      locale_numeric.h
  32. +0
    -95
      locale_pool.cpp
  33. +0
    -32
      locale_pool.h
  34. +0
    -0
      localization.h
  35. +52
    -9
      service.cpp
  36. +7
    -5
      service.h
  37. +3
    -1
      service_impl.h
  38. +0
    -446
      utf8_iterator.cpp
  39. +0
    -432
      utf8_iterator.h

+ 16
- 18
CMakeLists.txt View File

@@ -28,15 +28,25 @@ endif(NOT ICU_UC OR NOT ICU_DATA OR NOT ICU_I18N)

set(HAVE_ICU 1)

find_library(ICONV_LIB iconv)

check_cxx_source_compiles(
"#include <iconv.h>
int main() { iconv_t v=iconv_open((char *)0,(char *)); "
HAVE_ICONV)
if(NOT HAVE_ICONV)
find_library(ICONV_LIB iconv)
if(NOT ICONV_LIB)
message(FATAL " Can't find iconv")
endif(NOT ICONV_LIB)
endif(NOT HAVE_ICONV)

include_directories(${CMAKE_BINARY_DIR})
include_directories(boost_locale)
include_directories(${Boost_INCLUDE_DIRS})


Check_type_size(wchar_t SIZEOF_WCHAR_T)
check_type_size(wchar_t SIZEOF_WCHAR_T)

check_cxx_source_compiles(
"int main() { volatile long v;__sync_add_and_fetch(&v,1); }"
@@ -113,12 +123,7 @@ set(CPPCMS_SOURCES
url_dispatcher.cpp
http_cookie.cpp
util.cpp
locale_mo_file.cpp
locale_gettext.cpp
locale_environment.cpp
locale_pool.cpp
base64.cpp
locale_info.cpp
base_view.cpp
internal_file_server.cpp
scgi_api.cpp
@@ -128,15 +133,8 @@ set(CPPCMS_SOURCES
aio_timer.cpp
json.cpp
encoding.cpp
locale_charset.cpp
locale_icu_locale.cpp
locale_convert.cpp
locale_numeric.cpp
locale_collate.cpp
icu_util.cpp
form.cpp
filters.cpp
utf8_iterator.cpp)
filters.cpp)


add_definitions(-DDLL_EXPORT)
@@ -160,8 +158,8 @@ if(ICONV_LIB)
endif(ICONV_LIB)

if(WS2_32 AND WSOCK32)
target_link_libraries(cppcms ws2_32)
target_link_libraries(cppcms wsock32)
target_link_libraries(cppcms ${WS2_32})
target_link_libraries(cppcms ${WSOCK32})
endif(WS2_32 AND WSOCK32)

if(LIB_GETHOSTBYNAME)


+ 0
- 16
application.cpp View File

@@ -5,8 +5,6 @@
#include "service.h"
#include "cppcms_error.h"
#include "url_dispatcher.h"
#include "locale_environment.h"
#include "locale_gettext.h"
#include "intrusive_ptr.h"
#include "applications_pool.h"
#include "http_response.h"
@@ -100,20 +98,6 @@ intrusive_ptr<http::context> application::release_context()
}


cppcms::locale::environment &application::locale()
{
return context().locale();
}

char const *application::gt(char const *s)
{
return locale().gt(s);
}

char const *application::ngt(char const *s,char const *p,int n)
{
return locale().ngt(s,p,n);
}
bool application::is_asynchronous()
{
return pool_id() < 0;


+ 0
- 5
application.h View File

@@ -41,11 +41,6 @@ namespace cppcms {
http::request &request();
http::response &response();
url_dispatcher &dispatcher();
locale::environment &locale();

char const *gt(char const *s);
char const *ngt(char const *s,char const *p,int n);


void add(application &app);
void add(application &app,std::string regex,int part);


+ 0
- 4
base_view.cpp View File

@@ -1,9 +1,6 @@
#define CPPCMS_SOURCE
#include "base_view.h"
#include "util.h"
#include "locale_gettext.h"
#include "locale_environment.h"
#include "locale_convert.h"
#include "cppcms_error.h"

#include <vector>
@@ -13,7 +10,6 @@ namespace cppcms {

struct base_view::data {
std::ostream *out;
locale::gettext::tr const *tr;
};

base_view::base_view(std::ostream &out) :


+ 4
- 13
config.js View File

@@ -29,23 +29,14 @@
// "level" : 1,
// "buffer" : 4096
},
"l10n" : {
"defaults" : {
"encoding" : "UTF-8",
"locale" : "en_US",
"std_locale" : [ "ICU" , "C" ]
},
"localization" : {
"encoding" : "UTF-8",
"messages" : {
"paths" : [ "./transtext/locale" ],
"paths" : [ "../transtext/locale" ],
"domains" : [ "app", "test" ],
"default_domain" : ["test"]
},
"locales" : [
"he_IL",
"he_IL@calendar=hebrew",
"en_US",
{ "locale" : "ru_RU" , "std_locale" : "C" }
]
"locales" : [ "en_US", "he_IL", "he_IL@calendar=hebrew" ]
},
"locale" : {
"locales" :


+ 20
- 127
filters.cpp View File

@@ -1,7 +1,6 @@
#define CPPCMS_SOURCE
#include "filters.h"
#include "base64.h"
#include "locale_convert.h"
#include "util.h"
#include <iostream>

@@ -79,7 +78,9 @@ namespace cppcms { namespace filters {
to_upper const &to_upper::operator=(to_upper const &other){ obj_ = other.obj_; return *this; }
void to_upper::operator()(std::ostream &out) const
{
out << std::use_facet<locale::convert>(out.getloc()).to_upper(obj_.get(out));
std::string tmp =obj_.get(out) ;
std::locale loc = out.getloc();
out << ::cppcms::locale::to_upper( tmp,loc);
}

struct to_lower::data {};
@@ -90,7 +91,7 @@ namespace cppcms { namespace filters {
to_lower const &to_lower::operator=(to_lower const &other){ obj_ = other.obj_; return *this; }
void to_lower::operator()(std::ostream &out) const
{
out << std::use_facet<locale::convert>(out.getloc()).to_lower(obj_.get(out));
out << locale::to_lower(obj_.get(out),out.getloc());
}

struct to_title::data {};
@@ -101,7 +102,7 @@ namespace cppcms { namespace filters {
to_title const &to_title::operator=(to_title const &other){ obj_ = other.obj_; return *this; }
void to_title::operator()(std::ostream &out) const
{
out << std::use_facet<locale::convert>(out.getloc()).to_title(obj_.get(out));
out << locale::to_title(obj_.get(out),out.getloc());
}

struct escape::data {};
@@ -156,151 +157,43 @@ namespace cppcms { namespace filters {
os<<buf;
}

struct strftime::data {};
strftime::strftime() {}
strftime::~strftime() {}
strftime::strftime(strftime const &other) : format_(other.format_),t_(other.t_) {}
strftime::strftime(streamable const &obj,std::tm const &t) : format_(obj),t_(&t) {}
strftime const &strftime::operator=(strftime const &other)
{
format_ = other.format_;
t_=other.t_;
return *this;
}
void strftime::operator()(std::ostream &out) const
{
std::string fmt=format_.get(out);
std::use_facet<std::time_put<char> >(out.getloc()).put(out,out,' ',t_,fmt.data(),fmt.data()+fmt.size());
}


void format::init(streamable const &f)
{
format_=f;
size_ = 0;
}
streamable const *format::at(size_t n) const
{
n--;
if(n >= size_ || n < 0)
return 0;

const size_t objects_size = sizeof(objects_) / sizeof(objects_[0]);

if(n < objects_size)
return &objects_[n];
return &vobjects_[n - objects_size];
}
format &format::add(streamable const &obj)
{
if(size_ >= sizeof(objects_) / sizeof(objects_[0]))
vobjects_.push_back(obj);
else
objects_[size_] = obj;
size_ ++;
return *this;
}
void format::write(std::ostream &output) const
{
int pos = 0;
std::string const fmt=format_.get(output);
for(std::string::const_iterator p=fmt.begin(),e=fmt.end();p!=e;) {
char c=*p++;
if(c=='%') {
format_one(output,p,e,pos);
}
else
output.put(c);
}
}

void format::format_one(std::ostream &out,std::string::const_iterator &p,std::string::const_iterator e,int &pos) const
{
if(p==e)
return;
if(*p == '%') {
++p;
out << '%';
return;
}
pos++;
int the_pos = pos;

if('1' <= *p && *p<='9') {
int n=0;
while(p!=e && '0' <= *p && *p<='9') {
n=n*10 + (*p - '0');
++p;
}
if(p==e)
return;
if(*p=='%') {
++p;
the_pos = n;
streamable const *obj=at(the_pos);
if(obj) {
out<<*obj;
}
return;
}
return;
}
}

std::string format::str(std::locale const &loc) const
{
std::ostringstream oss;
oss.imbue(loc);
write(oss);
return oss.str();
}

struct date::data {};
struct time::data {};
struct datetime::data {};

date::date() : t_(0) {}
datetime::datetime() : t_(0){}
time::time() : t_(0) {}
date::date() : time_(0) {}
datetime::datetime() : time_(0){}
time::time() : time_(0) {}
date::~date() {}
datetime::~datetime() {}
time::~time() {}
date::date(date const &other) : t_(other.t_) {}
time::time(time const &other) : t_(other.t_) {}
datetime::datetime(datetime const &other) : t_(other.t_) {}
date::date(date const &other) : time_(other.time_) {}
time::time(time const &other) : time_(other.time_) {}
datetime::datetime(datetime const &other) : time_(other.time_) {}

date const &date::operator=(date const &other) { t_=other.t_; return *this; }
time const &time::operator=(time const &other) { t_=other.t_; return *this; }
datetime const &datetime::operator=(datetime const &other) { t_=other.t_; return *this; }
date const &date::operator=(date const &other) { time_=other.time_; return *this; }
time const &time::operator=(time const &other) { time_=other.time_; return *this; }
datetime const &datetime::operator=(datetime const &other) { time_=other.time_; return *this; }

date::date(std::tm const &t) : t_(&t) {}
time::time(std::tm const &t) : t_(&t) {}
datetime::datetime(std::tm const &t) : t_(&t) {}
date::date(double t) : time_(t) {}
time::time(double t) : time_(t) {}
datetime::datetime(double t) : time_(t) {}

void date::operator()(std::ostream &out) const
{
if(out.getloc().name()=="*")
out<<strftime("%Y-%m-%d",*t_);
else
out<<strftime("%x",*t_);
out << format("{1,date}") % time_;
}
void time::operator()(std::ostream &out) const
{
if(out.getloc().name()=="*")
out<<strftime("%H:%M:%S",*t_);
else
out<<strftime("%X",*t_);
out << format("{1,time}") % time_;
}
void datetime::operator()(std::ostream &out) const
{
if(out.getloc().name()=="*")
out<<strftime("%Y-%m-%d %H:%M:%S",*t_);
else
out<<strftime("%c",*t_);
out << format("{1,datetime}") % time_;
}




+ 9
- 362
filters.h View File

@@ -8,8 +8,8 @@
#include <iostream>
#include "defs.h"
#include "copy_ptr.h"
#include "localization.h"

#include "locale_gettext.h"
namespace cppcms {
namespace filters {

@@ -287,35 +287,7 @@ namespace cppcms {
return out;
}
///
/// \brief Output filter strftime
///
/// Format time according to locale using time_put<char> facet. (has similar
/// parameters to C strftime
///
class CPPCMS_API strftime {
public:
strftime();
~strftime();
strftime(strftime const &);
strftime const &operator=(strftime const &other);
void operator()(std::ostream &out) const;
strftime(streamable const &obj,std::tm const &t);

private:
streamable format_;
std::tm const *t_;
struct data;
util::copy_ptr<data> d;
};

inline std::ostream &operator<<(std::ostream &out,strftime const &obj)
{
obj(out);
return out;
}

class CPPCMS_API date {
public:
@@ -324,11 +296,11 @@ namespace cppcms {
date const &operator=(date const &other);
~date();

date(std::tm const &t);
date(double time);
void operator()(std::ostream &out) const;
private:
struct data;
std::tm const *t_;
double time_;
util::copy_ptr<data> d;
};
@@ -345,11 +317,11 @@ namespace cppcms {
time const &operator=(time const &other);
~time();

time(std::tm const &t);
time(double time);
void operator()(std::ostream &out) const;
private:
struct data;
std::tm const *t_;
double time_;
util::copy_ptr<data> d;
};
@@ -365,11 +337,11 @@ namespace cppcms {
datetime const &operator=(datetime const &other);
~datetime();

datetime(std::tm const &t);
datetime(double t);
void operator()(std::ostream &out) const;
private:
struct data;
std::tm const *t_;
double time_;
util::copy_ptr<data> d;
};
@@ -378,339 +350,14 @@ namespace cppcms {
obj(out);
return out;
}
class gt {
public:
gt(char const *msg) :
domain_(0),
msg_(msg)
{
}
gt(char const *domain,char const *msg) :
domain_(domain),
msg_(msg)
{
}
void operator()(std::ostream &out) const
{
locale::gettext const &trans = std::use_facet<locale::gettext>(out.getloc());
if(domain_)
out << trans.dictionary(domain_).gettext(msg_);
else
out << trans.dictionary().gettext(msg_);
}
private:
char const *domain_;
char const *msg_;
};
CPPCMS_STREAMED(gt)
class ngt {
public:
ngt(char const *s,char const *p,int n) :
domain_(0),
s_(s),
p_(p),
n_(n)
{
}
ngt(char const *domain,char const *s,char const *p,int n) :
domain_(domain),
s_(s),
p_(p),
n_(n)
{
}
void operator()(std::ostream &out) const
{
locale::gettext const &trans = std::use_facet<locale::gettext>(out.getloc());
if(domain_)
out << trans.dictionary(domain_).ngettext(s_,p_,n_);
else
out << trans.dictionary().ngettext(s_,p_,n_);
}
private:
char const *domain_;
char const *s_,*p_;
int n_;
};
CPPCMS_STREAMED(ngt)

class CPPCMS_API format {
public:
format(streamable const &f)
{
init(f);
}
#ifdef CPPCMS_HAVE_VARIADIC_TEMPLATES
template<typename... Args>
format(streamable const &f,Args... args)
{
init(f);
add_args(args...);
}
private:
void add_args()
{
}
template<typename T,typename... Args>
void add_args(T const &v,Args... args)
{
add(v);
add_args(args...);
}
public:
#else
template<typename T1>
format( streamable const &f,
T1 const &v1)
{
init(f);
add(v1);
}
template< typename T1,
typename T2>
format( streamable const &f,
T1 const &v1,
T2 const &v2)
{
init(f);
add(v1);
add(v2);
}
template< typename T1,
typename T2,
typename T3>
format( streamable const &f,
T1 const &v1,
T2 const &v2,
T3 const &v3)
{
init(f);
add(v1);
add(v2);
add(v3);
}
template< typename T1,
typename T2,
typename T3,
typename T4>
format( streamable const &f,
T1 const &v1,
T2 const &v2,
T3 const &v3,
T4 const &v4)
{
init(f);
add(v1);
add(v2);
add(v3);
add(v4);
}
template< typename T1,
typename T2,
typename T3,
typename T4,
typename T5>
format( streamable const &f,
T1 const &v1,
T2 const &v2,
T3 const &v3,
T4 const &v4,
T5 const &v5)
{
init(f);
add(v1);
add(v2);
add(v3);
add(v4);
add(v5);
}
template< typename T1,
typename T2,
typename T3,
typename T4,
typename T5,
typename T6>
format( streamable const &f,
T1 const &v1,
T2 const &v2,
T3 const &v3,
T4 const &v4,
T5 const &v5,
T6 const &v6)
{
init(f);
add(v1);
add(v2);
add(v4);
add(v5);
add(v6);
}
template< typename T1,
typename T2,
typename T3,
typename T4,
typename T5,
typename T6,
typename T7>
format( streamable const &f,
T1 const &v1,
T2 const &v2,
T3 const &v3,
T4 const &v4,
T5 const &v5,
T6 const &v6,
T7 const &v7)
{
init(f);
add(v1);
add(v2);
add(v3);
add(v4);
add(v5);
add(v6);
add(v7);
}
template< typename T1,
typename T2,
typename T3,
typename T4,
typename T5,
typename T6,
typename T7,
typename T8>
format( streamable const &f,
T1 const &v1,
T2 const &v2,
T3 const &v3,
T4 const &v4,
T5 const &v5,
T6 const &v6,
T7 const &v7,
T8 const &v8)
{
init(f);
add(v1);
add(v2);
add(v3);
add(v4);
add(v5);
add(v6);
add(v7);
add(v8);
}
template< typename T1,
typename T2,
typename T3,
typename T4,
typename T5,
typename T6,
typename T7,
typename T8,
typename T9>
format( streamable const &f,
T1 const &v1,
T2 const &v2,
T3 const &v3,
T4 const &v4,
T5 const &v5,
T6 const &v6,
T7 const &v7,
T8 const &v8,
T9 const &v9)
{
init(f);
add(v1);
add(v2);
add(v3);
add(v4);
add(v5);
add(v6);
add(v7);
add(v8);
add(v9);
}
template< typename T1,
typename T2,
typename T3,
typename T4,
typename T5,
typename T6,
typename T7,
typename T8,
typename T9,
typename T10>
format( streamable const &f,
T1 const &v1,
T2 const &v2,
T3 const &v3,
T4 const &v4,
T5 const &v5,
T6 const &v6,
T7 const &v7,
T8 const &v8,
T9 const &v9,
T10 const &v10)
{
init(f);
add(v1);
add(v2);
add(v3);
add(v4);
add(v5);
add(v6);
add(v7);
add(v8);
add(v9);
add(v10);
}
#endif

template<typename Streamable>
format &operator % (Streamable const &object)
{
return add(streamable(object));
}

void operator()(std::ostream &output) const
{
write(output);
}
std::string str(std::locale const &locale) const;

std::string str() const
{
return str(std::locale::classic());
}

format &add(streamable const &obj);
private:
void write(std::ostream &output) const;
void format_one(std::ostream &out,std::string::const_iterator &p,std::string::const_iterator e,int &pos) const;

void init(streamable const &f);

streamable const *at(size_t n) const;

streamable format_;
std::vector<streamable> vobjects_;
streamable objects_[10];
size_t size_;
};

CPPCMS_STREAMED(format)
using locale::translate;
using locale::format;
}

///////////////////////////////

using filters::format;
using filters::ngt;
using filters::gt;
}

#undef CPPCMS_STREAMED


+ 6
- 6
form.cpp View File

@@ -3,8 +3,6 @@
#include <iostream>
#include <stack>
#include <boost/format.hpp>
#include "locale_charset.h"
#include "locale_environment.h"

namespace cppcms {

@@ -380,12 +378,14 @@ void base_text::value(std::string v)

std::string base_text::value(std::locale const &v)
{
return std::use_facet<locale::charset>(v).to_utf8(value_);
//return std::use_facet<locale::charset>(v).to_utf8(value_);
return value_;
}

void base_text::value(std::string v,std::locale const &l)
{
value(std::use_facet<locale::charset>(l).from_utf8(v));
//value(std::use_facet<locale::charset>(l).from_utf8(v));
value(v);
}

void base_text::non_empty()
@@ -432,9 +432,9 @@ void base_text::load(http::context &context)
set(true);
if(validate_charset_) {
code_points_ = 0;
locale::charset const &charset=std::use_facet<locale::charset>(context.locale().get());
/* locale::charset const &charset=std::use_facet<locale::charset>(context.locale().get());
if(!charset.validate(value_,code_points_))
valid(false);
valid(false);*/
}
else {
code_points_=value_.size();


+ 1
- 2
form.h View File

@@ -14,7 +14,6 @@
#include "http_context.h"
#include "http_request.h"
#include "http_response.h"
#include "locale_environment.h"
#include "copy_ptr.h"
#include "cppcms_error.h"
#include "util.h"
@@ -897,7 +896,7 @@ namespace cppcms {
return;

std::istringstream ss(loaded_string_);
ss.imbue(context.locale().get());
ss.imbue(context.locale());
ss>>value_;
if(ss.fail() || !ss.eof())
valid(false);


+ 23
- 50
hello_world.cpp View File

@@ -5,15 +5,12 @@
#include "http_response.h"
#include "http_request.h"
#include "http_cookie.h"
#include "locale_environment.h"
#include "locale_charset.h"
#include "localization.h"
#include "http_context.h"
#include "filters.h"
#include "aio_timer.h"
#include "intrusive_ptr.h"
#include "form.h"
#include "locale_convert.h"
#include "utf8_iterator.h"
#include <sstream>
#include <stdexcept>
#include <stdlib.h>
@@ -203,35 +200,16 @@ public:
{
}

template<typename iterator>
void devide(std::string const &str,char const *name)
void devide(cppcms::locale::boundary::boundary_type type,std::string const &str,char const *name)
{
response().out()<<name<<":";
iterator it(str,locale().get());
iterator prev = it;
++it;
response().out()<<std::string(*prev,*it);
while(*it!=str.end()) {
prev=it;
++it;
response().out()<<" | "<<std::string(*prev,*it);
}
response().out()<<"<br>\n"<<name<<" reversed:";
it=str.end();
std::string::const_iterator p=*it;
--it;
response().out()<<std::string(*it,p);
while(*it!=str.begin()) {
p=*it;
--it;
response().out()<<" | "<<std::string(*it,p);
using namespace cppcms::locale;
boundary::index_type indx = boundary::map(type,str,context().locale());

for(unsigned i=0;i<indx.size()-1;i++) {
response().out()<<"|"<<str.substr(indx[i].offset,indx[i+1].offset-indx[i].offset);
}
response().out()<<"<br>\nRandom "<<name<<":";
it = str.begin() + rand() % str.size();
prev=it;
it+=5;
prev-=5;
response().out()<<std::string(*prev,*it)<<"<br>\n";
response().out()<<"|<br>\n";
}

void form()
@@ -247,14 +225,15 @@ public:
response().out()<<
"<html><body>\n";
cppcms::locale::convert const &cv=std::use_facet<cppcms::locale::convert>(locale().get());
std::locale loc = context().locale();

if(f.name.set()) {
using namespace cppcms::locale;
std::string name = f.name.value();
response().out() <<"Upper: "<<cv.to_upper(name)<<"<br>"<<std::endl;
response().out() <<"Lower: "<<cv.to_lower(name)<<"<br>"<<std::endl;
response().out() <<"Title: "<<cv.to_title(name)<<"<br>"<<std::endl;
response().out() <<"Normal: "<<cv.to_normal(name)<<"<br>"<<std::endl;
response().out() <<"Upper: "<<to_upper(name,loc)<<"<br>"<<std::endl;
response().out() <<"Lower: "<<to_lower(name,loc)<<"<br>"<<std::endl;
response().out() <<"Title: "<<to_title(name,loc)<<"<br>"<<std::endl;
response().out() <<"Fold Case: "<<fold_case(name,loc)<<"<br>"<<std::endl;

}
if(f.description.set()) {
@@ -263,12 +242,11 @@ public:
std::ofstream tmp("test.txt");
tmp<<descr;
}
devide<cppcms::utf8::const_code_point_iterator>(descr,"code");
devide<cppcms::utf8::const_character_iterator>(descr,"char");
devide<cppcms::utf8::const_word_iterator>(descr,"word");
devide<cppcms::utf8::const_sentence_iterator>(descr,"sentence");
devide<cppcms::utf8::const_line_iterator>(descr,"line");
using namespace cppcms::locale;
devide(boundary::character,descr,"code");
devide(boundary::word,descr,"word");
devide(boundary::sentence,descr,"sentence");
devide(boundary::line,descr,"line");
}

if(ok) {
@@ -315,19 +293,14 @@ public:
response().out()<<p->second<<"<br/>\n";
}

time_t t=::time(NULL);
std::tm tt;
localtime_r(&t,&tt);

response().out() << filters::date(tt) <<std::endl;
response().out() << filters::date(time(0)) <<std::endl;

response().out() << filters::escape(gt("hello\n")) << "<br>";
response().out() << filters::escape(locale::translate("hello\n")) << "<br>";
for(int i=0;i<30;i++) {
response().out() << format("To be or not to be %1%\n<br>",10);
response().out() << locale::format("To be or not to be {1}\n<br>") % 10;

response().out() << format(ngt("passed one day","passed %1% days",i),i) << "<br>\n";
//cppcms::util::format(response().out(),ngt("passed one day","passed %1% days",i),i) << "<br>";
response().out() << locale::format(locale::translate("passed one day","passed {1} days",i)) % i << "<br>\n";
}
response().out()
<<"<body></html>\n";


+ 3
- 4
http_context.cpp View File

@@ -5,7 +5,6 @@
#include "http_context.h"
#include "http_request.h"
#include "http_response.h"
#include "locale_environment.h"
#include "application.h"
#include "applications_pool.h"
#include "thread_pool.h"
@@ -19,11 +18,11 @@ namespace cppcms {
namespace http {

struct context::data {
cppcms::locale::environment locale;
std::locale locale;
http::request request;
std::auto_ptr<http::response> response;
data(context &cntx) :
locale(cntx.connection().service()),
locale(cntx.connection().service().locale()),
request(cntx.connection())
{
}
@@ -173,7 +172,7 @@ json::value const &context::settings()
return conn_->service().settings();
}

cppcms::locale::environment &context::locale()
std::locale context::locale()
{
return d->locale;
}


+ 3
- 2
http_context.h View File

@@ -8,12 +8,13 @@
#include "callback0.h"
#include "callback1.h"

#include <locale>

namespace cppcms {

class service;
class application;
namespace json { class value; }
namespace locale { class environment; }
namespace impl { namespace cgi { class connection; } }

namespace http {
@@ -30,7 +31,7 @@ namespace cppcms {
http::request &request();
http::response &response();
json::value const &settings();
cppcms::locale::environment &locale();
std::locale locale();
cppcms::service &service();

void run();


+ 3
- 4
http_response.cpp View File

@@ -9,8 +9,7 @@
#include "cppcms_error.h"
#include "service.h"
#include "config.h"
#include "locale_environment.h"
#include "locale_info.h"
#include "localization.h"
#include "util.h"

#include <iostream>
@@ -94,7 +93,7 @@ void response::set_content_header(std::string const &content_type)
set_header("Content-Type",content_type);
}
else {
std::string charset=std::use_facet<locale::info>(context_.locale().get()).encoding();
std::string charset=std::use_facet<locale::info>(context_.locale()).encoding();
set_header("Content-Type",content_type+"; charset="+charset);
}
}
@@ -249,7 +248,7 @@ std::ostream &response::out()
else
stream_=real_sink;

stream_->imbue(context_.locale().get());
stream_->imbue(context_.locale());
return *stream_;
}



+ 0
- 144
locale_charset.cpp View File

@@ -1,144 +0,0 @@
#define CPPCMS_SOURCE
#include "locale_charset.h"
#include "encoding.h"
#include "utf_iterator.h"
#include "cppcms_error.h"
#include <iostream>

namespace cppcms {
namespace locale {

struct charset::data {};

std::locale::id charset::id;

charset::charset(std::size_t refs) :
std::locale::facet(refs),
is_utf8_(true),
validators_(0)
{
}


charset::charset(std::string charset,std::size_t refs) :
std::locale::facet(refs),
name_(charset),
validators_(0)
{
is_utf8_ = charset=="utf8" || charset=="UTF8" || charset=="utf-8" || charset=="UTF-8";
}


charset::charset(std::string charset,intrusive_ptr<encoding::validators_set> p,std::size_t refs) :
std::locale::facet(refs),
name_(charset),
validators_(p)
{
is_utf8_ = charset=="utf8" || charset=="UTF8" || charset=="utf-8" || charset=="UTF-8";
}

charset::~charset()
{
}


bool charset::do_validate(char const *begin,char const *end,size_t &count) const
{
if(!validators_)
return true;
encoding::validator v=(*validators_)[name_];
return v.valid(begin,end,count);
}
std::string charset::do_to_utf8(std::string const &v) const
{
if(is_utf8_)
return v;
encoding::converter conv(name_);
return conv.to_utf8(v.data(),v.data()+v.size());
}
std::string charset::do_from_utf8(std::string const &v) const
{
if(is_utf8_)
return v;
encoding::converter conv(name_);
return conv.from_utf8(v.data(),v.data()+v.size());
}


std::basic_string<uint16_t> charset::do_to_utf16(char const *begin,char const *end) const
{
if(is_utf8_) {
std::basic_string<uint16_t> result;
result.reserve(end-begin);
while(begin < end) {
uint32_t code_point=utf8::next(begin,end,false,true);
if(code_point==utf::illegal)
throw cppcms_error("Invalid utf8");
utf16::seq s=utf16::encode(code_point);
result.append(s.c,s.len);
}
return result;
}
encoding::converter conv(name_);
return conv.to_utf16(begin,end);
}

std::basic_string<uint32_t> charset::do_to_utf32(char const *begin,char const *end) const
{
if(is_utf8_) {
std::basic_string<uint32_t> result;
result.reserve(end-begin);
while(begin < end) {
uint32_t code_point=utf8::next(begin,end,false,true);
if(code_point==utf::illegal)
throw cppcms_error("Invalid utf8");
result+=code_point;
}
return result;
}

encoding::converter conv(name_);
return conv.to_utf32(begin,end);
}


std::string charset::do_from_utf16(uint16_t const *begin,uint16_t const *end) const
{
if(is_utf8_) {
std::string result;
result.reserve(end-begin);
while(begin < end) {
uint32_t code_point=utf16::next(begin,end);
if(code_point==utf::illegal)
throw cppcms_error("Invalid utf16");
utf8::seq s=utf8::encode(code_point);
result.append(s.c,s.len);
}
return result;
}
encoding::converter conv(name_);
return conv.from_utf16(begin,end);
}


std::string charset::do_from_utf32(uint32_t const *begin,uint32_t const *end) const
{
if(is_utf8_) {
std::string result;
result.reserve(end-begin);
while(begin < end) {
uint32_t code_point=*begin++;
if(!utf::valid(code_point))
throw cppcms_error("Invalid utf32");
utf8::seq s=utf8::encode(code_point);
result.append(s.c,s.len);
}
return result;
}
encoding::converter conv(name_);
return conv.from_utf32(begin,end);
}

} // locale
} // cppcms

+ 0
- 143
locale_charset.h View File

@@ -1,143 +0,0 @@
#ifndef CPPCMS_LOCALE_CHARSET_H
#define CPPCMS_LOCALE_CHARSET_H

#include "defs.h"
#include "hold_ptr.h"
#include "intrusive_ptr.h"
#include "config.h"

#include <locale>
#include <string>

#ifndef HAVE_STD_WSTRING
namespace std {
typedef basic_string<wchar_t> wstring;
}
#endif


namespace cppcms {
namespace encoding {
class validators_set;
}
namespace locale {

class CPPCMS_API charset : public std::locale::facet {
public:
static std::locale::id id;
charset(std::size_t refs=0);
charset(std::string charset,std::size_t refs=0);
charset(std::string charset,intrusive_ptr<encoding::validators_set> p,std::size_t refs=0);
~charset();
bool validate(char const *begin,char const *end,size_t &count) const
{
return do_validate(begin,end,count);
}
bool validate(std::string const &s,size_t &count) const
{
return do_validate(s.data(),s.data()+s.size(),count);
}

std::string to_utf8(std::string const &v) const
{
return do_to_utf8(v);
}

std::string from_utf8(std::string const &v) const
{
return do_from_utf8(v);
}

std::basic_string<uint16_t> to_utf16(char const *begin,char const *end) const
{
return do_to_utf16(begin,end);
}

std::string from_utf16(uint16_t const *begin,uint16_t const *end) const
{
return do_from_utf16(begin,end);
}

std::basic_string<uint32_t> to_utf32(char const *begin,char const *end) const
{
return do_to_utf32(begin,end);
}

std::string from_utf32(uint32_t const *begin,uint32_t const *end) const
{
return do_from_utf32(begin,end);
}

std::wstring to_wstring(std::string const &v) const
{
#if SIZEOF_WCHAR_T==2
std::basic_string<uint16_t> tmp=do_to_utf16(v.data(),v.data()+v.size());
#else
std::basic_string<uint32_t> tmp=do_to_utf32(v.data(),v.data()+v.size());
#endif
return std::wstring(tmp.begin(),tmp.end());
}
std::string from_wstring(std::wstring const &v) const
{
#if SIZEOF_WCHAR_T==2
uint16_t const *begin=reinterpret_cast<uint16_t const *>(v.data());
uint16_t const *end=begin+v.size();
return do_from_utf16(begin,end);
#else
uint32_t const *begin=reinterpret_cast<uint32_t const *>(v.data());
uint32_t const *end=begin+v.size();
return do_from_utf32(begin,end);
#endif
}

#ifdef HAVE_CPP0X_UXSTRING
std::u16string to_u16string(std::string const &v) const
{
std::basic_string<uint16_t> tmp=do_to_utf16(v.data(),v.data()+v.size());
return std::u16string(tmp.begin(),tmp.end());
}
std::string from_u16string(std::u16string const &v) const
{
uint16_t const *begin=reinterpret_cast<uint16_t const *>(v.data());
uint16_t const *end=begin+v.size();
return do_from_utf16(begin,end);
}
std::u32string to_u32string(std::string const &v) const
{
std::basic_string<uint32_t> tmp=do_to_utf32(v.data(),v.data()+v.size());
return std::u32string(tmp.begin(),tmp.end());
}
std::string from_u32string(std::u32string const &v) const
{
uint32_t const *begin=reinterpret_cast<uint32_t const *>(v.data());
uint32_t const *end=begin+v.size();
return do_from_utf32(begin,end);
}
#endif

private:
virtual bool do_validate(char const *begin,char const *end,size_t &count) const;

virtual std::string do_to_utf8(std::string const &v) const;
virtual std::string do_from_utf8(std::string const &v) const;

virtual std::basic_string<uint16_t> do_to_utf16(char const *begin,char const *end) const;
virtual std::string do_from_utf16(uint16_t const *begin,uint16_t const *end) const;

virtual std::basic_string<uint32_t> do_to_utf32(char const *begin,char const *end) const;
virtual std::string do_from_utf32(uint32_t const *begin,uint32_t const *end) const;
struct data;
util::hold_ptr<data> d;
std::string name_;
bool is_utf8_;
intrusive_ptr<encoding::validators_set> validators_;

};


} } // cppcms::locale

#endif

+ 0
- 144
locale_collate.cpp View File

@@ -1,144 +0,0 @@
#define CPPCMS_SOURCE
#include "locale_collate.h"
#include "locale_icu_locale.h"
#include "noncopyable.h"
#include "icu_util.h"

#include <stdexcept>

#include <boost/functional/hash.hpp>
#include <boost/shared_ptr.hpp>
#include <unicode/coll.h>


namespace cppcms {
namespace locale {

class collate_impl : public util::noncopyable {
public:
typedef collate::level_type level_type;

int compare(level_type level,std::string const &l,std::string const &r) const
{

UErrorCode status=U_ZERO_ERROR;
icu::UnicodeString left(impl::std_to_icu(l,locale_));
icu::UnicodeString right(impl::std_to_icu(r,locale_));

int res = get(level)->compare(left,right,status);
if(U_FAILURE(status))
throw std::runtime_error(std::string("collation failed:") + u_errorName(status));
if(res<0)
return -1;
else if(res > 0)
return 1;
return 0;
}

std::string transform(level_type level,std::string const &s) const
{
icu::UnicodeString us(impl::std_to_icu(s,locale_));
std::string tmp;
tmp.resize(s.size());
boost::shared_ptr<icu::Collator> collator=get(level);
int len = collator->getSortKey(us,reinterpret_cast<uint8_t *>(&tmp[0]),tmp.size());
if(len > int(tmp.size())) {
tmp.resize(len);
collator->getSortKey(us,reinterpret_cast<uint8_t *>(&tmp[0]),tmp.size());
}
else
tmp.resize(len);
return tmp;
}

collate_impl(std::locale const &l) : locale_(l)
{
icu_locale const &iculoc=std::use_facet<icu_locale>(locale_);
static const icu::Collator::ECollationStrength levels[collators_size] =
{
icu::Collator::PRIMARY,
icu::Collator::SECONDARY,
icu::Collator::TERTIARY,
icu::Collator::QUATERNARY
};
for(int i=0;i<collators_size;i++) {

UErrorCode status=U_ZERO_ERROR;

collators_[i].reset(icu::Collator::createInstance(iculoc.get(),status));

if(U_FAILURE(status))
throw std::runtime_error(std::string("collation failed:") + u_errorName(status));

collators_[i]->setStrength(levels[i]);
}

}

private:
static const int collators_size = 4;

boost::shared_ptr<icu::Collator> get(level_type level) const
{
int l=int(level);
if(l < 0)
l=0;
else if(l >= collators_size)
l = collators_size-1;
return collators_[l];
}


boost::shared_ptr<icu::Collator> collators_[collators_size];
std::locale locale_;
};

/////////

collate::collate(collate_impl *impl,size_t refs) : std::collate<char>(refs),impl_(impl)
{
}
collate::~collate()
{
}
int collate::compare(level_type level,std::string const &l,std::string const &r) const
{
return impl_->compare(level,l,r);
}
int collate::compare( level_type level,
char const *p1_start,char const *p1_end,
char const *p2_start,char const *p2_end) const
{
return impl_->compare(level,std::string(p1_start,p1_end),std::string(p2_start,p2_end));
}
std::string collate::transform(level_type level,std::string const &s) const
{
return impl_->transform(level,s);
}
std::string collate::transform(level_type level,char const *b,char const *e) const
{
return impl_->transform(level,std::string(b,e));
}

long collate::hash(level_type level,std::string const &s) const
{
boost::hash<std::string> hasher;
return hasher(transform(level,s));
}
long collate::hash(level_type level,char const *b,char const *e) const
{
boost::hash<std::string> hasher;
return hasher(transform(level,b,e));
}

collate *collate::create(std::locale const &l)
{
return new collate(new collate_impl(l));
}


} } // cppcms::locale

+ 0
- 62
locale_collate.h View File

@@ -1,62 +0,0 @@
#include <locale>
#include <string>

#include "defs.h"
#include "hold_ptr.h"

namespace cppcms { namespace locale {

class collate_impl;

class CPPCMS_API collate : public std::collate<char> {
public:
typedef enum {
primary = 0,
alphabetic_sensitive = primary,
secondary = 1,
diacritic_sensitive = secondary,
tertiary = 2,
case_sensitive = tertiary,
quaternary = 3
} level_type;

int compare( level_type level,
char const *p1_start,char const *p1_end,
char const *p2_start,char const *p2_end) const;

int compare(level_type level,std::string const &l,std::string const &r) const;
long hash(level_type level,std::string const &s) const;
long hash(level_type level,char const *b,char const *e) const;
std::string transform(level_type level,std::string const &s) const;
std::string transform(level_type level,char const *b,char const *e) const;
static collate *create(std::locale const &l);

private:

collate(collate_impl *impl,size_t refs = 0);
virtual ~collate();
/// Standard functions... override
virtual int do_compare( char const *p1_start,char const *p1_end,
char const *p2_start,char const *p2_end) const
{
return compare(primary,p1_start,p1_end,p2_start,p2_end);
}
virtual std::string do_transform(char const *b,char const *e) const
{
return transform(primary,b,e);
}

virtual long do_hash(char const *b,char const *e) const
{
return hash(primary,b,e);
}

util::hold_ptr<collate_impl> impl_;

};

} } // cppcms::locale

+ 0
- 221
locale_convert.cpp View File

@@ -1,221 +0,0 @@
#define CPPCMS_SOURCE
#include "locale_convert.h"
#include "locale_icu_locale.h"
#include "locale_charset.h"
#include "noncopyable.h"
#include "utf_iterator.h"

#ifdef HAVE_ICU
#include <unicode/unistr.h>
#include <unicode/normlzr.h>
#include "icu_util.h"
#endif

#include <stdexcept>
#include <typeinfo>

namespace cppcms {
namespace locale {
class convert_impl : public util::noncopyable {
public:
virtual std::string to_upper(std::string const &str) const = 0;
virtual std::string to_lower(std::string const &str) const = 0;
virtual std::string to_title(std::string const &str) const = 0;
virtual std::string to_normal(std::string const &str,convert::norm_type how) const = 0;
virtual ~convert_impl() {};
};



#ifdef HAVE_ICU

class icu_convert_impl : public convert_impl {
public:
icu_convert_impl(std::locale const &loc) :
std_locale_(loc),
icu_locale_(std::use_facet<icu_locale>(loc).get())
{
}

static icu::UnicodeString normalize(icu::UnicodeString const &str,convert::norm_type how)
{
UNormalizationMode mode;
switch(how) {
case convert::norm_nfc: mode = UNORM_NFC; break;
case convert::norm_nfd: mode = UNORM_NFD; break;
case convert::norm_nfkc: mode = UNORM_NFKC; break;
case convert::norm_nfkd: mode = UNORM_NFKD; break;
default: mode=UNORM_DEFAULT;
}

icu::UnicodeString res;
UErrorCode status = U_ZERO_ERROR;

icu::Normalizer::normalize(str,mode,0,res,status);
if(U_FAILURE(status))
throw std::runtime_error(std::string("normalization failed:") + u_errorName(status));
return res;
}

std::string to_upper(std::string const &str) const
{
return impl::icu_to_std((impl::std_to_icu(str,std_locale_).toUpper(icu_locale_)),std_locale_);
}
std::string to_lower(std::string const &str) const
{
return impl::icu_to_std((impl::std_to_icu(str,std_locale_).toLower(icu_locale_)),std_locale_);
}
std::string to_title(std::string const &str) const
{
return impl::icu_to_std((impl::std_to_icu(str,std_locale_).toTitle(0,icu_locale_)),std_locale_);
}
std::string to_normal(std::string const &str,convert::norm_type how) const
{
return impl::icu_to_std(normalize(impl::std_to_icu(str,std_locale_),how),std_locale_);
}
private:
friend class convert;
std::locale std_locale_;
icu::Locale icu_locale_;
};



#endif

class std_convert_impl : public convert_impl {
public:
std_convert_impl(std::locale const &l) :
locale_(l),
cfacet_(0),
wfacet_(0),
charset_(0)
{
if(std::has_facet<std::ctype<wchar_t> >(locale_)) {
wfacet_ = & std::use_facet<std::ctype<wchar_t> >(locale_);
charset_ = & std::use_facet<charset>(locale_);
}
else {
cfacet_ = & std::use_facet<std::ctype<char> >(locale_);
}
}

template<typename Char>
void titelize(std::basic_string<Char> &str,std::ctype<Char> const *conv) const
{
bool prev_is_not_alpha = true;
for(unsigned i=0;i<str.size();i++) {
Char c=str[i];
if(prev_is_not_alpha)
str[i]=conv->toupper(c);
else
str[i]=conv->tolower(c);
prev_is_not_alpha=!conv->is(std::ctype_base::alpha,c);
}
}
std::string to_upper(std::string const &str) const
{
if(wfacet_) {
std::wstring tmp=charset_->to_wstring(str);
wfacet_->toupper(&tmp[0],&tmp[0]+tmp.size());
return charset_->from_wstring(tmp);
}
else {
std::string tmp=str;
cfacet_->toupper(&tmp[0],&tmp[0]+tmp.size());
return tmp;
}
}

std::string to_lower(std::string const &str) const
{
if(wfacet_) {
std::wstring tmp=charset_->to_wstring(str);
wfacet_->tolower(&tmp[0],&tmp[0]+tmp.size());
return charset_->from_wstring(tmp);
}
else {
std::string tmp=str;
cfacet_->tolower(&tmp[0],&tmp[0]+tmp.size());
return tmp;
}
}
std::string to_title(std::string const &str) const
{
if(wfacet_) {
std::wstring tmp=charset_->to_wstring(str);
titelize(tmp,wfacet_);
return charset_->from_wstring(tmp);
}
else {
std::string tmp=str;
titelize(tmp,cfacet_);
return tmp;
}
}

std::string to_normal(std::string const &str,convert::norm_type how) const
{
#ifdef HAVE_ICU
return impl::icu_to_std(icu_convert_impl::normalize(impl::std_to_icu(str,locale_),how),locale_);
#else
return str;
#endif
}
private:
std::locale locale_;
std::ctype<char> const *cfacet_;
std::ctype<wchar_t> const *wfacet_;
charset const *charset_;
}; // std_convert
std::locale::id convert::id;

convert *convert::create(std::locale const &l,std::string provider)
{
#ifdef HAVE_ICU
char const *default_provider="icu";
#else
char const *default_provider="std";
#endif

if(provider=="default")
provider=default_provider;

#ifdef HAVE_ICU
if(provider=="icu") {
return new convert(new icu_convert_impl(l));
}
#endif

if(provider=="std") {
return new convert(new std_convert_impl(l));
}
throw std::runtime_error("Unknown locale provider:"+provider);
}
convert::convert(convert_impl *impl,size_t refs) : std::locale::facet(refs), impl_(impl)
{
}
convert::~convert()
{
}

std::string convert::to_upper(std::string const &str) const { return impl_->to_upper(str); }
std::string convert::to_lower(std::string const &str) const { return impl_->to_lower(str); }
std::string convert::to_title(std::string const &str) const { return impl_->to_title(str); }
std::string convert::to_normal(std::string const &str,norm_type how) const { return impl_->to_normal(str,how); }


} /// locale
} /// convert


+ 0
- 89
locale_convert.h View File

@@ -1,89 +0,0 @@
#ifndef CPPCMS_LOCALE_ICU_H
#define CPPCMS_LOCALE_ICU_H

#include "defs.h"
#include "config.h"
#include "hold_ptr.h"
#include <locale>


namespace cppcms {
namespace locale {

class convert_impl;

///
/// \brief This class provides basic unicode aware string manipulation utilities
///
/// If CppCMS is compiled with ICU support it performs these operations using ICU
/// library, otherwise it uses std::locale facets for these operations, so some
/// functionality may have lower quality or not supported at all
///

class CPPCMS_API convert : public std::locale::facet {
public:
static std::locale::id id;

typedef enum { norm_default, /// < Default Unicode normalization as provided by ICU
norm_nfc, /// < NFC Unicode normalization
norm_nfd, /// < NFD Unicode normalization
norm_nfkc, /// < NFKC Unicode normalization
norm_nfkd /// < NFKD Unicode normalization
} norm_type;

///
/// Create convert facet.
///
/// \a charset, \a icu_locale and \a info facets should be assigned to \a source
///

convert(convert_impl *impl,size_t refs=0);
virtual ~convert();

///
/// Convert string in current locale representation (utf8 or other encoding)
/// to upper case.
///
std::string to_upper(std::string const &str) const;
///
/// Convert string in current locale representation (utf8 or other encoding)
/// to lower case.
///
std::string to_lower(std::string const &str) const;

///
/// Convert string in current locale representation (utf8 or other encoding)
/// to title case.
///
std::string to_title(std::string const &str) const;

///
/// Perform Unicode normalization of the string in current locale representation
/// (utf8 or other encoding). Such conversion may be meaningless for non-Unicode locale.
///
/// Note: if CppCMS is compiled without support of ICU this function does nothing.
///

std::string to_normal(std::string const &str,norm_type how = norm_default) const;

///
/// Create instance of the facet
///

static convert *create(std::locale const &l,std::string provider="default");

private:
util::hold_ptr<convert_impl> impl_;
};


} // locale
} // cppcms


#endif

+ 0
- 88
locale_environment.cpp View File

@@ -1,88 +0,0 @@
#define CPPCMS_SOURCE
#include "locale_environment.h"
#include "service.h"
#include "locale_pool.h"
#include "json.h"

namespace cppcms {
namespace locale {

struct environment::data {
std::locale const *locale;
gettext::tr const *current;
std::string domain_name;
std::string locale_name;
};

environment::environment(cppcms::service &srv) :
service_(srv),
d(new data)
{
d->locale_name=service_.settings().get("locale.default","C");
setup();
}

environment::~environment()
{
}


void environment::setup()
{
d->locale=&service_.locale_pool().get(d->locale_name);

if(std::has_facet<cppcms::locale::gettext>(*d->locale)){
cppcms::locale::gettext const &gt=std::use_facet<cppcms::locale::gettext>(*d->locale);
if(d->domain_name.empty())
d->current=&gt.dictionary();
else
d->current=&gt.dictionary(d->domain_name.c_str());
}
else {
static cppcms::locale::gettext::tr const tr;
d->current=&tr;
}
}

void environment::locale(std::string l)
{
d->locale_name=l;
setup();
}

std::string environment::locale()
{
return d->locale_name;
}

void environment::gettext_domain(std::string s)
{
d->domain_name=s;
setup();
}

std::string environment::gettext_domain()
{
return d->domain_name;
}


char const *environment::ngt(char const *s,char const *p,int n)
{
return d->current->ngettext(s,p,n);
}
char const *environment::gt(char const *s)
{
return d->current->gettext(s);
}

std::locale const &environment::get()
{
return *d->locale;
}


} // locale
} // cppcms



+ 0
- 40
locale_environment.h View File

@@ -1,40 +0,0 @@
#ifndef CPPCMS_LOCALE_ENVIRONMENT_H
#define CPPCMS_LOCALE_ENVIRONMENT_H

#include "defs.h"
#include "hold_ptr.h"
#include "noncopyable.h"
#include "locale_gettext.h"

namespace cppcms {
class service;
namespace locale {
class CPPCMS_API environment : public util::noncopyable {
public:
std::locale const &get();
void set(std::locale const &);
void gettext_domain(std::string s);
std::string gettext_domain();
void locale(std::string);
std::string locale();

char const *gt(char const *s);
char const *ngt(char const *s,char const *p,int n);


environment(cppcms::service &srv);
~environment();

private:
void setup();

struct data;
cppcms::service &service_;
util::hold_ptr<data> d;
};
}//
} // cppcms


#endif

+ 0
- 561
locale_gettext.cpp View File

@@ -1,561 +0,0 @@
#define CPPCMS_SOURCE
#include "locale_gettext.h"
#include "locale_mo_file.h"
#include <cstdlib>
#include <cstring>
#include <ctype.h>
#include <cassert>
#include <memory>
#include <map>
#include <boost/regex.hpp>
#include <boost/shared_ptr.hpp>

namespace cppcms {
namespace locale {
namespace impl {
namespace lambda {
struct plural { // INTERFACE
virtual int operator()(int n) const = 0;
virtual ~plural(){};
};
plural *compile(char const *expr);
}


class trans_thread_safe : public gettext::tr {

struct default_plural : public lambda::plural {
int operator()(int n) const { return n==1 ? 0 : 1; };
~default_plural() {};
};

std::auto_ptr<dictionary> dic_;
std::auto_ptr<lambda::plural> converter_;

static lambda::plural *get_converter(char const *header)
{
using namespace std;
char const *ptr,*ptr2;
string tmp;
lambda::plural *result;
if(!header) goto error;
ptr=strstr(header,"Plural-Forms:");
if(!ptr) goto error;
ptr=strstr(ptr,"plural");
if(!ptr) goto error;
if(ptr[6]=='s') { // Prevent detecting plurals as plural
ptr=strstr(ptr+6,"plural");
}
if(!ptr) goto error;
ptr+=6;
while(*ptr && isblank(*ptr)) ptr++;
if(*ptr!='=') goto error;
ptr++;
ptr2=strstr(ptr,";");
if(!ptr2) goto error;
tmp.append(ptr,ptr2-ptr);
result=lambda::compile(tmp.c_str());
if(!result) goto error;
return result;
error:
return new default_plural();
}
public:
trans_thread_safe(dictionary *dic) :
dic_(dic)
{
char const *header=dic_->lookup("",0);
converter_.reset(get_converter(header));
}
virtual ~trans_thread_safe()
{
}
virtual char const *gettext(char const *s) const
{
char const *t=dic_->lookup(s,0);
return t ? t : s;
}

virtual char const *ngettext(char const *s,char const *p,int n) const
{
int idx=(*converter_)(n);
if(idx<0) idx=0;
char const *t=dic_->lookup(s,idx);
if(!t) {
return n==1 ? s : p;
}
return t;
}
};

} // impl


// The actual gettext class

gettext::tr::~tr()
{
}

char const *gettext::tr::gettext(char const *m) const
{
return m;
}

char const *gettext::tr::ngettext(char const *s,char const *p,int n) const
{
return n==1 ? s : p;
}


std::locale::id gettext::id;

struct gettext::data {
typedef std::map<std::string,boost::shared_ptr<tr> > translators_type;
translators_type translators;
std::string default_domain;
};


gettext::gettext(std::size_t refs) :
std::locale::facet(refs),
d(new data)
{
}
gettext::~gettext()
{
}


bool gettext::load(std::string locale,std::string dir,std::string domain)
{
std::auto_ptr<impl::dictionary> dic;

static boost::regex lreg("^([a-zA-Z]+)(_([a-zA-Z])+)?(\\.([a-zA-Z0-9_\\-]+))?(\\@(.*))?$");
boost::cmatch m;
if(!boost::regex_match(locale.c_str(),m,lreg)) {
return false;
}
std::string variants[4]={
m[1]+m[2]+m[6],
m[1]+m[2],
m[1]+m[6],
m[1]
};
for(int i=0;i<4;i++) {
std::string path=dir + "/" + variants[i] +"/LC_MESSAGES/" + domain + ".mo";
dic.reset(impl::dictionary::load(path.c_str()));
if(dic.get()) {
d->translators[domain].reset(new impl::trans_thread_safe(dic.release()));
return true;
}
}
return false;
}

void gettext::set_default_domain(std::string domain)
{
d->default_domain=domain;
}


gettext::tr const &gettext::do_dictionary() const
{
return do_dictionary(d->default_domain.c_str());
}

gettext::tr const &gettext::do_dictionary(char const *domain) const
{
data::translators_type::const_iterator p=d->translators.find(domain);
if(p == d->translators.end()) {
static const gettext::tr default_one;
return default_one;
}
return *p->second;
}


namespace impl {
namespace lambda {

#define LOG(x)

struct identity : public plural {
virtual int operator()(int n) const { LOG(cout<<"id("<<n<<")\n";) return n; };
};

struct unary : public plural {
plural *op1;
unary(plural *ptr): op1(ptr) {};
virtual ~unary() { delete op1; };
};


struct binary : public plural {
plural *op1,*op2;
binary(plural *p1,plural *p2): op1(p1),op2(p2) {};
virtual ~binary() { delete op1; delete op2; };
};

struct number : public plural {
int val;
number(int v) : val(v) {};
virtual int operator()(int n) const { LOG(cout<<"value="<<val<<endl;) return val; };
};

#ifdef DEBUG_LAMBDA
#define UNOP(name,oper) \
struct name: public unary { name(plural *op) : unary(op) {};\
virtual int operator()(int n) const { int v=(*op1)(n); cerr<<#oper<<v<<endl; return oper(v); }; };

#define BINOP(name,oper) \
struct name : public binary { name(plural *p1,plural *p2) : binary(p1,p2) {}; virtual int operator()(int n) const \
{ int v1=(*op1)(n); int v2=(*op2)(n); cout<<v1<<#oper<<v2<<endl; return v1 oper v2; }; };

#define BINOPD(name,oper) \
struct name : public binary { \
name(plural *p1,plural *p2) : binary(p1,p2) {};\
virtual int operator()(int n) const { int v1=(*op1)(n); int v2=(*op2)(n); \
cout<<v1<<#oper<<v2<<endl; \
return v2==0 ? 0 : v1 oper v2; };\
};
#else
#define UNOP(name,oper) \
struct name: public unary { name(plural *op) : unary(op) {}; virtual int operator()(int n) const { return oper (*op1)(n); }; };

#define BINOP(name,oper) \
struct name : public binary { name(plural *p1,plural *p2) : binary(p1,p2) {}; virtual int operator()(int n) const { return (*op1)(n) oper (*op2)(n); }; };

#define BINOPD(name,oper) \
struct name : public binary { \
name(plural *p1,plural *p2) : binary(p1,p2) {};\
virtual int operator()(int n) const { int v1=(*op1)(n); int v2=(*op2)(n); return v2==0 ? 0 : v1 oper v2; };\
};
#endif
enum { END = 0 , SHL = 256, SHR, GTE,LTE, EQ, NEQ, AND, OR, NUM, VARIABLE };

UNOP(l_not,!)
UNOP(minus,-)
UNOP(bin_not,~)

BINOP(mul,*)
BINOPD(div,/)
BINOPD(mod,%)
static int level10[]={3,'*','/','%'};

BINOP(add,+)
BINOP(sub,-)
static int level9[]={2,'+','-'};

BINOP(shl,<<)
BINOP(shr,>>)
static int level8[]={2,SHL,SHR};

BINOP(gt,>)
BINOP(lt,<)
BINOP(gte,>=)
BINOP(lte,<=)
static int level7[]={4,'<','>',GTE,LTE};

BINOP(eq,==)
BINOP(neq,!=)
static int level6[]={2,EQ,NEQ};

BINOP(bin_and,&)
static int level5[]={1,'&'};

BINOP(bin_xor,^)
static int level4[]={1,'^'};

BINOP(bin_or,|)
static int level3[]={1,'|'};

BINOP(l_and,&&)
static int level2[]={1,AND};

BINOP(l_or,||)
static int level1[]={1,OR};

struct conditional : public plural {
plural *op1,*op2,*op3;
conditional(plural *p1,plural *p2,plural *p3): op1(p1),op2(p2),op3(p3) {};
virtual ~conditional() { delete op1; delete op2; delete op3; };
virtual int operator()(int n) const { return (*op1)(n) ? (*op2)(n) : (*op3)(n); };
};


plural *bin_factory(int value,plural *left,plural *right)
{
switch(value) {
case '/': return new div(left,right);
case '*': return new mul(left,right);
case '%': return new mod(left,right);
case '+': return new add(left,right);
case '-': return new sub(left,right);
case SHL: return new shl(left,right);
case SHR: return new shr(left,right);
case '>': return new gt(left,right);
case '<': return new lt(left,right);
case GTE: return new gte(left,right);
case LTE: return new lte(left,right);
case EQ: return new eq(left,right);
case NEQ: return new neq(left,right);
case '&': return new bin_and(left,right);
case '^': return new bin_xor(left,right);
case '|': return new bin_or (left,right);
case AND: return new l_and(left,right);
case OR: return new l_or(left,right);
default:
delete left;
delete right;
return NULL;
}
}

plural *un_factory(int value,plural *op)
{
switch(value) {
case '!': return new l_not(op);
case '~': return new bin_not(op);
case '-': return new minus(op);
default:
delete op;
return NULL;
}
}

static inline bool is_in(int v,int *p)
{
int len=*p;
p++;
while(len && *p!=v) { p++;len--; }
return len;
}


class tockenizer {
char const *text;
int pos;
int next_tocken;
int int_value;
void step()
{
while(text[pos] && isblank(text[pos])) pos++;
char const *ptr=text+pos;
char *tmp_ptr;
if(strncmp(ptr,"<<",2)==0) { pos+=2; next_tocken=SHL; }
else if(strncmp(ptr,">>",2)==0) { pos+=2; next_tocken=SHR; }
else if(strncmp(ptr,"&&",2)==0) { pos+=2; next_tocken=AND; }
else if(strncmp(ptr,"||",2)==0) { pos+=2; next_tocken=OR; }
else if(strncmp(ptr,"<=",2)==0) { pos+=2; next_tocken=LTE; }
else if(strncmp(ptr,">=",2)==0) { pos+=2; next_tocken=GTE; }
else if(strncmp(ptr,"==",2)==0) { pos+=2; next_tocken=EQ; }
else if(strncmp(ptr,"!=",2)==0) { pos+=2; next_tocken=NEQ; }
else if(*ptr=='n') { pos++; next_tocken=VARIABLE; }
else if(isdigit(*ptr)) { int_value=strtol(text+pos,&tmp_ptr,0); pos=tmp_ptr-text; next_tocken=NUM; }
else if(*ptr=='\0') { next_tocken=0; }
else { next_tocken=*ptr; pos++; }
#ifdef DEBUG_LAMBDA
if(next_tocken>=' ' && next_tocken<=127)
std::cout<<"Tocken:"<<(char)next_tocken<<'\n';
else if(next_tocken==NUM)
std::cout<<"Number:"<<int_value<<"\n";
else if(next_tocken==VARIABLE)
std::cout<<"Variale\n";
else
std::cout<<"TockenID:"<<next_tocken<<'\n';
#endif
}
public:
tockenizer(char const *s) { text=s; pos=0; step(); };
int get(int *val=NULL){
int iv=int_value;
int res=next_tocken;
step();
if(val && res==NUM){
*val=iv;
}
return res;
};
int next(int *val=NULL) {
if(val && next_tocken==NUM) {
*val=int_value;
return NUM;
}
return next_tocken;
}
};


#define BINARY_EXPR(expr,hexpr,list) \
plural *expr() \
{ \
LOG(std::cout<< #expr<<'\n';) \
plural *op1=NULL,*op2=NULL; \
if((op1=hexpr())==NULL) goto error; \
while(is_in(t.next(),list)) { \
LOG(cout<<"Concate with "<<(char)t.next()<<endl;) \
int o=t.get(); \
if((op2=hexpr())==NULL) goto error; \
op1=bin_factory(o,op1,op2); \
assert(op1); \
op2=NULL; \
} \
return op1; \
error: \
delete op1; \
delete op2; \
return NULL; \
}

struct parser {
tockenizer &t;
parser(tockenizer &tin) : t(tin) {};

plural *value_expr()
{
LOG(std::cout<<"Value\n";)
plural *op=NULL;
if(t.next()=='(') {
LOG(std::cout<<"Value ()\n";)
t.get();
if((op=cond_expr())==NULL) goto error;
if(t.get()!=')') goto error;
return op;
}
else if(t.next()==NUM) {
int value;
t.get(&value);
LOG(std::cout<<"Value ("<<value<<")\n";)
return new number(value);
}
else if(t.next()==VARIABLE) {
t.get();
LOG(std::cout<<"Value (n)\n";)
return new identity();
}
return NULL;
error:
delete op;
return NULL;
};

plural *un_expr()
{
plural *op1=NULL;
static int level_unary[]={3,'-','!','~'};
if(is_in(t.next(),level_unary)) {
int op=t.get();
if((op1=un_expr())==NULL)
goto error;
switch(op) {
case '-':
LOG(std::cout<<"Unary(-)\n";)
return new minus(op1);
case '!':
LOG(std::cout<<"Unary(!)\n";)
return new l_not(op1);
case '~':
LOG(std::cout<<"Unary(~)\n";)
return new bin_not(op1);
default:
goto error;
}
}
else {
LOG(std::cout<<"Unary... none\n";)
return value_expr();
}
error:
delete op1;
return NULL;
};

BINARY_EXPR(l10,un_expr,level10);
BINARY_EXPR(l9,l10,level9);
BINARY_EXPR(l8,l9,level8);
BINARY_EXPR(l7,l8,level7);
BINARY_EXPR(l6,l7,level6);
BINARY_EXPR(l5,l6,level5);
BINARY_EXPR(l4,l5,level4);
BINARY_EXPR(l3,l4,level3);
BINARY_EXPR(l2,l3,level2);
BINARY_EXPR(l1,l2,level1);

plural *cond_expr()
{
plural *cond=NULL,*case1=NULL,*case2=NULL;
if((cond=l1())==NULL)
goto error;
if(t.next()=='?') {
LOG(std::cout<<"Condtion... make\n";)
t.get();
if((case1=cond_expr())==NULL)
goto error;
if(t.get()!=':')
goto error;
if((case2=cond_expr())==NULL)
goto error;
}
else {
LOG(std::cout<<"Condtion... none\n";)
return cond;
}
return new conditional(cond,case1,case2);
error:
delete cond;
delete case1;
delete case2;
return NULL;
}
public:
plural *compile()
{
plural *res=cond_expr();
if(res && t.next()!=END) {
delete res;
return NULL;
};
return res;
}
};
#ifdef DEBUG_LAMBDA
string printtree(plural *p)
{
identity *pi=dynamic_cast<identity *>(p);
if(pi) { return string("n"); };
unary *pu=dynamic_cast<unary *>(p);
if(pu) { return string(typeid(*pu).name())+"("+printtree(pu->op1)+")"; }
binary *pb=dynamic_cast<binary *>(p);
if(pb) { return string(typeid(*pb).name())+"("+printtree(pb->op1)+","+printtree(pb->op2)+")"; };
number *pn=dynamic_cast<number *>(p);
if(pn) { char buf[32]; snprintf(buf,sizeof(buf),"(%d)",pn->val); return string(buf); };
conditional *pc=dynamic_cast<conditional *>(p);
if(pc) { return "("+printtree(pc->op1)+")?("+printtree(pc->op2)+"):("+printtree(pc->op3)+")"; };
return string("PLURAL");
}
#endif

plural *compile(char const *str)
{
LOG(cout<<"Compiling:["<<str<<"]\n";)
tockenizer t(str);
parser p(t);
plural *tmp=p.compile();
#ifdef DEBUG_LAMBDA
cout<<printtree(tmp)<<endl;
for(int i=0;i<15;i++) {
cout<<"f("<<i<<")="<<(*tmp)(i)<<endl;
}
#endif
return tmp;
}


} // lambda
} // impl


} // locale
} // cppcms

+ 0
- 57
locale_gettext.h View File

@@ -1,57 +0,0 @@
#ifndef CPPCMS_LOCALE_GETTEXT_H
#define CPPCMS_LOCALE_GETTEXT_H

#include "defs.h"
#include "hold_ptr.h"
#include <locale>

namespace cppcms {
namespace locale {
class CPPCMS_API gettext : public std::locale::facet {
public:
static std::locale::id id;

struct CPPCMS_API tr {
public:
virtual char const *gettext(char const *m) const;
virtual char const *ngettext(char const *s,char const *p,int n) const;
virtual ~tr();
};

gettext(std::size_t refs=0);
~gettext();


tr const &dictionary(char const *domain) const
{
return do_dictionary(domain);
}

tr const &dictionary() const
{
return do_dictionary();
}
bool load(std::string locale_name,std::string path,std::string domain);
void set_default_domain(std::string domain);

protected:

virtual tr const &do_dictionary(char const *domain) const;
virtual tr const &do_dictionary() const;

private:


struct data;
util::hold_ptr<data> d;
};

} // locale
} // cppcms



#endif

+ 0
- 24
locale_icu_locale.cpp View File

@@ -1,24 +0,0 @@
#define CPPCMS_SOURCE

#include "locale_icu_locale.h"
#ifdef HAVE_ICU
namespace cppcms { namespace locale {
std::locale::id icu_locale::id;

struct icu_locale::data {};

icu_locale::icu_locale(std::string name,size_t refs) :
std::locale::facet(refs),
locale_(icu::Locale::createCanonical(name.c_str()))
{
}
icu_locale::~icu_locale()
{
}
icu::Locale const &icu_locale::get() const
{
return locale_;
}
}} // locale::cppcms
#endif

+ 0
- 33
locale_icu_locale.h View File

@@ -1,33 +0,0 @@
#ifndef CPPCMS_LOCALE_ICU_LOCALE_H
#define CPPCMS_LOCALE_ICU_LOCALE_H
#include "defs.h"
#include "config.h"
#include "hold_ptr.h"

#ifdef HAVE_ICU

#include <locale>
#include <string>
#include <unicode/locid.h>

namespace cppcms {
namespace locale {

class CPPCMS_API icu_locale : public std::locale::facet {
public:
static std::locale::id id;
icu_locale(std::string name,size_t refs = 0);

icu::Locale const &get() const;
virtual ~icu_locale();
private:
struct data;
util::hold_ptr<data> d;
icu::Locale locale_;
};
}
}


#endif // HAVE_ICU
#endif

+ 0
- 43
locale_info.cpp View File

@@ -1,43 +0,0 @@
#define CPPCMS_SOURCE
#include "locale_info.h"
#include <boost/regex.hpp>


namespace cppcms {
namespace locale {

std::locale::id info::id;

struct info::data {};

info::info(std::string name,std::size_t refs) :
std::locale::facet(refs),
name_(name),
is_utf8_(false)
{
static boost::regex lreg("^([a-zA-Z]+)(_([a-zA-Z])+)?(\\.([a-zA-Z0-9_\\-]+))?(\\@(.*))?$");
boost::cmatch m;
if(!boost::regex_match(name_.c_str(),m,lreg)) {
return;
}

language_=m[1];
territory_=m[3];
encoding_=m[5];
variant_=m[7];
if(encoding_ == "utf-8" || encoding_=="UTF-8" || encoding_=="utf8" || encoding_=="UTF8")
is_utf8_=true;
}
info::~info()
{
}
std::string info::name() const { return name_; }
std::string info::language() const { return language_; }
std::string info::territory() const { return territory_; }
std::string info::encoding() const { return encoding_; }
std::string info::variant() const { return variant_; }
bool info::is_utf8() const { return is_utf8_; }

} // locale
} // cppcms

+ 0
- 40
locale_info.h View File

@@ -1,40 +0,0 @@
#ifndef CPPCMS_LOCALE_INFO_H
#define CPPCMS_LOCALE_INFO_H

#include "defs.h"
#include "hold_ptr.h"
#include <locale>
#include <string>

namespace cppcms { namespace locale {

class CPPCMS_API info : public std::locale::facet {
public:
static std::locale::id id;
info(std::string name,std::size_t refs=0);
~info();

std::string name() const ;

std::string language() const;
std::string territory() const;
std::string encoding() const;
std::string variant() const;

bool is_utf8() const;
private:
struct data;
util::hold_ptr<data> d;
std::string name_;
std::string language_;
std::string territory_;
std::string encoding_;
std::string variant_;
bool is_utf8_;

};


} } // cppcms::locale

#endif

+ 0
- 342
locale_mo_file.cpp View File

@@ -1,342 +0,0 @@
#include "locale_mo_file.h"
/********************************************************
* This file was adopted by Artyom Tonkikh for *
* purouses of thread safe gettext implementation *
********************************************************/
/*
The MIT License
Copyright (c) 2007 Jonathan Blow (jon [at] number-none [dot] com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
This code is designed to be a very simple drop-in method for reading .mo
files, which are a standard format for storing text strings to help with
internationalization.
For more information, see: http://www.gnu.org/software/gettext/manual/gettext.html
Unfortunately the gettext code is unwieldy. For a simple program like
a video game, we just want to look up some strings in a pre-baked file,
which is what this code does.
We assume that you started with a .po file (which is a human-readable format
containing all the strings) and then compiled it into a .mo file (which is
a binary format that can be efficiently read into memory all in one chunk).
This code then reads straight from the .mo file, so there is no extra
string allocation and corresponding memory fragmentation.
You can generate a .mo file from a .po file using programs such as poedit
or msgfmt.
This code assumes you compiled the hash table into the .mo file. It also
doesn't attempt to care about the encoding of your text; it assumes you
already know what that is. (I use UTF-8 which seems like the only sane
choice).
There's no good reason that this is a C++ file, rather than a C file; I just
wrote it that way originally. You can trivially get rid of the C++-ness if
you want it to compile as straight C.
Send questions to jon [at] number-none [dot] com.
21 December 2007
*/
// From the header file:
// From the .cpp fie:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/stat.h>
#include <string.h>
namespace cppcms { namespace locale { namespace impl {
struct Localization_Text {
Localization_Text(char const*);
~Localization_Text();
void abort();
void *mo_data;
int reversed;
int num_strings;
int original_table_offset;
int translated_table_offset;
int hash_num_entries;
int hash_offset;
};
// This is just the common hashpjw routine, pasted in:
#define HASHWORDBITS 32
inline unsigned long hashpjw(const char *str_param) {
unsigned long hval = 0;
unsigned long g;
const char *s = str_param;
while (*s) {
hval <<= 4;
hval += (unsigned char) *s++;
g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4));
if (g != 0) {
hval ^= g >> (HASHWORDBITS - 8);
hval ^= g;
}
}
return hval;
}
// Here is the actual code:
// Read an entire file into memory. Replace this with any equivalent function.
#ifdef WIN32
#define fileno _fileno
#define fstat _fstat
#define stat _stat
#endif
int os_read_entire_file(FILE *file, void **data_return) {
assert(file);
int descriptor = fileno(file);
struct stat file_stats;
int result = fstat(descriptor, &file_stats);
if (result == -1) return -1;
int length = file_stats.st_size;
unsigned char *data = new unsigned char[length];
fseek(file, 0, SEEK_SET);
int success = fread((void *)data, length, 1, file);
if (success < 1) {
delete [] data;
return -1;
}
*data_return = data;
return length;
}
// Swap the endianness of a 4-byte word.
// On some architectures you can replace my_swap4 with an inlined instruction.
inline unsigned long my_swap4(unsigned long result) {
unsigned long c0 = (result >> 0) & 0xff;
unsigned long c1 = (result >> 8) & 0xff;
unsigned long c2 = (result >> 16) & 0xff;
unsigned long c3 = (result >> 24) & 0xff;
return (c0 << 24) | (c1 << 16) | (c2 << 8) | c3;
}
inline int read4_from_offset(Localization_Text *loc, int offset) {
unsigned long *ptr = (unsigned long *)(((char *)loc->mo_data) + offset);
if (loc->reversed) {
return my_swap4(*ptr);
} else {
return *ptr;
}
}
inline char *get_source_string(Localization_Text *loc, int index,int *len=NULL) {
int addr_offset = loc->original_table_offset + 8 * index;
int string_len = read4_from_offset(loc, addr_offset);
int string_offset = read4_from_offset(loc, addr_offset+4);
char *t = ((char *)loc->mo_data) + string_offset;
if(len) *len=string_len;
return t;
}
inline char *get_translated_string(Localization_Text *loc, int index, int *len=NULL) {
int addr_offset = loc->translated_table_offset + 8 * index;
if(len) *len=read4_from_offset(loc, addr_offset);
int string_offset = read4_from_offset(loc, addr_offset+4);
char *t = ((char *)loc->mo_data) + string_offset;
return t;
}
static bool label_matches(Localization_Text *loc, char const *s, int index) {
char *t = get_source_string(loc, index);
if (strcmp(s, t) == 0) return true;
return false;
}
inline int get_target_index(Localization_Text *loc, char const *s) {
unsigned long V = hashpjw(s);
int S = loc->hash_num_entries;
int hash_cursor = V % S;
int orig_hash_cursor = hash_cursor;
int increment = 1 + (V % (S - 2));
while (1) {
unsigned int index = read4_from_offset(loc, loc->hash_offset + 4 * hash_cursor);
if (index == 0) break;
index--; // Because entries in the table are stored +1 so that 0 means empty.
if (label_matches(loc, s, index)) return index;
// if (index_empty(loc, index)) break;
hash_cursor += increment;
hash_cursor %= S;
if (hash_cursor == orig_hash_cursor) break;
}
return -1;
}
Localization_Text::Localization_Text(char const *filename) {
mo_data = NULL;
num_strings = 0;
original_table_offset = 0;
translated_table_offset = 0;
hash_num_entries = 0;
hash_offset = 0;
FILE *f = fopen(filename, "rb");
if (!f) return;
void *data;
int length = os_read_entire_file(f, &data); // Replace this with any function that will read an entire file and return it in a block of newly-allocated memory.
fclose(f);
if (length < 0) return; // os_read_entire_file returns -1 on failure.
if (length < 24) { // There has to be at least this much in the header...
abort();
return;
}
mo_data = data;
unsigned long *long_ptr = (unsigned long *)data;
const unsigned long TARGET_MAGIC = 0x950412DE;
const unsigned long TARGET_MAGIC_REVERSED = 0xDE120495;
unsigned long magic = long_ptr[0];
if (magic == TARGET_MAGIC) {
reversed = 0;
} else if (magic == TARGET_MAGIC_REVERSED) {
reversed = 1;
} else {
abort();
return;
}
num_strings = read4_from_offset(this, 8);
original_table_offset = read4_from_offset(this, 12);
translated_table_offset = read4_from_offset(this, 16);
hash_num_entries = read4_from_offset(this, 20);
hash_offset = read4_from_offset(this, 24);
if (hash_num_entries == 0) { // We expect a hash table to be there; if it's not, bail.
abort();
return;
}
}
void Localization_Text::abort() {
delete [] (char *)mo_data;
mo_data = NULL;
return;
}
Localization_Text::~Localization_Text() {
if (mo_data) delete [] ((char *)mo_data);
}
dictionary::dictionary(std::auto_ptr<Localization_Text> l) : loc_(l)
{
}
dictionary::~dictionary()
{
}
dictionary *dictionary::load(char const *fname)
{
std::auto_ptr<Localization_Text> loc(new Localization_Text(fname));
if(!loc->mo_data)
return 0;
return new dictionary(loc);
}
char const *dictionary::lookup(char const *s,int std_id) const
{
int len;
int target_index = get_target_index(loc_.get(), s);
if (target_index == -1) return NULL; // Maybe we want to log an error?
char *tmp=get_translated_string(loc_.get(), target_index, &len);
char *p=tmp;
while(std_id>0 && p-tmp<len) {
if(*p)
p++;
else{
p++;
std_id--;
}
}
if(p-tmp<len)
return p;
else
return NULL;
}
} // impl
} // locale
} // cppcms

+ 0
- 30
locale_mo_file.h View File

@@ -1,30 +0,0 @@
#ifndef CPPCMS_LOCALE_MO_FILE_H
#define CPPCMS_LOCLAE_MO_FILE_H

#include <memory>

namespace cppcms {
namespace locale {
namespace impl {
struct Localization_Text;

class dictionary {
public:
~dictionary();
char const *lookup(char const *s,int std_id) const;
static dictionary *load(char const *file_name);
private:
dictionary(std::auto_ptr<Localization_Text>);
dictionary(dictionary const &);
dictionary const &operator=(dictionary const &);

std::auto_ptr<Localization_Text> loc_;
};
}
}

}



#endif

+ 0
- 287
locale_numeric.cpp View File

@@ -1,287 +0,0 @@
#define CPPCMS_SOURCE
#include "locale_numeric.h"
#include "icu_util.h"
#include "locale_icu_locale.h"
#include "cppcms_error.h"

#include <unicode/numfmt.h>
#include <unicode/rbnf.h>
#include <unicode/ustring.h>
#include <unicode/fmtable.h>

#include <boost/shared_ptr.hpp>

namespace cppcms {
namespace locale {
class numeric_impl {
public:
typedef boost::shared_ptr<icu::NumberFormat> formatter_type;

typedef numeric::format_type format_type;

formatter_type get(format_type type,int presision=-1) const
{
formatter_type fmt;

if(type < 0 || type >= numeric::format_count)
type=numeric::format_normal;

fmt=formatters_[type];

if(presision == -1)
return fmt;

fmt.reset(static_cast<icu::NumberFormat *>(fmt->clone()));
fmt->setMaximumFractionDigits(presision);
fmt->setMinimumFractionDigits(presision);

return fmt;
}
std::string format(format_type type,double v,int pres=-1) const
{
icu::UnicodeString str;
return impl::icu_to_std(get(type,pres)->format(v,str),locale_);
}
std::string format(format_type type,int32_t v) const
{
icu::UnicodeString str;
return impl::icu_to_std(get(type)->format(v,str),locale_);
}

std::string format(format_type type,int64_t v) const
{
icu::UnicodeString str;
return impl::icu_to_std(get(type)->format(v,str),locale_);
}

bool parse_base(format_type type,std::string const &str,icu::Formattable &fmt) const
{
icu::ParsePosition pos;
icu::UnicodeString ustr=impl::std_to_icu(str,locale_);

get(type)->parse(ustr,fmt,pos);

if(pos.getIndex()==0 || pos.getIndex()!=ustr.length())
return false;
return true;
}


bool parse(format_type type,std::string const &str,double &v) const
{
icu::Formattable fmt;
if(!parse_base(type,str,fmt))
return false;

UErrorCode code=U_ZERO_ERROR;
double tmp=fmt.getDouble(code);
if(U_FAILURE(code))
return false;
v=tmp;
return true;
}
bool parse(format_type type,std::string const &str,int32_t &v) const
{
icu::Formattable fmt;
if(!parse_base(type,str,fmt))
return false;

UErrorCode code=U_ZERO_ERROR;
int32_t tmp=fmt.getLong(code);
if(U_FAILURE(code))
return false;
v=tmp;
return true;
}
bool parse(format_type type,std::string const &str,int64_t &v) const
{
icu::Formattable fmt;
if(!parse_base(type,str,fmt))
return false;

UErrorCode code=U_ZERO_ERROR;
int64_t tmp=fmt.getInt64(code);
if(U_FAILURE(code))
return false;
v=tmp;
return true;
}

numeric_impl(std::locale const &std_loc) : locale_(std_loc)
{
#define CPPCMS_ICU_VERSION (U_ICU_VERSION_MAJOR_NUM * 100 + U_ICU_VERSION_MINOR_NUM)
icu::Locale const &icu_loc = std::use_facet<icu_locale>(locale_).get();

UErrorCode err=U_ZERO_ERROR;
formatters_[numeric::format_normal].reset(icu::NumberFormat::createInstance(icu_loc,err));
check(err);

formatters_[numeric::format_scientific].reset(icu::NumberFormat::createScientificInstance(icu_loc,err));
check(err);

formatters_[numeric::format_percent].reset(icu::NumberFormat::createPercentInstance(icu_loc,err));
check(err);

formatters_[numeric::format_currency].reset(icu::NumberFormat::createCurrencyInstance(icu_loc,err));
check(err);

#if CPPCMS_ICU_VERSION >= 402

formatter_type fmt(icu::NumberFormat::createInstance(icu_loc,icu::NumberFormat::kIsoCurrencyStyle,err));

#else

formatter_type fmt(static_cast<icu::NumberFormat *>(formatters_[numeric::format_currency]->clone()));
std::string iso_str = std::use_facet<std::moneypunct<char,true> >(locale_).curr_symbol();
icu::UnicodeString iso=impl::std_to_icu(iso_str,locale_);
fmt->setCurrency(iso.getBuffer(),err);
#endif

formatters_[numeric::format_iso_currency] = fmt;
check(err);

formatters_[numeric::format_spellout].reset(new icu::RuleBasedNumberFormat(URBNF_SPELLOUT,icu_loc,err));
check(err);

formatters_[numeric::format_ordinal].reset(new icu::RuleBasedNumberFormat(URBNF_ORDINAL,icu_loc,err));
check(err);
#if CPPCMS_ICU_VERSION >= 402

formatters_[numeric::format_numbering].reset(new icu::RuleBasedNumberFormat(URBNF_NUMERING,icu_loc,err));

#else

formatters_[numeric::format_numbering] = formatters_[numeric::format_normal];

#endif

check(err);

}
private:
void check(UErrorCode err)
{
if(U_FAILURE(err))
throw cppcms_error(std::string("Failed to create NumericFormat") + u_errorName(err));
}
formatter_type formatters_[numeric::format_count];
std::locale locale_;

};


//// Proxy

numeric::~numeric()
{
}
numeric::numeric(numeric_impl *ptr,size_t refs) : std::locale::facet(refs), impl_(ptr)
{
}
std::locale::id numeric::id;

std::string numeric::format(format_type type,double value) const
{
return impl_->format(type,value);
}

std::string numeric::format(format_type type,double value,int presision) const
{
return impl_->format(type,value,presision);
}

std::string numeric::format(format_type type,long long value) const
{
return impl_->format(type,int64_t(value));
}
std::string numeric::format(format_type type,unsigned long long value) const
{
return impl_->format(type,int64_t(value));
}

std::string numeric::format(format_type type,long value) const
{
return impl_->format(type,int64_t(value));
}
std::string numeric::format(format_type type,unsigned long value) const
{
return impl_->format(type,int64_t(value));
}

std::string numeric::format(format_type type,int value) const
{
return impl_->format(type,int32_t(value));
}
std::string numeric::format(format_type type,unsigned value) const
{
return impl_->format(type,int64_t(value));
}
bool numeric::parse(format_type type,std::string const &str,double &value) const
{
return impl_->parse(type,str,value);
}
bool numeric::parse(format_type type,std::string const &str,int &value) const
{
int32_t tmp;
if(!impl_->parse(type,str,tmp)) return false;
value=tmp;
return true;
}
bool numeric::parse(format_type type,std::string const &str,unsigned int &value) const
{
int64_t tmp;
if(!impl_->parse(type,str,tmp)) return false;
value=tmp;
return true;
}

bool numeric::parse(format_type type,std::string const &str,long &value) const
{
int64_t tmp;
if(!impl_->parse(type,str,tmp)) return false;
value=tmp;
return true;
}
bool numeric::parse(format_type type,std::string const &str,unsigned long &value) const
{
int64_t tmp;
if(!impl_->parse(type,str,tmp)) return false;
value=tmp;
return true;
}

bool numeric::parse(format_type type,std::string const &str,long long &value) const
{
int64_t tmp;
if(!impl_->parse(type,str,tmp)) return false;
value=tmp;
return true;
}
bool numeric::parse(format_type type,std::string const &str,unsigned long long &value) const
{
int64_t tmp;
if(!impl_->parse(type,str,tmp)) return false;
value=tmp;
return true;
}
numeric *numeric::create(std::locale const &l)
{
return new numeric(new numeric_impl(l));
}

} // locale
} // cppcms

+ 0
- 67
locale_numeric.h View File

@@ -1,67 +0,0 @@
#ifndef CPPCMS_LOCALE_NUMERIC_H
#define CPPCMS_LOCALE_NUMERIC_H
#include <locale>

#include "defs.h"
#include "hold_ptr.h"

namespace cppcms {
namespace locale {
class numeric_impl;
class CPPCMS_API numeric : public std::locale::facet {
public:

static std::locale::id id;

static numeric *create(std::locale const &l);

typedef enum {
format_normal = 0, ///< Normal, locale default formatting
format_scientific, ///< scientific format
format_percent, ///< percent format
format_currency, ///< currency format
format_iso_currency, ///< currency with ISO currency marker -- '$' -> 'USD'
format_spellout, ///< spellout number if rules availible
format_ordinal, ///< display ordinal format 1st, 2nd etc.
format_numbering, ///< display alternative number format Roman, Hebrew

format_count,
} format_type;

std::string format(format_type type,double value) const;
std::string format(format_type type,double value,int presision) const;

std::string format(format_type type,long long value) const;
std::string format(format_type type,unsigned long long value) const;

std::string format(format_type type,long value) const;
std::string format(format_type type,unsigned long value) const;

std::string format(format_type type,int value) const;
std::string format(format_type type,unsigned value) const;
bool parse(format_type type,std::string const &,double &value) const;

bool parse(format_type type,std::string const &,int &value) const;
bool parse(format_type type,std::string const &,unsigned int &value) const;

bool parse(format_type type,std::string const &,long &value) const;
bool parse(format_type type,std::string const &,unsigned long &value) const;

bool parse(format_type type,std::string const &,long long &value) const;
bool parse(format_type type,std::string const &,unsigned long long &value) const;

private:
numeric(numeric_impl *,size_t refs=0);
virtual ~numeric();

util::hold_ptr<numeric_impl> impl_;

};
}
}

#endif

+ 0
- 95
locale_pool.cpp View File

@@ -1,95 +0,0 @@
#define CPPCMS_SOURCE
#include "locale_pool.h"
#include "cppcms_error.h"
#include "locale_gettext.h"
#include "locale_info.h"
#include "locale_charset.h"
#include "locale_convert.h"
#include "locale_icu_locale.h"
#include "encoding.h"
#include "json.h"
#include <vector>
#include <map>
#include <boost/shared_ptr.hpp>

namespace cppcms { namespace locale {

struct pool::data {
std::vector<std::string> domains;
typedef std::map<std::string,boost::shared_ptr<std::locale> > locales_type;
locales_type locales;
std::string path;
std::locale fallback;

data() : fallback(std::locale::classic()) {}
};

pool::pool(json::value const &settings) :
d(new data)
{
d->path=settings.get("locale.gettext_path","/usr/local/locale");
d->domains=settings.get("locale.gettext_domains",std::vector<std::string>());
std::string default_domain;
if(!d->domains.empty())
default_domain=d->domains.front();
default_domain=settings.get("locale.default_gettext_domain",default_domain);
std::vector<std::string> const &locales=settings.get("locale.locales",std::vector<std::string>());

intrusive_ptr<encoding::validators_set> validators(new encoding::validators_set);

for(unsigned i=0;i<locales.size();i++) {
std::string name=locales[i];
std::auto_ptr<gettext> gt(new gettext());

for(unsigned i=0;i < d->domains.size();i++) {
gt->load(name,d->path,d->domains[i]);
}
gt->set_default_domain(default_domain);

boost::shared_ptr<std::locale> base;

try {
base.reset(new std::locale(name.c_str()));
}
catch(std::runtime_error const &e) {
base.reset(new std::locale("C"));
}

boost::shared_ptr<std::locale> combined(new std::locale(*base,gt.release()));
base=combined;

std::auto_ptr<info> inf(new info(name));
std::string enc=inf->encoding();
combined.reset(new std::locale(*base,inf.release()));
base=combined;
combined.reset(new std::locale(*base,new charset(enc,validators)));
base=combined;
#ifdef HAVE_ICU
combined.reset(new std::locale(*base,new icu_locale(name)));
base=combined;
#endif
combined.reset(new std::locale(*base,convert::create(*base)));
base=combined;

d->locales[name]=combined;
}
}

std::locale const &pool::get(std::string const &name) const
{
data::locales_type::const_iterator p;
if((p=d->locales.find(name))==d->locales.end()) {
return d->fallback;
}
return *p->second;
}


pool::~pool()
{
}




} } // cppcms::locale

+ 0
- 32
locale_pool.h View File

@@ -1,32 +0,0 @@
#ifndef CPPCMS_LOCALE_POOL_H
#define CPPCMS_LOCALE_POOL_H


#include "defs.h"
#include "hold_ptr.h"
#include "noncopyable.h"
#include <string>
#include <locale>


namespace cppcms {
namespace json { class value; }

namespace locale {
class CPPCMS_API pool : util::noncopyable {
public:
pool(json::value const &conf);
~pool();

std::locale const &get(std::string const &name) const;

private:
struct data;
util::hold_ptr<data> d;
};

} // locale
} // cppcms


#endif

locale.h → localization.h View File


+ 52
- 9
service.cpp View File

@@ -1,4 +1,5 @@
#define CPPCMS_SOURCE
#include "asio_config.h"
#include "service.h"
#include "service_impl.h"
#include "applications_pool.h"
@@ -9,11 +10,10 @@
#include "scgi_api.h"
#include "http_api.h"
#include "fastcgi_api.h"
#include "locale_pool.h"
#include "internal_file_server.h"
#include "json.h"
#include "localization.h"

#include "asio_config.h"

#ifdef CPPCMS_POSIX
#include <sys/wait.h>
@@ -24,6 +24,7 @@
#include <boost/lexical_cast.hpp>
#include <boost/regex.hpp>


namespace cppcms {

service::service(json::value const &v) :
@@ -241,7 +242,6 @@ void service::shutdown()

void service::run()
{
locale_pool();
start_acceptor();

if(settings().get("file_server.enable",false))
@@ -426,15 +426,58 @@ void service::stop()
impl_->get_io_service().stop();
}

locale::pool const &service::locale_pool()
locale::generator const &service::generator()
{
if(!impl_->locale_pool_.get()) {
impl_->locale_pool_.reset(new locale::pool(settings()));
if(impl_->locale_generator_.get())
return *impl_->locale_generator_.get();

typedef std::vector<std::string> vstr_type;
impl_->locale_generator_.reset(new locale::generator());
locale::generator &gen= *impl_->locale_generator_;
gen.characters(locale::char_facet);
std::string enc = settings().get("localization.encoding","");

if(!enc.empty())
gen.octet_encoding(enc);

vstr_type paths= settings().get("localization.messages.path",vstr_type());
vstr_type domains = settings().get("localization.messages.domains",vstr_type());

if(!paths.empty() && !domains.empty()) {
unsigned i;
for(i=0;i<paths.size();i++)
gen.add_messages_path(paths[i]);
for(i=0;i<domains.size();i++)
gen.add_messages_domain(domains[i]);
}

vstr_type locales = settings().get("localization.messages.locales",vstr_type());

if(locales.empty()) {
gen.preload("");
impl_->default_locale_=gen("");
}
else {
for(unsigned i=0;i<locales.size();i++)
gen.preload(locales[i]);
impl_->default_locale_=gen(locales[0]);
}
return *impl_->locale_pool_;

return *impl_->locale_generator_.get();

}

std::locale service::locale()
{
generator();
return impl_->default_locale_;
}
std::locale service::locale(std::string const &name)
{
return generator().get(name);
}


namespace impl {
service::service() :
io_service_(new boost::asio::io_service()),
@@ -452,7 +495,7 @@ namespace impl {
// applications pool should be destroyed after
// io_service, because soma apps may try unregister themselfs
applications_pool_.reset();
locale_pool_.reset();
locale_generator_.reset();
settings_.reset();

}


+ 7
- 5
service.h View File

@@ -5,19 +5,18 @@
#include "noncopyable.h"
#include "hold_ptr.h"
#include "callback0.h"
#include <locale>

namespace boost { namespace locale { class generator; }}

namespace cppcms {
namespace locale { using namespace boost::locale; }
namespace impl {
class service;
}

class applications_pool;
class thread_pool;
namespace locale {
class pool;
}
namespace json {
class value;
}
@@ -35,7 +34,10 @@ namespace cppcms {
cppcms::applications_pool &applications_pool();
cppcms::thread_pool &thread_pool();
json::value const &settings();
cppcms::locale::pool const &locale_pool();

locale::generator const &generator();
std::locale locale();
std::locale locale(std::string const &name);

cppcms::impl::service &impl();



+ 3
- 1
service_impl.h View File

@@ -3,6 +3,7 @@

#include "asio_config.h"
#include "json.h"
#include "localization.h"
#include <memory>

namespace cppcms {
@@ -33,7 +34,8 @@ namespace impl {
std::auto_ptr<json::value> settings_;
std::auto_ptr<applications_pool> applications_pool_;
std::auto_ptr<thread_pool> thread_pool_;
std::auto_ptr<locale::pool> locale_pool_;
std::auto_ptr<locale::generator> locale_generator_;
std::locale default_locale_;

#ifdef CPPCMS_WIN32
typedef SOCKET native_socket_type;


+ 0
- 446
utf8_iterator.cpp View File

@@ -1,446 +0,0 @@
#define CPPCMS_SOURCE
#include "utf8_iterator.h"
#include "config.h"
#include "utf_iterator.h"
#include "noncopyable.h"
#include "locale_icu_locale.h"

#ifdef HAVE_ICU
#include <unicode/locid.h>
#include <unicode/brkiter.h>
#include <unicode/utext.h>
#endif
#include <stdexcept>
#include <typeinfo>


namespace cppcms { namespace utf8 { namespace details {
#ifdef HAVE_ICU


/// Implementation

class break_iterator_impl : util::noncopyable {
public:
break_iterator_impl(char const *b,char const *e,icu::BreakIterator *it,UText *text = 0,size_t pos = (size_t)(-1)) :
begin_(b),
end_(e),
br_(it),
text_(text)
{
if(text_ == 0) {
UErrorCode status = U_ZERO_ERROR;
text_=utext_openUTF8(0,begin_,end_-begin_,&status);
if(!U_SUCCESS(status)) {
delete br_;
throw std::runtime_error(u_errorName(status));
}
}
UErrorCode status = U_ZERO_ERROR;
br_->setText(text_,status);

if(!U_SUCCESS(status)) {
utext_close(text_);
delete br_;
throw std::runtime_error(u_errorName(status));
}

if(pos!=(size_t)(-1))
br_->isBoundary(pos);
else
first();
}
~break_iterator_impl()
{
utext_close(text_);
delete br_;
}
break_iterator_impl *clone() const
{
UErrorCode status = U_ZERO_ERROR;
UText *text=utext_clone(0,text_,false,true,&status);
if(!U_SUCCESS(status)) {
throw std::runtime_error(u_errorName(status));
}
return new break_iterator_impl(begin_,end_,br_->clone(),text,br_->current());
}

bool equal(break_iterator_impl const &other) const
{
return *br_ == *other.br_;
}
bool less(break_iterator_impl const &other) const
{
return br_->current() < other.br_->current();
}

char const *to_che(int32_t n) const
{
if(n == icu::BreakIterator::DONE || begin_ + n > end_)
return end_;
return begin_ + n;
}

char const *to_chb(int32_t n) const
{
if(n == icu::BreakIterator::DONE || begin_ + n < begin_)
return begin_;
return begin_ + n;
}

char const *curr() const
{
return to_che(br_->current());
}
char const *first()
{
return to_che(br_->first());
}

char const *next()
{
return to_che(br_->next());
}

char const *last()
{
return to_chb(br_->last());
}
char const *prev()
{
return to_chb(br_->previous());
}
void curr(char const *pos)
{
br_->isBoundary(pos - begin_);
}
char const *following(char const *pos)
{
return to_che(br_->following(pos - begin_));
}
char const *preceding(char const *pos)
{
return to_chb(br_->preceding(pos - begin_));
}

char const *move(int n)
{
if(n>0)
return to_che(br_->next(n));
else
return to_chb(br_->next(n));
}

char const *begin_;
char const *end_;
icu::BreakIterator *br_;
UText *text_;
};


/// Actual Iterator


namespace {
icu::Locale const &icu_locale(std::locale const &l)
{
try {
return std::use_facet<locale::icu_locale>(l).get();
}
catch(std::bad_cast const &e) {
return icu::Locale::getDefault();
}
}
icu::BreakIterator *create_iterator( std::locale const &l,
icu::BreakIterator *(*factory)(icu::Locale const &l,UErrorCode &err))
{
icu::Locale const &loc=icu_locale(l);

UErrorCode status = U_ZERO_ERROR;
icu::BreakIterator *br = factory(loc,status);
if(!U_SUCCESS(status)) {
delete br;
throw std::runtime_error(u_errorName(status));
}
return br;
}
}

template<>
break_iterator::break_iterator(char const *begin,char const *end,std::locale const &loc,character_tag tag) :
impl_(new break_iterator_impl(begin,end,create_iterator(loc, &icu::BreakIterator::createCharacterInstance)))
{
}
template<>
break_iterator::break_iterator(char const *begin,char const *end,std::locale const &loc,word_tag tag) :
impl_(new break_iterator_impl(begin,end,create_iterator(loc, &icu::BreakIterator::createWordInstance)))
{
}
template<>
break_iterator::break_iterator(char const *begin,char const *end,std::locale const &loc,line_tag tag) :
impl_(new break_iterator_impl(begin,end,create_iterator(loc, &icu::BreakIterator::createLineInstance)))
{
}

template<>
break_iterator::break_iterator(char const *begin,char const *end,std::locale const &loc,sentence_tag tag) :
impl_(new break_iterator_impl(begin,end,create_iterator(loc, &icu::BreakIterator::createSentenceInstance)))
{
}

#else /// NO ICU
class break_iterator_impl {
codepoint_iterator current_;
public:
typedef enum { charrecter, word, sentence, line } iter_type;

iter_type type_;

char const *begin_,*end_;
std::ctype<wchar_t> const *wfacet_;
std::ctype<char> const *facet_;


break_iterator_impl *clone() const
{
return new break_iterator_impl(*this);
}

break_iterator_impl(char const *begin,char const *end,std::locale const &l,iter_type type) :
current_(begin,end,l,code_point_tag()),
type_(type),
begin_(begin),
end_(end),
wfacet_(0),
facet_(0)
{
if(std::has_facet<std::ctype<wchar_t> >(l)) {
wfacet_ = & std::use_facet<std::ctype<wchar_t> >(l);
}
else {
facet_ = & std::use_facet<std::ctype<char> >(l);;
}
}

bool is(std::ctype_base::mask m)
{
char const *ptr=curr();
if(ptr >= end_)
return false;
if(wfacet_) {
wchar_t v=utf8::next(ptr,end_);
return wfacet_->is(m,v);
}
else {
return facet_->is(m,*ptr);
}
}
bool is_alpha()
{
return is(std::ctype_base::alpha);
}
bool is_sentence_break()
{
char const *ptr=curr();
if(ptr >= end_)
return false;
if(wfacet_) {
wchar_t v=utf8::next(ptr,end_);
static const std::basic_string<wchar_t> breakers(L".;?!");
return breakers.find(v)!=std::basic_string<wchar_t>::npos;
}
else {
char v=*ptr;
static const std::string breakers(".;?!");
return breakers.find(v)!=std::string::npos;
}
}
bool is_space()
{
return is(std::ctype_base::space);
}

bool equal(break_iterator_impl const &other) const
{
return current_.equal(other.current_);
}
bool less(break_iterator_impl const &other) const
{
return current_.less(other.current_);
}

char const *curr() const
{
return current_.curr();
}
char const *next()
{
switch(type_) {
case charrecter:
return current_.next();
case word:
do
current_.next();
while(current_.curr() < end_ && is_alpha());
return curr();
case sentence:
while(current_.curr() < end_ && !is_sentence_break())
current_.next();
return current_.next();
case line:
do
current_.next();
while(current_.curr() < end_ && !is_space());
return curr();
default: throw std::runtime_error("Internal Error in " __FILE__ );
}
}
char const *prev()
{
switch(type_) {
case charrecter:
return current_.prev();
case word:
do
current_.prev();
while(current_.curr() > begin_ && is_alpha());
return curr();
case sentence:
do
current_.prev();
while(current_.curr() > begin_ && !is_sentence_break());
return current_.curr();
case line:
do
current_.prev();
while(current_.curr() > begin_ && !is_space());
return curr();
default: throw std::runtime_error("Internal Error in " __FILE__ );
}
}
char const *first()
{
return current_.first();
}
char const *last()
{
return current_.last();
}
void curr(char const *iter)
{
switch(type_) {
case charrecter: current_.curr(iter); break;
default:
current_.curr();
next();
prev();
}
}
char const *following(char const *pos)
{
switch(type_) {
case charrecter: return current_.following(pos);
default:
current_.curr();
return next();
}
}

char const *preceding(char const *pos)
{
switch(type_) {
case charrecter: return current_.preceding(pos);
default:
current_.curr();
return prev();
}
}
char const *move(int steps)
{
while(steps > 0) {
next();
steps --;
}
while(steps < 0) {
prev();
steps ++;
}
return curr();
}
};
template<>
break_iterator::break_iterator(char const *begin,char const *end,std::locale const &loc,character_tag tag) :
impl_(new break_iterator_impl(begin,end,loc,break_iterator_impl::charrecter))
{
}
template<>
break_iterator::break_iterator(char const *begin,char const *end,std::locale const &loc,word_tag tag) :
impl_(new break_iterator_impl(begin,end,loc,break_iterator_impl::word))
{
}
template<>
break_iterator::break_iterator(char const *begin,char const *end,std::locale const &loc,line_tag tag) :
impl_(new break_iterator_impl(begin,end,loc,break_iterator_impl::line))
{
}

template<>
break_iterator::break_iterator(char const *begin,char const *end,std::locale const &loc,sentence_tag tag) :
impl_(new break_iterator_impl(begin,end,loc,break_iterator_impl::sentence))
{
}


#endif

break_iterator::break_iterator()
{
}
break_iterator::~break_iterator()
{
}
break_iterator::break_iterator(break_iterator const &other) : impl_(other.impl_)
{
}
break_iterator const &break_iterator::operator=(break_iterator const &other)
{
impl_ = other.impl_;
return *this;
}
bool break_iterator::equal(break_iterator const &other) const
{
if(impl_.get() && other.impl_.get())
return impl_->equal(*other.impl_);
if(!impl_.get() && !other.impl_.get())
return true;
return false;
}
bool break_iterator::less(break_iterator const &other) const
{
if(impl_.get() && other.impl_.get())
return impl_->less(*other.impl_);
return false;
}

char const *break_iterator::move(int n) { return impl_->move(n); }
char const *break_iterator::next() { return impl_->next(); }
char const *break_iterator::first() { return impl_->first(); }
char const *break_iterator::prev() { return impl_->prev(); }
char const *break_iterator::last() { return impl_->last(); }
char const *break_iterator::curr() const { return impl_->curr(); }
char const *break_iterator::following(char const *p) { return impl_->following(p); }
char const *break_iterator::preceding(char const *p) { return impl_->preceding(p); }
void break_iterator::curr(char const *p) { impl_->curr(p); }

}}} // cppcms::utf8::details

+ 0
- 432
utf8_iterator.h View File

@@ -1,432 +0,0 @@
#ifndef CPPCMS_UTF8_ITERATOR_H
#define CPPCMS_UTF8_ITERATOR_H

#include "defs.h"
#include "clone_ptr.h"
#include <locale>
#include <string>

namespace cppcms {

namespace utf8 {

namespace details {

struct code_point_tag {};
struct character_tag {};
struct word_tag {};
struct sentence_tag {};
struct line_tag {};


template<typename T>
struct string_traits;

template<typename TraitsT,typename AllocT>
struct string_traits<std::basic_string<char,TraitsT,AllocT> &>
{
typedef typename std::basic_string<char,TraitsT,AllocT> string_type;
typedef typename string_type::iterator iterator_type;
typedef string_type *pointer_type;
};
template<typename TraitsT,typename AllocT>
struct string_traits<std::basic_string<char,TraitsT,AllocT> const &>
{
typedef typename std::basic_string<char,TraitsT,AllocT> string_type;
typedef typename string_type::const_iterator iterator_type;
typedef string_type const *pointer_type;
};

class codepoint_iterator {
public:
codepoint_iterator() : begin_(0), end_(0), current_(0)
{
}
template<typename Tag>
codepoint_iterator(char const *begin,char const *end,std::locale const &loc,Tag t);

bool equal(codepoint_iterator const &other) const
{
return current_ == other.current_;
}

bool less(codepoint_iterator const &other) const
{
return current_ < other.current_;
}

char const *curr() const
{
return current_;
}
char const *next()
{
if(current_ >= end_)
return current_;

unsigned char tmp=*current_++;
if((tmp & 0x80) == 0)
return current_;
while(current_ < end_ && ((unsigned char)(*current_) & 0xC0) == 0x80)
current_ ++;
return current_;

}

char const *prev()
{
while(current_ > begin_) {
unsigned char c = * (--current_);
if( (c & 0xC0) != 0x80 )// 10xxxxxx -- utf8 part
break;
}
return current_;
}

char const *first()
{
current_ = begin_;
return current_;
}

char const *last()
{
current_ = end_;
return current_;
}

void curr(char const *iter)
{
if(iter <= begin_) {
current_ = begin_;
}
else if(iter >= end_) {
current_ = end_;
}
else {
current_ = iter;
}

while( current_ != end_ && (((unsigned char)(*current_)) & 0xC0) == 0x80)
current_++;
}

char const *following(char const *pos)
{
curr(pos);
return next();
}
char const *preceding(char const *pos)
{
curr(pos);
return prev();
}
char const *move(int steps)
{
while(steps > 0) {
next();
steps --;
}
while(steps < 0) {
prev();
steps ++;
}
return curr();

}

private:
char const *begin_;
char const *end_;
char const *current_;
};
template<>
inline codepoint_iterator::codepoint_iterator( char const *begin,
char const *end,
std::locale const &loc,
code_point_tag unused) :
begin_(begin),
end_(end),
current_(begin)
{
}
class break_iterator_impl;

class CPPCMS_API break_iterator {
public:
break_iterator();
template<typename Tag>
break_iterator(char const *begin,char const *end,std::locale const &loc,Tag t);
break_iterator(break_iterator const &);
break_iterator const &operator = (break_iterator const &);
~break_iterator();

bool equal(break_iterator const &other) const;
bool less(break_iterator const &other) const;

char const *curr() const;
char const *next();
char const *prev();
char const *first();
char const *last();
void curr(char const *iter);
char const *following(char const *pos);
char const *preceding(char const *pos);
char const *move(int n);
private:
util::clone_ptr<break_iterator_impl> impl_;

};
template<>
CPPCMS_API break_iterator::break_iterator( char const *begin,
char const *end,
std::locale const &l,
character_tag tag);
template<>
CPPCMS_API break_iterator::break_iterator( char const *begin,
char const *end,
std::locale const &l,
word_tag tag);
template<>
CPPCMS_API break_iterator::break_iterator( char const *begin,
char const *end,
std::locale const &l,
sentence_tag tag);
template<>
CPPCMS_API break_iterator::break_iterator( char const *begin,
char const *end,
std::locale const &l,
line_tag tag);

} // details


template<typename StringType,typename WalkerType,typename TagType>
class base_iterator {
public:
typedef typename details::string_traits<StringType>::iterator_type iterator_type;
typename details::string_traits<StringType>::pointer_type pointer_type;

bool operator==(base_iterator const &other) const
{
return walker_.equal(other.walker_);
}
bool operator!=(base_iterator const &other) const
{
return !walker_.equal(other.walker_);
}
bool operator< (base_iterator const &other) const
{
return walker_.less(other.walker_);
}
bool operator> (base_iterator const &other) const
{
return other.walker_.less(walker_);
}
bool operator>= (base_iterator const &other) const
{
return !walker_.less(other.walker_);
}
bool operator<= (base_iterator const &other) const
{
return !other.walker_.less(walker_);
}

base_iterator(StringType str,std::locale const &l = std::locale()) :
walker_(&*str.begin(),&*str.end(),l,TagType()),
begin_(str.begin()),
cbegin_(str.data())
{
}
base_iterator(iterator_type begin,iterator_type end,std::locale const &l = std::locale()) :
walker_(&*begin,&*end,l,TagType()),
begin_(begin),
cbegin_(&*begin)
{
}

base_iterator(){}

iterator_type operator*() const
{
return to_iterator(walker_.curr());
}
iterator_type next()
{
return to_iterator(walker_.next());

}

iterator_type prev()
{
return to_iterator(walker_.prev());
}

iterator_type first()
{
return to_iterator(walker_.first());
}

iterator_type last()
{
return to_iterator(walker_.last());
}

iterator_type to_iterator(char const *ptr) const
{
return begin_ + (ptr - cbegin_);
}


base_iterator const &operator=(iterator_type iter)
{
walker_.curr(cbegin_ + (iter - begin_));
return *this;
}

iterator_type following(iterator_type pos)
{
return to_iterator(walker_.following(cbegin_ + (pos - begin_)));
}
iterator_type preceding(iterator_type pos)
{
return to_iterator(walker_.preceding(cbegin_ + (pos - begin_)));
}

base_iterator operator++(int unused)
{
base_iterator tmp(*this);
next();
return tmp;
}

base_iterator &operator++()
{
next();
return *this;
}
base_iterator operator--(int unused)
{
base_iterator tmp(*this);
prev();
return tmp;
}

base_iterator &operator--()
{
prev();
return *this;
}

base_iterator const &operator+=(int n)
{
walker_.move(n);
return *this;
}
base_iterator const &operator-=(int n)
{
walker_.move(-n);
return *this;
}

private:
WalkerType walker_;
iterator_type begin_;
char const *cbegin_;
};

template<typename StringType,typename WalkerType,typename TagType>
base_iterator<StringType,WalkerType,TagType> operator+(
base_iterator<StringType,WalkerType,TagType> const &iter,
int n)
{
base_iterator<StringType,WalkerType,TagType> tmp=iter;
tmp+=n;
return tmp;
}
template<typename StringType,typename WalkerType,typename TagType>
base_iterator<StringType,WalkerType,TagType> operator+(
int n,
base_iterator<StringType,WalkerType,TagType> const &iter)
{
base_iterator<StringType,WalkerType,TagType> tmp=iter;
tmp+=n;
return tmp;
}
template<typename StringType,typename WalkerType,typename TagType>
base_iterator<StringType,WalkerType,TagType> operator-(
base_iterator<StringType,WalkerType,TagType> const &iter,
int n)
{
base_iterator<StringType,WalkerType,TagType> tmp=iter;
tmp-=n;
return tmp;
}
template<typename StringType,typename WalkerType,typename TagType>
base_iterator<StringType,WalkerType,TagType> operator-(
base_iterator<StringType,WalkerType,TagType> const &a,
base_iterator<StringType,WalkerType,TagType> const &b)
{
int n=0;
if(a > b) {
base_iterator<StringType,WalkerType,TagType> tmp=b;
int n = 0;
while(b < a) {
++b;
++n;
}
}
else if( b > a ) {
base_iterator<StringType,WalkerType,TagType> tmp=a;
int n = 0;
while(b > a) {
++a;
--n;
}
}
return n;
}

typedef base_iterator<std::string &,details::codepoint_iterator,details::code_point_tag> code_point_iterator;
typedef base_iterator<std::string const &,details::codepoint_iterator,details::code_point_tag> const_code_point_iterator;
typedef base_iterator<std::string &,details::break_iterator,details::character_tag> character_iterator;
typedef base_iterator<std::string const &,details::break_iterator,details::character_tag> const_character_iterator;
typedef base_iterator<std::string &,details::break_iterator,details::word_tag> word_iterator;
typedef base_iterator<std::string const &,details::break_iterator,details::word_tag> const_word_iterator;

typedef base_iterator<std::string &,details::break_iterator,details::sentence_tag> sentence_iterator;
typedef base_iterator<std::string const &,details::break_iterator,details::sentence_tag> const_sentence_iterator;

typedef base_iterator<std::string &,details::break_iterator,details::line_tag> line_iterator;
typedef base_iterator<std::string const &,details::break_iterator,details::line_tag> const_line_iterator;

} // utf8

} // cppcms




#endif

Loading…
Cancel
Save