@@ -28,15 +28,25 @@ endif(NOT ICU_UC OR NOT ICU_DATA OR NOT ICU_I18N) | |||||
set(HAVE_ICU 1) | 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(${CMAKE_BINARY_DIR}) | ||||
include_directories(boost_locale) | 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( | check_cxx_source_compiles( | ||||
"int main() { volatile long v;__sync_add_and_fetch(&v,1); }" | "int main() { volatile long v;__sync_add_and_fetch(&v,1); }" | ||||
@@ -113,12 +123,7 @@ set(CPPCMS_SOURCES | |||||
url_dispatcher.cpp | url_dispatcher.cpp | ||||
http_cookie.cpp | http_cookie.cpp | ||||
util.cpp | util.cpp | ||||
locale_mo_file.cpp | |||||
locale_gettext.cpp | |||||
locale_environment.cpp | |||||
locale_pool.cpp | |||||
base64.cpp | base64.cpp | ||||
locale_info.cpp | |||||
base_view.cpp | base_view.cpp | ||||
internal_file_server.cpp | internal_file_server.cpp | ||||
scgi_api.cpp | scgi_api.cpp | ||||
@@ -128,15 +133,8 @@ set(CPPCMS_SOURCES | |||||
aio_timer.cpp | aio_timer.cpp | ||||
json.cpp | json.cpp | ||||
encoding.cpp | encoding.cpp | ||||
locale_charset.cpp | |||||
locale_icu_locale.cpp | |||||
locale_convert.cpp | |||||
locale_numeric.cpp | |||||
locale_collate.cpp | |||||
icu_util.cpp | |||||
form.cpp | form.cpp | ||||
filters.cpp | |||||
utf8_iterator.cpp) | |||||
filters.cpp) | |||||
add_definitions(-DDLL_EXPORT) | add_definitions(-DDLL_EXPORT) | ||||
@@ -160,8 +158,8 @@ if(ICONV_LIB) | |||||
endif(ICONV_LIB) | endif(ICONV_LIB) | ||||
if(WS2_32 AND WSOCK32) | 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) | endif(WS2_32 AND WSOCK32) | ||||
if(LIB_GETHOSTBYNAME) | if(LIB_GETHOSTBYNAME) | ||||
@@ -5,8 +5,6 @@ | |||||
#include "service.h" | #include "service.h" | ||||
#include "cppcms_error.h" | #include "cppcms_error.h" | ||||
#include "url_dispatcher.h" | #include "url_dispatcher.h" | ||||
#include "locale_environment.h" | |||||
#include "locale_gettext.h" | |||||
#include "intrusive_ptr.h" | #include "intrusive_ptr.h" | ||||
#include "applications_pool.h" | #include "applications_pool.h" | ||||
#include "http_response.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() | bool application::is_asynchronous() | ||||
{ | { | ||||
return pool_id() < 0; | return pool_id() < 0; | ||||
@@ -41,11 +41,6 @@ namespace cppcms { | |||||
http::request &request(); | http::request &request(); | ||||
http::response &response(); | http::response &response(); | ||||
url_dispatcher &dispatcher(); | 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); | ||||
void add(application &app,std::string regex,int part); | void add(application &app,std::string regex,int part); | ||||
@@ -1,9 +1,6 @@ | |||||
#define CPPCMS_SOURCE | #define CPPCMS_SOURCE | ||||
#include "base_view.h" | #include "base_view.h" | ||||
#include "util.h" | #include "util.h" | ||||
#include "locale_gettext.h" | |||||
#include "locale_environment.h" | |||||
#include "locale_convert.h" | |||||
#include "cppcms_error.h" | #include "cppcms_error.h" | ||||
#include <vector> | #include <vector> | ||||
@@ -13,7 +10,6 @@ namespace cppcms { | |||||
struct base_view::data { | struct base_view::data { | ||||
std::ostream *out; | std::ostream *out; | ||||
locale::gettext::tr const *tr; | |||||
}; | }; | ||||
base_view::base_view(std::ostream &out) : | base_view::base_view(std::ostream &out) : | ||||
@@ -29,23 +29,14 @@ | |||||
// "level" : 1, | // "level" : 1, | ||||
// "buffer" : 4096 | // "buffer" : 4096 | ||||
}, | }, | ||||
"l10n" : { | |||||
"defaults" : { | |||||
"encoding" : "UTF-8", | |||||
"locale" : "en_US", | |||||
"std_locale" : [ "ICU" , "C" ] | |||||
}, | |||||
"localization" : { | |||||
"encoding" : "UTF-8", | |||||
"messages" : { | "messages" : { | ||||
"paths" : [ "./transtext/locale" ], | |||||
"paths" : [ "../transtext/locale" ], | |||||
"domains" : [ "app", "test" ], | "domains" : [ "app", "test" ], | ||||
"default_domain" : ["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" : { | "locale" : { | ||||
"locales" : | "locales" : | ||||
@@ -1,7 +1,6 @@ | |||||
#define CPPCMS_SOURCE | #define CPPCMS_SOURCE | ||||
#include "filters.h" | #include "filters.h" | ||||
#include "base64.h" | #include "base64.h" | ||||
#include "locale_convert.h" | |||||
#include "util.h" | #include "util.h" | ||||
#include <iostream> | #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; } | to_upper const &to_upper::operator=(to_upper const &other){ obj_ = other.obj_; return *this; } | ||||
void to_upper::operator()(std::ostream &out) const | 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 {}; | 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; } | to_lower const &to_lower::operator=(to_lower const &other){ obj_ = other.obj_; return *this; } | ||||
void to_lower::operator()(std::ostream &out) const | 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 {}; | 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; } | to_title const &to_title::operator=(to_title const &other){ obj_ = other.obj_; return *this; } | ||||
void to_title::operator()(std::ostream &out) const | 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 {}; | struct escape::data {}; | ||||
@@ -156,151 +157,43 @@ namespace cppcms { namespace filters { | |||||
os<<buf; | 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 date::data {}; | ||||
struct time::data {}; | struct time::data {}; | ||||
struct datetime::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() {} | date::~date() {} | ||||
datetime::~datetime() {} | datetime::~datetime() {} | ||||
time::~time() {} | 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 | 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 | 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 | 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_; | |||||
} | } | ||||
@@ -8,8 +8,8 @@ | |||||
#include <iostream> | #include <iostream> | ||||
#include "defs.h" | #include "defs.h" | ||||
#include "copy_ptr.h" | #include "copy_ptr.h" | ||||
#include "localization.h" | |||||
#include "locale_gettext.h" | |||||
namespace cppcms { | namespace cppcms { | ||||
namespace filters { | namespace filters { | ||||
@@ -287,35 +287,7 @@ namespace cppcms { | |||||
return out; | 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 { | class CPPCMS_API date { | ||||
public: | public: | ||||
@@ -324,11 +296,11 @@ namespace cppcms { | |||||
date const &operator=(date const &other); | date const &operator=(date const &other); | ||||
~date(); | ~date(); | ||||
date(std::tm const &t); | |||||
date(double time); | |||||
void operator()(std::ostream &out) const; | void operator()(std::ostream &out) const; | ||||
private: | private: | ||||
struct data; | struct data; | ||||
std::tm const *t_; | |||||
double time_; | |||||
util::copy_ptr<data> d; | util::copy_ptr<data> d; | ||||
}; | }; | ||||
@@ -345,11 +317,11 @@ namespace cppcms { | |||||
time const &operator=(time const &other); | time const &operator=(time const &other); | ||||
~time(); | ~time(); | ||||
time(std::tm const &t); | |||||
time(double time); | |||||
void operator()(std::ostream &out) const; | void operator()(std::ostream &out) const; | ||||
private: | private: | ||||
struct data; | struct data; | ||||
std::tm const *t_; | |||||
double time_; | |||||
util::copy_ptr<data> d; | util::copy_ptr<data> d; | ||||
}; | }; | ||||
@@ -365,11 +337,11 @@ namespace cppcms { | |||||
datetime const &operator=(datetime const &other); | datetime const &operator=(datetime const &other); | ||||
~datetime(); | ~datetime(); | ||||
datetime(std::tm const &t); | |||||
datetime(double t); | |||||
void operator()(std::ostream &out) const; | void operator()(std::ostream &out) const; | ||||
private: | private: | ||||
struct data; | struct data; | ||||
std::tm const *t_; | |||||
double time_; | |||||
util::copy_ptr<data> d; | util::copy_ptr<data> d; | ||||
}; | }; | ||||
@@ -378,339 +350,14 @@ namespace cppcms { | |||||
obj(out); | obj(out); | ||||
return 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 | #undef CPPCMS_STREAMED | ||||
@@ -3,8 +3,6 @@ | |||||
#include <iostream> | #include <iostream> | ||||
#include <stack> | #include <stack> | ||||
#include <boost/format.hpp> | #include <boost/format.hpp> | ||||
#include "locale_charset.h" | |||||
#include "locale_environment.h" | |||||
namespace cppcms { | namespace cppcms { | ||||
@@ -380,12 +378,14 @@ void base_text::value(std::string v) | |||||
std::string base_text::value(std::locale const &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) | 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() | void base_text::non_empty() | ||||
@@ -432,9 +432,9 @@ void base_text::load(http::context &context) | |||||
set(true); | set(true); | ||||
if(validate_charset_) { | if(validate_charset_) { | ||||
code_points_ = 0; | 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_)) | if(!charset.validate(value_,code_points_)) | ||||
valid(false); | |||||
valid(false);*/ | |||||
} | } | ||||
else { | else { | ||||
code_points_=value_.size(); | code_points_=value_.size(); | ||||
@@ -14,7 +14,6 @@ | |||||
#include "http_context.h" | #include "http_context.h" | ||||
#include "http_request.h" | #include "http_request.h" | ||||
#include "http_response.h" | #include "http_response.h" | ||||
#include "locale_environment.h" | |||||
#include "copy_ptr.h" | #include "copy_ptr.h" | ||||
#include "cppcms_error.h" | #include "cppcms_error.h" | ||||
#include "util.h" | #include "util.h" | ||||
@@ -897,7 +896,7 @@ namespace cppcms { | |||||
return; | return; | ||||
std::istringstream ss(loaded_string_); | std::istringstream ss(loaded_string_); | ||||
ss.imbue(context.locale().get()); | |||||
ss.imbue(context.locale()); | |||||
ss>>value_; | ss>>value_; | ||||
if(ss.fail() || !ss.eof()) | if(ss.fail() || !ss.eof()) | ||||
valid(false); | valid(false); | ||||
@@ -5,15 +5,12 @@ | |||||
#include "http_response.h" | #include "http_response.h" | ||||
#include "http_request.h" | #include "http_request.h" | ||||
#include "http_cookie.h" | #include "http_cookie.h" | ||||
#include "locale_environment.h" | |||||
#include "locale_charset.h" | |||||
#include "localization.h" | |||||
#include "http_context.h" | #include "http_context.h" | ||||
#include "filters.h" | #include "filters.h" | ||||
#include "aio_timer.h" | #include "aio_timer.h" | ||||
#include "intrusive_ptr.h" | #include "intrusive_ptr.h" | ||||
#include "form.h" | #include "form.h" | ||||
#include "locale_convert.h" | |||||
#include "utf8_iterator.h" | |||||
#include <sstream> | #include <sstream> | ||||
#include <stdexcept> | #include <stdexcept> | ||||
#include <stdlib.h> | #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<<":"; | 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() | void form() | ||||
@@ -247,14 +225,15 @@ public: | |||||
response().out()<< | response().out()<< | ||||
"<html><body>\n"; | "<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()) { | if(f.name.set()) { | ||||
using namespace cppcms::locale; | |||||
std::string name = f.name.value(); | 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()) { | if(f.description.set()) { | ||||
@@ -263,12 +242,11 @@ public: | |||||
std::ofstream tmp("test.txt"); | std::ofstream tmp("test.txt"); | ||||
tmp<<descr; | 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) { | if(ok) { | ||||
@@ -315,19 +293,14 @@ public: | |||||
response().out()<<p->second<<"<br/>\n"; | 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++) { | 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() | response().out() | ||||
<<"<body></html>\n"; | <<"<body></html>\n"; | ||||
@@ -5,7 +5,6 @@ | |||||
#include "http_context.h" | #include "http_context.h" | ||||
#include "http_request.h" | #include "http_request.h" | ||||
#include "http_response.h" | #include "http_response.h" | ||||
#include "locale_environment.h" | |||||
#include "application.h" | #include "application.h" | ||||
#include "applications_pool.h" | #include "applications_pool.h" | ||||
#include "thread_pool.h" | #include "thread_pool.h" | ||||
@@ -19,11 +18,11 @@ namespace cppcms { | |||||
namespace http { | namespace http { | ||||
struct context::data { | struct context::data { | ||||
cppcms::locale::environment locale; | |||||
std::locale locale; | |||||
http::request request; | http::request request; | ||||
std::auto_ptr<http::response> response; | std::auto_ptr<http::response> response; | ||||
data(context &cntx) : | data(context &cntx) : | ||||
locale(cntx.connection().service()), | |||||
locale(cntx.connection().service().locale()), | |||||
request(cntx.connection()) | request(cntx.connection()) | ||||
{ | { | ||||
} | } | ||||
@@ -173,7 +172,7 @@ json::value const &context::settings() | |||||
return conn_->service().settings(); | return conn_->service().settings(); | ||||
} | } | ||||
cppcms::locale::environment &context::locale() | |||||
std::locale context::locale() | |||||
{ | { | ||||
return d->locale; | return d->locale; | ||||
} | } | ||||
@@ -8,12 +8,13 @@ | |||||
#include "callback0.h" | #include "callback0.h" | ||||
#include "callback1.h" | #include "callback1.h" | ||||
#include <locale> | |||||
namespace cppcms { | namespace cppcms { | ||||
class service; | class service; | ||||
class application; | class application; | ||||
namespace json { class value; } | namespace json { class value; } | ||||
namespace locale { class environment; } | |||||
namespace impl { namespace cgi { class connection; } } | namespace impl { namespace cgi { class connection; } } | ||||
namespace http { | namespace http { | ||||
@@ -30,7 +31,7 @@ namespace cppcms { | |||||
http::request &request(); | http::request &request(); | ||||
http::response &response(); | http::response &response(); | ||||
json::value const &settings(); | json::value const &settings(); | ||||
cppcms::locale::environment &locale(); | |||||
std::locale locale(); | |||||
cppcms::service &service(); | cppcms::service &service(); | ||||
void run(); | void run(); | ||||
@@ -9,8 +9,7 @@ | |||||
#include "cppcms_error.h" | #include "cppcms_error.h" | ||||
#include "service.h" | #include "service.h" | ||||
#include "config.h" | #include "config.h" | ||||
#include "locale_environment.h" | |||||
#include "locale_info.h" | |||||
#include "localization.h" | |||||
#include "util.h" | #include "util.h" | ||||
#include <iostream> | #include <iostream> | ||||
@@ -94,7 +93,7 @@ void response::set_content_header(std::string const &content_type) | |||||
set_header("Content-Type",content_type); | set_header("Content-Type",content_type); | ||||
} | } | ||||
else { | 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); | set_header("Content-Type",content_type+"; charset="+charset); | ||||
} | } | ||||
} | } | ||||
@@ -249,7 +248,7 @@ std::ostream &response::out() | |||||
else | else | ||||
stream_=real_sink; | stream_=real_sink; | ||||
stream_->imbue(context_.locale().get()); | |||||
stream_->imbue(context_.locale()); | |||||
return *stream_; | return *stream_; | ||||
} | } | ||||
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 | |||||
@@ -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 |
@@ -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 >=std::use_facet<cppcms::locale::gettext>(*d->locale); | |||||
if(d->domain_name.empty()) | |||||
d->current=>.dictionary(); | |||||
else | |||||
d->current=>.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 | |||||
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 | |||||
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -1,4 +1,5 @@ | |||||
#define CPPCMS_SOURCE | #define CPPCMS_SOURCE | ||||
#include "asio_config.h" | |||||
#include "service.h" | #include "service.h" | ||||
#include "service_impl.h" | #include "service_impl.h" | ||||
#include "applications_pool.h" | #include "applications_pool.h" | ||||
@@ -9,11 +10,10 @@ | |||||
#include "scgi_api.h" | #include "scgi_api.h" | ||||
#include "http_api.h" | #include "http_api.h" | ||||
#include "fastcgi_api.h" | #include "fastcgi_api.h" | ||||
#include "locale_pool.h" | |||||
#include "internal_file_server.h" | #include "internal_file_server.h" | ||||
#include "json.h" | #include "json.h" | ||||
#include "localization.h" | |||||
#include "asio_config.h" | |||||
#ifdef CPPCMS_POSIX | #ifdef CPPCMS_POSIX | ||||
#include <sys/wait.h> | #include <sys/wait.h> | ||||
@@ -24,6 +24,7 @@ | |||||
#include <boost/lexical_cast.hpp> | #include <boost/lexical_cast.hpp> | ||||
#include <boost/regex.hpp> | #include <boost/regex.hpp> | ||||
namespace cppcms { | namespace cppcms { | ||||
service::service(json::value const &v) : | service::service(json::value const &v) : | ||||
@@ -241,7 +242,6 @@ void service::shutdown() | |||||
void service::run() | void service::run() | ||||
{ | { | ||||
locale_pool(); | |||||
start_acceptor(); | start_acceptor(); | ||||
if(settings().get("file_server.enable",false)) | if(settings().get("file_server.enable",false)) | ||||
@@ -426,15 +426,58 @@ void service::stop() | |||||
impl_->get_io_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 { | namespace impl { | ||||
service::service() : | service::service() : | ||||
io_service_(new boost::asio::io_service()), | io_service_(new boost::asio::io_service()), | ||||
@@ -452,7 +495,7 @@ namespace impl { | |||||
// applications pool should be destroyed after | // applications pool should be destroyed after | ||||
// io_service, because soma apps may try unregister themselfs | // io_service, because soma apps may try unregister themselfs | ||||
applications_pool_.reset(); | applications_pool_.reset(); | ||||
locale_pool_.reset(); | |||||
locale_generator_.reset(); | |||||
settings_.reset(); | settings_.reset(); | ||||
} | } | ||||
@@ -5,19 +5,18 @@ | |||||
#include "noncopyable.h" | #include "noncopyable.h" | ||||
#include "hold_ptr.h" | #include "hold_ptr.h" | ||||
#include "callback0.h" | #include "callback0.h" | ||||
#include <locale> | |||||
namespace boost { namespace locale { class generator; }} | |||||
namespace cppcms { | namespace cppcms { | ||||
namespace locale { using namespace boost::locale; } | |||||
namespace impl { | namespace impl { | ||||
class service; | class service; | ||||
} | } | ||||
class applications_pool; | class applications_pool; | ||||
class thread_pool; | class thread_pool; | ||||
namespace locale { | |||||
class pool; | |||||
} | |||||
namespace json { | namespace json { | ||||
class value; | class value; | ||||
} | } | ||||
@@ -35,7 +34,10 @@ namespace cppcms { | |||||
cppcms::applications_pool &applications_pool(); | cppcms::applications_pool &applications_pool(); | ||||
cppcms::thread_pool &thread_pool(); | cppcms::thread_pool &thread_pool(); | ||||
json::value const &settings(); | 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(); | cppcms::impl::service &impl(); | ||||
@@ -3,6 +3,7 @@ | |||||
#include "asio_config.h" | #include "asio_config.h" | ||||
#include "json.h" | #include "json.h" | ||||
#include "localization.h" | |||||
#include <memory> | #include <memory> | ||||
namespace cppcms { | namespace cppcms { | ||||
@@ -33,7 +34,8 @@ namespace impl { | |||||
std::auto_ptr<json::value> settings_; | std::auto_ptr<json::value> settings_; | ||||
std::auto_ptr<applications_pool> applications_pool_; | std::auto_ptr<applications_pool> applications_pool_; | ||||
std::auto_ptr<thread_pool> thread_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 | #ifdef CPPCMS_WIN32 | ||||
typedef SOCKET native_socket_type; | typedef SOCKET native_socket_type; | ||||
@@ -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 |
@@ -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 |