@@ -28,15 +28,25 @@ endif(NOT ICU_UC OR NOT ICU_DATA OR NOT ICU_I18N) | |||
set(HAVE_ICU 1) | |||
find_library(ICONV_LIB iconv) | |||
check_cxx_source_compiles( | |||
"#include <iconv.h> | |||
int main() { iconv_t v=iconv_open((char *)0,(char *)); " | |||
HAVE_ICONV) | |||
if(NOT HAVE_ICONV) | |||
find_library(ICONV_LIB iconv) | |||
if(NOT ICONV_LIB) | |||
message(FATAL " Can't find iconv") | |||
endif(NOT ICONV_LIB) | |||
endif(NOT HAVE_ICONV) | |||
include_directories(${CMAKE_BINARY_DIR}) | |||
include_directories(boost_locale) | |||
include_directories(${Boost_INCLUDE_DIRS}) | |||
Check_type_size(wchar_t SIZEOF_WCHAR_T) | |||
check_type_size(wchar_t SIZEOF_WCHAR_T) | |||
check_cxx_source_compiles( | |||
"int main() { volatile long v;__sync_add_and_fetch(&v,1); }" | |||
@@ -113,12 +123,7 @@ set(CPPCMS_SOURCES | |||
url_dispatcher.cpp | |||
http_cookie.cpp | |||
util.cpp | |||
locale_mo_file.cpp | |||
locale_gettext.cpp | |||
locale_environment.cpp | |||
locale_pool.cpp | |||
base64.cpp | |||
locale_info.cpp | |||
base_view.cpp | |||
internal_file_server.cpp | |||
scgi_api.cpp | |||
@@ -128,15 +133,8 @@ set(CPPCMS_SOURCES | |||
aio_timer.cpp | |||
json.cpp | |||
encoding.cpp | |||
locale_charset.cpp | |||
locale_icu_locale.cpp | |||
locale_convert.cpp | |||
locale_numeric.cpp | |||
locale_collate.cpp | |||
icu_util.cpp | |||
form.cpp | |||
filters.cpp | |||
utf8_iterator.cpp) | |||
filters.cpp) | |||
add_definitions(-DDLL_EXPORT) | |||
@@ -160,8 +158,8 @@ if(ICONV_LIB) | |||
endif(ICONV_LIB) | |||
if(WS2_32 AND WSOCK32) | |||
target_link_libraries(cppcms ws2_32) | |||
target_link_libraries(cppcms wsock32) | |||
target_link_libraries(cppcms ${WS2_32}) | |||
target_link_libraries(cppcms ${WSOCK32}) | |||
endif(WS2_32 AND WSOCK32) | |||
if(LIB_GETHOSTBYNAME) | |||
@@ -5,8 +5,6 @@ | |||
#include "service.h" | |||
#include "cppcms_error.h" | |||
#include "url_dispatcher.h" | |||
#include "locale_environment.h" | |||
#include "locale_gettext.h" | |||
#include "intrusive_ptr.h" | |||
#include "applications_pool.h" | |||
#include "http_response.h" | |||
@@ -100,20 +98,6 @@ intrusive_ptr<http::context> application::release_context() | |||
} | |||
cppcms::locale::environment &application::locale() | |||
{ | |||
return context().locale(); | |||
} | |||
char const *application::gt(char const *s) | |||
{ | |||
return locale().gt(s); | |||
} | |||
char const *application::ngt(char const *s,char const *p,int n) | |||
{ | |||
return locale().ngt(s,p,n); | |||
} | |||
bool application::is_asynchronous() | |||
{ | |||
return pool_id() < 0; | |||
@@ -41,11 +41,6 @@ namespace cppcms { | |||
http::request &request(); | |||
http::response &response(); | |||
url_dispatcher &dispatcher(); | |||
locale::environment &locale(); | |||
char const *gt(char const *s); | |||
char const *ngt(char const *s,char const *p,int n); | |||
void add(application &app); | |||
void add(application &app,std::string regex,int part); | |||
@@ -1,9 +1,6 @@ | |||
#define CPPCMS_SOURCE | |||
#include "base_view.h" | |||
#include "util.h" | |||
#include "locale_gettext.h" | |||
#include "locale_environment.h" | |||
#include "locale_convert.h" | |||
#include "cppcms_error.h" | |||
#include <vector> | |||
@@ -13,7 +10,6 @@ namespace cppcms { | |||
struct base_view::data { | |||
std::ostream *out; | |||
locale::gettext::tr const *tr; | |||
}; | |||
base_view::base_view(std::ostream &out) : | |||
@@ -29,23 +29,14 @@ | |||
// "level" : 1, | |||
// "buffer" : 4096 | |||
}, | |||
"l10n" : { | |||
"defaults" : { | |||
"encoding" : "UTF-8", | |||
"locale" : "en_US", | |||
"std_locale" : [ "ICU" , "C" ] | |||
}, | |||
"localization" : { | |||
"encoding" : "UTF-8", | |||
"messages" : { | |||
"paths" : [ "./transtext/locale" ], | |||
"paths" : [ "../transtext/locale" ], | |||
"domains" : [ "app", "test" ], | |||
"default_domain" : ["test"] | |||
}, | |||
"locales" : [ | |||
"he_IL", | |||
"he_IL@calendar=hebrew", | |||
"en_US", | |||
{ "locale" : "ru_RU" , "std_locale" : "C" } | |||
] | |||
"locales" : [ "en_US", "he_IL", "he_IL@calendar=hebrew" ] | |||
}, | |||
"locale" : { | |||
"locales" : | |||
@@ -1,7 +1,6 @@ | |||
#define CPPCMS_SOURCE | |||
#include "filters.h" | |||
#include "base64.h" | |||
#include "locale_convert.h" | |||
#include "util.h" | |||
#include <iostream> | |||
@@ -79,7 +78,9 @@ namespace cppcms { namespace filters { | |||
to_upper const &to_upper::operator=(to_upper const &other){ obj_ = other.obj_; return *this; } | |||
void to_upper::operator()(std::ostream &out) const | |||
{ | |||
out << std::use_facet<locale::convert>(out.getloc()).to_upper(obj_.get(out)); | |||
std::string tmp =obj_.get(out) ; | |||
std::locale loc = out.getloc(); | |||
out << ::cppcms::locale::to_upper( tmp,loc); | |||
} | |||
struct to_lower::data {}; | |||
@@ -90,7 +91,7 @@ namespace cppcms { namespace filters { | |||
to_lower const &to_lower::operator=(to_lower const &other){ obj_ = other.obj_; return *this; } | |||
void to_lower::operator()(std::ostream &out) const | |||
{ | |||
out << std::use_facet<locale::convert>(out.getloc()).to_lower(obj_.get(out)); | |||
out << locale::to_lower(obj_.get(out),out.getloc()); | |||
} | |||
struct to_title::data {}; | |||
@@ -101,7 +102,7 @@ namespace cppcms { namespace filters { | |||
to_title const &to_title::operator=(to_title const &other){ obj_ = other.obj_; return *this; } | |||
void to_title::operator()(std::ostream &out) const | |||
{ | |||
out << std::use_facet<locale::convert>(out.getloc()).to_title(obj_.get(out)); | |||
out << locale::to_title(obj_.get(out),out.getloc()); | |||
} | |||
struct escape::data {}; | |||
@@ -156,151 +157,43 @@ namespace cppcms { namespace filters { | |||
os<<buf; | |||
} | |||
struct strftime::data {}; | |||
strftime::strftime() {} | |||
strftime::~strftime() {} | |||
strftime::strftime(strftime const &other) : format_(other.format_),t_(other.t_) {} | |||
strftime::strftime(streamable const &obj,std::tm const &t) : format_(obj),t_(&t) {} | |||
strftime const &strftime::operator=(strftime const &other) | |||
{ | |||
format_ = other.format_; | |||
t_=other.t_; | |||
return *this; | |||
} | |||
void strftime::operator()(std::ostream &out) const | |||
{ | |||
std::string fmt=format_.get(out); | |||
std::use_facet<std::time_put<char> >(out.getloc()).put(out,out,' ',t_,fmt.data(),fmt.data()+fmt.size()); | |||
} | |||
void format::init(streamable const &f) | |||
{ | |||
format_=f; | |||
size_ = 0; | |||
} | |||
streamable const *format::at(size_t n) const | |||
{ | |||
n--; | |||
if(n >= size_ || n < 0) | |||
return 0; | |||
const size_t objects_size = sizeof(objects_) / sizeof(objects_[0]); | |||
if(n < objects_size) | |||
return &objects_[n]; | |||
return &vobjects_[n - objects_size]; | |||
} | |||
format &format::add(streamable const &obj) | |||
{ | |||
if(size_ >= sizeof(objects_) / sizeof(objects_[0])) | |||
vobjects_.push_back(obj); | |||
else | |||
objects_[size_] = obj; | |||
size_ ++; | |||
return *this; | |||
} | |||
void format::write(std::ostream &output) const | |||
{ | |||
int pos = 0; | |||
std::string const fmt=format_.get(output); | |||
for(std::string::const_iterator p=fmt.begin(),e=fmt.end();p!=e;) { | |||
char c=*p++; | |||
if(c=='%') { | |||
format_one(output,p,e,pos); | |||
} | |||
else | |||
output.put(c); | |||
} | |||
} | |||
void format::format_one(std::ostream &out,std::string::const_iterator &p,std::string::const_iterator e,int &pos) const | |||
{ | |||
if(p==e) | |||
return; | |||
if(*p == '%') { | |||
++p; | |||
out << '%'; | |||
return; | |||
} | |||
pos++; | |||
int the_pos = pos; | |||
if('1' <= *p && *p<='9') { | |||
int n=0; | |||
while(p!=e && '0' <= *p && *p<='9') { | |||
n=n*10 + (*p - '0'); | |||
++p; | |||
} | |||
if(p==e) | |||
return; | |||
if(*p=='%') { | |||
++p; | |||
the_pos = n; | |||
streamable const *obj=at(the_pos); | |||
if(obj) { | |||
out<<*obj; | |||
} | |||
return; | |||
} | |||
return; | |||
} | |||
} | |||
std::string format::str(std::locale const &loc) const | |||
{ | |||
std::ostringstream oss; | |||
oss.imbue(loc); | |||
write(oss); | |||
return oss.str(); | |||
} | |||
struct date::data {}; | |||
struct time::data {}; | |||
struct datetime::data {}; | |||
date::date() : t_(0) {} | |||
datetime::datetime() : t_(0){} | |||
time::time() : t_(0) {} | |||
date::date() : time_(0) {} | |||
datetime::datetime() : time_(0){} | |||
time::time() : time_(0) {} | |||
date::~date() {} | |||
datetime::~datetime() {} | |||
time::~time() {} | |||
date::date(date const &other) : t_(other.t_) {} | |||
time::time(time const &other) : t_(other.t_) {} | |||
datetime::datetime(datetime const &other) : t_(other.t_) {} | |||
date::date(date const &other) : time_(other.time_) {} | |||
time::time(time const &other) : time_(other.time_) {} | |||
datetime::datetime(datetime const &other) : time_(other.time_) {} | |||
date const &date::operator=(date const &other) { t_=other.t_; return *this; } | |||
time const &time::operator=(time const &other) { t_=other.t_; return *this; } | |||
datetime const &datetime::operator=(datetime const &other) { t_=other.t_; return *this; } | |||
date const &date::operator=(date const &other) { time_=other.time_; return *this; } | |||
time const &time::operator=(time const &other) { time_=other.time_; return *this; } | |||
datetime const &datetime::operator=(datetime const &other) { time_=other.time_; return *this; } | |||
date::date(std::tm const &t) : t_(&t) {} | |||
time::time(std::tm const &t) : t_(&t) {} | |||
datetime::datetime(std::tm const &t) : t_(&t) {} | |||
date::date(double t) : time_(t) {} | |||
time::time(double t) : time_(t) {} | |||
datetime::datetime(double t) : time_(t) {} | |||
void date::operator()(std::ostream &out) const | |||
{ | |||
if(out.getloc().name()=="*") | |||
out<<strftime("%Y-%m-%d",*t_); | |||
else | |||
out<<strftime("%x",*t_); | |||
out << format("{1,date}") % time_; | |||
} | |||
void time::operator()(std::ostream &out) const | |||
{ | |||
if(out.getloc().name()=="*") | |||
out<<strftime("%H:%M:%S",*t_); | |||
else | |||
out<<strftime("%X",*t_); | |||
out << format("{1,time}") % time_; | |||
} | |||
void datetime::operator()(std::ostream &out) const | |||
{ | |||
if(out.getloc().name()=="*") | |||
out<<strftime("%Y-%m-%d %H:%M:%S",*t_); | |||
else | |||
out<<strftime("%c",*t_); | |||
out << format("{1,datetime}") % time_; | |||
} | |||
@@ -8,8 +8,8 @@ | |||
#include <iostream> | |||
#include "defs.h" | |||
#include "copy_ptr.h" | |||
#include "localization.h" | |||
#include "locale_gettext.h" | |||
namespace cppcms { | |||
namespace filters { | |||
@@ -287,35 +287,7 @@ namespace cppcms { | |||
return out; | |||
} | |||
/// | |||
/// \brief Output filter strftime | |||
/// | |||
/// Format time according to locale using time_put<char> facet. (has similar | |||
/// parameters to C strftime | |||
/// | |||
class CPPCMS_API strftime { | |||
public: | |||
strftime(); | |||
~strftime(); | |||
strftime(strftime const &); | |||
strftime const &operator=(strftime const &other); | |||
void operator()(std::ostream &out) const; | |||
strftime(streamable const &obj,std::tm const &t); | |||
private: | |||
streamable format_; | |||
std::tm const *t_; | |||
struct data; | |||
util::copy_ptr<data> d; | |||
}; | |||
inline std::ostream &operator<<(std::ostream &out,strftime const &obj) | |||
{ | |||
obj(out); | |||
return out; | |||
} | |||
class CPPCMS_API date { | |||
public: | |||
@@ -324,11 +296,11 @@ namespace cppcms { | |||
date const &operator=(date const &other); | |||
~date(); | |||
date(std::tm const &t); | |||
date(double time); | |||
void operator()(std::ostream &out) const; | |||
private: | |||
struct data; | |||
std::tm const *t_; | |||
double time_; | |||
util::copy_ptr<data> d; | |||
}; | |||
@@ -345,11 +317,11 @@ namespace cppcms { | |||
time const &operator=(time const &other); | |||
~time(); | |||
time(std::tm const &t); | |||
time(double time); | |||
void operator()(std::ostream &out) const; | |||
private: | |||
struct data; | |||
std::tm const *t_; | |||
double time_; | |||
util::copy_ptr<data> d; | |||
}; | |||
@@ -365,11 +337,11 @@ namespace cppcms { | |||
datetime const &operator=(datetime const &other); | |||
~datetime(); | |||
datetime(std::tm const &t); | |||
datetime(double t); | |||
void operator()(std::ostream &out) const; | |||
private: | |||
struct data; | |||
std::tm const *t_; | |||
double time_; | |||
util::copy_ptr<data> d; | |||
}; | |||
@@ -378,339 +350,14 @@ namespace cppcms { | |||
obj(out); | |||
return out; | |||
} | |||
class gt { | |||
public: | |||
gt(char const *msg) : | |||
domain_(0), | |||
msg_(msg) | |||
{ | |||
} | |||
gt(char const *domain,char const *msg) : | |||
domain_(domain), | |||
msg_(msg) | |||
{ | |||
} | |||
void operator()(std::ostream &out) const | |||
{ | |||
locale::gettext const &trans = std::use_facet<locale::gettext>(out.getloc()); | |||
if(domain_) | |||
out << trans.dictionary(domain_).gettext(msg_); | |||
else | |||
out << trans.dictionary().gettext(msg_); | |||
} | |||
private: | |||
char const *domain_; | |||
char const *msg_; | |||
}; | |||
CPPCMS_STREAMED(gt) | |||
class ngt { | |||
public: | |||
ngt(char const *s,char const *p,int n) : | |||
domain_(0), | |||
s_(s), | |||
p_(p), | |||
n_(n) | |||
{ | |||
} | |||
ngt(char const *domain,char const *s,char const *p,int n) : | |||
domain_(domain), | |||
s_(s), | |||
p_(p), | |||
n_(n) | |||
{ | |||
} | |||
void operator()(std::ostream &out) const | |||
{ | |||
locale::gettext const &trans = std::use_facet<locale::gettext>(out.getloc()); | |||
if(domain_) | |||
out << trans.dictionary(domain_).ngettext(s_,p_,n_); | |||
else | |||
out << trans.dictionary().ngettext(s_,p_,n_); | |||
} | |||
private: | |||
char const *domain_; | |||
char const *s_,*p_; | |||
int n_; | |||
}; | |||
CPPCMS_STREAMED(ngt) | |||
class CPPCMS_API format { | |||
public: | |||
format(streamable const &f) | |||
{ | |||
init(f); | |||
} | |||
#ifdef CPPCMS_HAVE_VARIADIC_TEMPLATES | |||
template<typename... Args> | |||
format(streamable const &f,Args... args) | |||
{ | |||
init(f); | |||
add_args(args...); | |||
} | |||
private: | |||
void add_args() | |||
{ | |||
} | |||
template<typename T,typename... Args> | |||
void add_args(T const &v,Args... args) | |||
{ | |||
add(v); | |||
add_args(args...); | |||
} | |||
public: | |||
#else | |||
template<typename T1> | |||
format( streamable const &f, | |||
T1 const &v1) | |||
{ | |||
init(f); | |||
add(v1); | |||
} | |||
template< typename T1, | |||
typename T2> | |||
format( streamable const &f, | |||
T1 const &v1, | |||
T2 const &v2) | |||
{ | |||
init(f); | |||
add(v1); | |||
add(v2); | |||
} | |||
template< typename T1, | |||
typename T2, | |||
typename T3> | |||
format( streamable const &f, | |||
T1 const &v1, | |||
T2 const &v2, | |||
T3 const &v3) | |||
{ | |||
init(f); | |||
add(v1); | |||
add(v2); | |||
add(v3); | |||
} | |||
template< typename T1, | |||
typename T2, | |||
typename T3, | |||
typename T4> | |||
format( streamable const &f, | |||
T1 const &v1, | |||
T2 const &v2, | |||
T3 const &v3, | |||
T4 const &v4) | |||
{ | |||
init(f); | |||
add(v1); | |||
add(v2); | |||
add(v3); | |||
add(v4); | |||
} | |||
template< typename T1, | |||
typename T2, | |||
typename T3, | |||
typename T4, | |||
typename T5> | |||
format( streamable const &f, | |||
T1 const &v1, | |||
T2 const &v2, | |||
T3 const &v3, | |||
T4 const &v4, | |||
T5 const &v5) | |||
{ | |||
init(f); | |||
add(v1); | |||
add(v2); | |||
add(v3); | |||
add(v4); | |||
add(v5); | |||
} | |||
template< typename T1, | |||
typename T2, | |||
typename T3, | |||
typename T4, | |||
typename T5, | |||
typename T6> | |||
format( streamable const &f, | |||
T1 const &v1, | |||
T2 const &v2, | |||
T3 const &v3, | |||
T4 const &v4, | |||
T5 const &v5, | |||
T6 const &v6) | |||
{ | |||
init(f); | |||
add(v1); | |||
add(v2); | |||
add(v4); | |||
add(v5); | |||
add(v6); | |||
} | |||
template< typename T1, | |||
typename T2, | |||
typename T3, | |||
typename T4, | |||
typename T5, | |||
typename T6, | |||
typename T7> | |||
format( streamable const &f, | |||
T1 const &v1, | |||
T2 const &v2, | |||
T3 const &v3, | |||
T4 const &v4, | |||
T5 const &v5, | |||
T6 const &v6, | |||
T7 const &v7) | |||
{ | |||
init(f); | |||
add(v1); | |||
add(v2); | |||
add(v3); | |||
add(v4); | |||
add(v5); | |||
add(v6); | |||
add(v7); | |||
} | |||
template< typename T1, | |||
typename T2, | |||
typename T3, | |||
typename T4, | |||
typename T5, | |||
typename T6, | |||
typename T7, | |||
typename T8> | |||
format( streamable const &f, | |||
T1 const &v1, | |||
T2 const &v2, | |||
T3 const &v3, | |||
T4 const &v4, | |||
T5 const &v5, | |||
T6 const &v6, | |||
T7 const &v7, | |||
T8 const &v8) | |||
{ | |||
init(f); | |||
add(v1); | |||
add(v2); | |||
add(v3); | |||
add(v4); | |||
add(v5); | |||
add(v6); | |||
add(v7); | |||
add(v8); | |||
} | |||
template< typename T1, | |||
typename T2, | |||
typename T3, | |||
typename T4, | |||
typename T5, | |||
typename T6, | |||
typename T7, | |||
typename T8, | |||
typename T9> | |||
format( streamable const &f, | |||
T1 const &v1, | |||
T2 const &v2, | |||
T3 const &v3, | |||
T4 const &v4, | |||
T5 const &v5, | |||
T6 const &v6, | |||
T7 const &v7, | |||
T8 const &v8, | |||
T9 const &v9) | |||
{ | |||
init(f); | |||
add(v1); | |||
add(v2); | |||
add(v3); | |||
add(v4); | |||
add(v5); | |||
add(v6); | |||
add(v7); | |||
add(v8); | |||
add(v9); | |||
} | |||
template< typename T1, | |||
typename T2, | |||
typename T3, | |||
typename T4, | |||
typename T5, | |||
typename T6, | |||
typename T7, | |||
typename T8, | |||
typename T9, | |||
typename T10> | |||
format( streamable const &f, | |||
T1 const &v1, | |||
T2 const &v2, | |||
T3 const &v3, | |||
T4 const &v4, | |||
T5 const &v5, | |||
T6 const &v6, | |||
T7 const &v7, | |||
T8 const &v8, | |||
T9 const &v9, | |||
T10 const &v10) | |||
{ | |||
init(f); | |||
add(v1); | |||
add(v2); | |||
add(v3); | |||
add(v4); | |||
add(v5); | |||
add(v6); | |||
add(v7); | |||
add(v8); | |||
add(v9); | |||
add(v10); | |||
} | |||
#endif | |||
template<typename Streamable> | |||
format &operator % (Streamable const &object) | |||
{ | |||
return add(streamable(object)); | |||
} | |||
void operator()(std::ostream &output) const | |||
{ | |||
write(output); | |||
} | |||
std::string str(std::locale const &locale) const; | |||
std::string str() const | |||
{ | |||
return str(std::locale::classic()); | |||
} | |||
format &add(streamable const &obj); | |||
private: | |||
void write(std::ostream &output) const; | |||
void format_one(std::ostream &out,std::string::const_iterator &p,std::string::const_iterator e,int &pos) const; | |||
void init(streamable const &f); | |||
streamable const *at(size_t n) const; | |||
streamable format_; | |||
std::vector<streamable> vobjects_; | |||
streamable objects_[10]; | |||
size_t size_; | |||
}; | |||
CPPCMS_STREAMED(format) | |||
using locale::translate; | |||
using locale::format; | |||
} | |||
/////////////////////////////// | |||
using filters::format; | |||
using filters::ngt; | |||
using filters::gt; | |||
} | |||
#undef CPPCMS_STREAMED | |||
@@ -3,8 +3,6 @@ | |||
#include <iostream> | |||
#include <stack> | |||
#include <boost/format.hpp> | |||
#include "locale_charset.h" | |||
#include "locale_environment.h" | |||
namespace cppcms { | |||
@@ -380,12 +378,14 @@ void base_text::value(std::string v) | |||
std::string base_text::value(std::locale const &v) | |||
{ | |||
return std::use_facet<locale::charset>(v).to_utf8(value_); | |||
//return std::use_facet<locale::charset>(v).to_utf8(value_); | |||
return value_; | |||
} | |||
void base_text::value(std::string v,std::locale const &l) | |||
{ | |||
value(std::use_facet<locale::charset>(l).from_utf8(v)); | |||
//value(std::use_facet<locale::charset>(l).from_utf8(v)); | |||
value(v); | |||
} | |||
void base_text::non_empty() | |||
@@ -432,9 +432,9 @@ void base_text::load(http::context &context) | |||
set(true); | |||
if(validate_charset_) { | |||
code_points_ = 0; | |||
locale::charset const &charset=std::use_facet<locale::charset>(context.locale().get()); | |||
/* locale::charset const &charset=std::use_facet<locale::charset>(context.locale().get()); | |||
if(!charset.validate(value_,code_points_)) | |||
valid(false); | |||
valid(false);*/ | |||
} | |||
else { | |||
code_points_=value_.size(); | |||
@@ -14,7 +14,6 @@ | |||
#include "http_context.h" | |||
#include "http_request.h" | |||
#include "http_response.h" | |||
#include "locale_environment.h" | |||
#include "copy_ptr.h" | |||
#include "cppcms_error.h" | |||
#include "util.h" | |||
@@ -897,7 +896,7 @@ namespace cppcms { | |||
return; | |||
std::istringstream ss(loaded_string_); | |||
ss.imbue(context.locale().get()); | |||
ss.imbue(context.locale()); | |||
ss>>value_; | |||
if(ss.fail() || !ss.eof()) | |||
valid(false); | |||
@@ -5,15 +5,12 @@ | |||
#include "http_response.h" | |||
#include "http_request.h" | |||
#include "http_cookie.h" | |||
#include "locale_environment.h" | |||
#include "locale_charset.h" | |||
#include "localization.h" | |||
#include "http_context.h" | |||
#include "filters.h" | |||
#include "aio_timer.h" | |||
#include "intrusive_ptr.h" | |||
#include "form.h" | |||
#include "locale_convert.h" | |||
#include "utf8_iterator.h" | |||
#include <sstream> | |||
#include <stdexcept> | |||
#include <stdlib.h> | |||
@@ -203,35 +200,16 @@ public: | |||
{ | |||
} | |||
template<typename iterator> | |||
void devide(std::string const &str,char const *name) | |||
void devide(cppcms::locale::boundary::boundary_type type,std::string const &str,char const *name) | |||
{ | |||
response().out()<<name<<":"; | |||
iterator it(str,locale().get()); | |||
iterator prev = it; | |||
++it; | |||
response().out()<<std::string(*prev,*it); | |||
while(*it!=str.end()) { | |||
prev=it; | |||
++it; | |||
response().out()<<" | "<<std::string(*prev,*it); | |||
} | |||
response().out()<<"<br>\n"<<name<<" reversed:"; | |||
it=str.end(); | |||
std::string::const_iterator p=*it; | |||
--it; | |||
response().out()<<std::string(*it,p); | |||
while(*it!=str.begin()) { | |||
p=*it; | |||
--it; | |||
response().out()<<" | "<<std::string(*it,p); | |||
using namespace cppcms::locale; | |||
boundary::index_type indx = boundary::map(type,str,context().locale()); | |||
for(unsigned i=0;i<indx.size()-1;i++) { | |||
response().out()<<"|"<<str.substr(indx[i].offset,indx[i+1].offset-indx[i].offset); | |||
} | |||
response().out()<<"<br>\nRandom "<<name<<":"; | |||
it = str.begin() + rand() % str.size(); | |||
prev=it; | |||
it+=5; | |||
prev-=5; | |||
response().out()<<std::string(*prev,*it)<<"<br>\n"; | |||
response().out()<<"|<br>\n"; | |||
} | |||
void form() | |||
@@ -247,14 +225,15 @@ public: | |||
response().out()<< | |||
"<html><body>\n"; | |||
cppcms::locale::convert const &cv=std::use_facet<cppcms::locale::convert>(locale().get()); | |||
std::locale loc = context().locale(); | |||
if(f.name.set()) { | |||
using namespace cppcms::locale; | |||
std::string name = f.name.value(); | |||
response().out() <<"Upper: "<<cv.to_upper(name)<<"<br>"<<std::endl; | |||
response().out() <<"Lower: "<<cv.to_lower(name)<<"<br>"<<std::endl; | |||
response().out() <<"Title: "<<cv.to_title(name)<<"<br>"<<std::endl; | |||
response().out() <<"Normal: "<<cv.to_normal(name)<<"<br>"<<std::endl; | |||
response().out() <<"Upper: "<<to_upper(name,loc)<<"<br>"<<std::endl; | |||
response().out() <<"Lower: "<<to_lower(name,loc)<<"<br>"<<std::endl; | |||
response().out() <<"Title: "<<to_title(name,loc)<<"<br>"<<std::endl; | |||
response().out() <<"Fold Case: "<<fold_case(name,loc)<<"<br>"<<std::endl; | |||
} | |||
if(f.description.set()) { | |||
@@ -263,12 +242,11 @@ public: | |||
std::ofstream tmp("test.txt"); | |||
tmp<<descr; | |||
} | |||
devide<cppcms::utf8::const_code_point_iterator>(descr,"code"); | |||
devide<cppcms::utf8::const_character_iterator>(descr,"char"); | |||
devide<cppcms::utf8::const_word_iterator>(descr,"word"); | |||
devide<cppcms::utf8::const_sentence_iterator>(descr,"sentence"); | |||
devide<cppcms::utf8::const_line_iterator>(descr,"line"); | |||
using namespace cppcms::locale; | |||
devide(boundary::character,descr,"code"); | |||
devide(boundary::word,descr,"word"); | |||
devide(boundary::sentence,descr,"sentence"); | |||
devide(boundary::line,descr,"line"); | |||
} | |||
if(ok) { | |||
@@ -315,19 +293,14 @@ public: | |||
response().out()<<p->second<<"<br/>\n"; | |||
} | |||
time_t t=::time(NULL); | |||
std::tm tt; | |||
localtime_r(&t,&tt); | |||
response().out() << filters::date(tt) <<std::endl; | |||
response().out() << filters::date(time(0)) <<std::endl; | |||
response().out() << filters::escape(gt("hello\n")) << "<br>"; | |||
response().out() << filters::escape(locale::translate("hello\n")) << "<br>"; | |||
for(int i=0;i<30;i++) { | |||
response().out() << format("To be or not to be %1%\n<br>",10); | |||
response().out() << locale::format("To be or not to be {1}\n<br>") % 10; | |||
response().out() << format(ngt("passed one day","passed %1% days",i),i) << "<br>\n"; | |||
//cppcms::util::format(response().out(),ngt("passed one day","passed %1% days",i),i) << "<br>"; | |||
response().out() << locale::format(locale::translate("passed one day","passed {1} days",i)) % i << "<br>\n"; | |||
} | |||
response().out() | |||
<<"<body></html>\n"; | |||
@@ -5,7 +5,6 @@ | |||
#include "http_context.h" | |||
#include "http_request.h" | |||
#include "http_response.h" | |||
#include "locale_environment.h" | |||
#include "application.h" | |||
#include "applications_pool.h" | |||
#include "thread_pool.h" | |||
@@ -19,11 +18,11 @@ namespace cppcms { | |||
namespace http { | |||
struct context::data { | |||
cppcms::locale::environment locale; | |||
std::locale locale; | |||
http::request request; | |||
std::auto_ptr<http::response> response; | |||
data(context &cntx) : | |||
locale(cntx.connection().service()), | |||
locale(cntx.connection().service().locale()), | |||
request(cntx.connection()) | |||
{ | |||
} | |||
@@ -173,7 +172,7 @@ json::value const &context::settings() | |||
return conn_->service().settings(); | |||
} | |||
cppcms::locale::environment &context::locale() | |||
std::locale context::locale() | |||
{ | |||
return d->locale; | |||
} | |||
@@ -8,12 +8,13 @@ | |||
#include "callback0.h" | |||
#include "callback1.h" | |||
#include <locale> | |||
namespace cppcms { | |||
class service; | |||
class application; | |||
namespace json { class value; } | |||
namespace locale { class environment; } | |||
namespace impl { namespace cgi { class connection; } } | |||
namespace http { | |||
@@ -30,7 +31,7 @@ namespace cppcms { | |||
http::request &request(); | |||
http::response &response(); | |||
json::value const &settings(); | |||
cppcms::locale::environment &locale(); | |||
std::locale locale(); | |||
cppcms::service &service(); | |||
void run(); | |||
@@ -9,8 +9,7 @@ | |||
#include "cppcms_error.h" | |||
#include "service.h" | |||
#include "config.h" | |||
#include "locale_environment.h" | |||
#include "locale_info.h" | |||
#include "localization.h" | |||
#include "util.h" | |||
#include <iostream> | |||
@@ -94,7 +93,7 @@ void response::set_content_header(std::string const &content_type) | |||
set_header("Content-Type",content_type); | |||
} | |||
else { | |||
std::string charset=std::use_facet<locale::info>(context_.locale().get()).encoding(); | |||
std::string charset=std::use_facet<locale::info>(context_.locale()).encoding(); | |||
set_header("Content-Type",content_type+"; charset="+charset); | |||
} | |||
} | |||
@@ -249,7 +248,7 @@ std::ostream &response::out() | |||
else | |||
stream_=real_sink; | |||
stream_->imbue(context_.locale().get()); | |||
stream_->imbue(context_.locale()); | |||
return *stream_; | |||
} | |||
@@ -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 | |||
#include "asio_config.h" | |||
#include "service.h" | |||
#include "service_impl.h" | |||
#include "applications_pool.h" | |||
@@ -9,11 +10,10 @@ | |||
#include "scgi_api.h" | |||
#include "http_api.h" | |||
#include "fastcgi_api.h" | |||
#include "locale_pool.h" | |||
#include "internal_file_server.h" | |||
#include "json.h" | |||
#include "localization.h" | |||
#include "asio_config.h" | |||
#ifdef CPPCMS_POSIX | |||
#include <sys/wait.h> | |||
@@ -24,6 +24,7 @@ | |||
#include <boost/lexical_cast.hpp> | |||
#include <boost/regex.hpp> | |||
namespace cppcms { | |||
service::service(json::value const &v) : | |||
@@ -241,7 +242,6 @@ void service::shutdown() | |||
void service::run() | |||
{ | |||
locale_pool(); | |||
start_acceptor(); | |||
if(settings().get("file_server.enable",false)) | |||
@@ -426,15 +426,58 @@ void service::stop() | |||
impl_->get_io_service().stop(); | |||
} | |||
locale::pool const &service::locale_pool() | |||
locale::generator const &service::generator() | |||
{ | |||
if(!impl_->locale_pool_.get()) { | |||
impl_->locale_pool_.reset(new locale::pool(settings())); | |||
if(impl_->locale_generator_.get()) | |||
return *impl_->locale_generator_.get(); | |||
typedef std::vector<std::string> vstr_type; | |||
impl_->locale_generator_.reset(new locale::generator()); | |||
locale::generator &gen= *impl_->locale_generator_; | |||
gen.characters(locale::char_facet); | |||
std::string enc = settings().get("localization.encoding",""); | |||
if(!enc.empty()) | |||
gen.octet_encoding(enc); | |||
vstr_type paths= settings().get("localization.messages.path",vstr_type()); | |||
vstr_type domains = settings().get("localization.messages.domains",vstr_type()); | |||
if(!paths.empty() && !domains.empty()) { | |||
unsigned i; | |||
for(i=0;i<paths.size();i++) | |||
gen.add_messages_path(paths[i]); | |||
for(i=0;i<domains.size();i++) | |||
gen.add_messages_domain(domains[i]); | |||
} | |||
vstr_type locales = settings().get("localization.messages.locales",vstr_type()); | |||
if(locales.empty()) { | |||
gen.preload(""); | |||
impl_->default_locale_=gen(""); | |||
} | |||
else { | |||
for(unsigned i=0;i<locales.size();i++) | |||
gen.preload(locales[i]); | |||
impl_->default_locale_=gen(locales[0]); | |||
} | |||
return *impl_->locale_pool_; | |||
return *impl_->locale_generator_.get(); | |||
} | |||
std::locale service::locale() | |||
{ | |||
generator(); | |||
return impl_->default_locale_; | |||
} | |||
std::locale service::locale(std::string const &name) | |||
{ | |||
return generator().get(name); | |||
} | |||
namespace impl { | |||
service::service() : | |||
io_service_(new boost::asio::io_service()), | |||
@@ -452,7 +495,7 @@ namespace impl { | |||
// applications pool should be destroyed after | |||
// io_service, because soma apps may try unregister themselfs | |||
applications_pool_.reset(); | |||
locale_pool_.reset(); | |||
locale_generator_.reset(); | |||
settings_.reset(); | |||
} | |||
@@ -5,19 +5,18 @@ | |||
#include "noncopyable.h" | |||
#include "hold_ptr.h" | |||
#include "callback0.h" | |||
#include <locale> | |||
namespace boost { namespace locale { class generator; }} | |||
namespace cppcms { | |||
namespace locale { using namespace boost::locale; } | |||
namespace impl { | |||
class service; | |||
} | |||
class applications_pool; | |||
class thread_pool; | |||
namespace locale { | |||
class pool; | |||
} | |||
namespace json { | |||
class value; | |||
} | |||
@@ -35,7 +34,10 @@ namespace cppcms { | |||
cppcms::applications_pool &applications_pool(); | |||
cppcms::thread_pool &thread_pool(); | |||
json::value const &settings(); | |||
cppcms::locale::pool const &locale_pool(); | |||
locale::generator const &generator(); | |||
std::locale locale(); | |||
std::locale locale(std::string const &name); | |||
cppcms::impl::service &impl(); | |||
@@ -3,6 +3,7 @@ | |||
#include "asio_config.h" | |||
#include "json.h" | |||
#include "localization.h" | |||
#include <memory> | |||
namespace cppcms { | |||
@@ -33,7 +34,8 @@ namespace impl { | |||
std::auto_ptr<json::value> settings_; | |||
std::auto_ptr<applications_pool> applications_pool_; | |||
std::auto_ptr<thread_pool> thread_pool_; | |||
std::auto_ptr<locale::pool> locale_pool_; | |||
std::auto_ptr<locale::generator> locale_generator_; | |||
std::locale default_locale_; | |||
#ifdef CPPCMS_WIN32 | |||
typedef SOCKET native_socket_type; | |||
@@ -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 |