1 //
2 // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See
5 // accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 //
8 #define BOOST_LOCALE_SOURCE
9 #include <locale>
10 #include <string>
11 #include <ios>
12 #include <boost/locale/formatting.hpp>
13 #include <boost/locale/generator.hpp>
14 #include <boost/locale/encoding.hpp>
15 #include <boost/shared_ptr.hpp>
16 #include <sstream>
17 #include <stdlib.h>
18 #include <time.h>
19 #include <string.h>
20 #include <wctype.h>
21 #include <ctype.h>
22 #include <langinfo.h>
23 #include <monetary.h>
24 #include <errno.h>
25 #include "../util/numeric.hpp"
26 #include "all_generator.hpp"
27
28
29 #if defined(__linux) || defined(__APPLE__)
30 #define BOOST_LOCALE_HAVE_WCSFTIME_L
31 #endif
32
33 namespace boost {
34 namespace locale {
35 namespace impl_posix {
36
37 template<typename CharType>
38 class num_format : public util::base_num_format<CharType>
39 {
40 public:
41 typedef typename std::num_put<CharType>::iter_type iter_type;
42 typedef std::basic_string<CharType> string_type;
43 typedef CharType char_type;
44
num_format(boost::shared_ptr<locale_t> lc,size_t refs=0)45 num_format(boost::shared_ptr<locale_t> lc,size_t refs = 0) :
46 util::base_num_format<CharType>(refs),
47 lc_(lc)
48 {
49 }
50 protected:
51
do_format_currency(bool intl,iter_type out,std::ios_base &,char_type,long double val) const52 virtual iter_type do_format_currency(bool intl,iter_type out,std::ios_base &/*ios*/,char_type /*fill*/,long double val) const
53 {
54 char buf[4]={};
55 char const *format = intl ? "%i" : "%n";
56 errno=0;
57 ssize_t n = strfmon_l(buf,sizeof(buf),*lc_,format,static_cast<double>(val));
58 if(n >= 0)
59 return write_it(out,buf,n);
60
61 for(std::vector<char> tmp(sizeof(buf)*2);tmp.size() <= 4098;tmp.resize(tmp.size()*2)) {
62 n = strfmon_l(&tmp.front(),tmp.size(),*lc_,format,static_cast<double>(val));
63 if(n >= 0)
64 return write_it(out,&tmp.front(),n);
65 }
66 return out;
67 }
68
write_it(std::ostreambuf_iterator<char> out,char const * ptr,size_t n) const69 std::ostreambuf_iterator<char> write_it(std::ostreambuf_iterator<char> out,char const *ptr,size_t n) const
70 {
71 for(size_t i=0;i<n;i++)
72 *out++ = *ptr++;
73 return out;
74 }
75
write_it(std::ostreambuf_iterator<wchar_t> out,char const * ptr,size_t n) const76 std::ostreambuf_iterator<wchar_t> write_it(std::ostreambuf_iterator<wchar_t> out,char const *ptr,size_t n) const
77 {
78 std::wstring tmp = conv::to_utf<wchar_t>(ptr,ptr+n,nl_langinfo_l(CODESET,*lc_));
79 for(size_t i=0;i<tmp.size();i++)
80 *out++ = tmp[i];
81 return out;
82 }
83 private:
84
85 boost::shared_ptr<locale_t> lc_;
86
87 }; /// num_format
88
89
90 template<typename CharType>
91 struct ftime_traits;
92
93 template<>
94 struct ftime_traits<char> {
ftimeboost::locale::impl_posix::ftime_traits95 static std::string ftime(char const *format,const struct tm *t,locale_t lc)
96 {
97 char buf[16];
98 size_t n=strftime_l(buf,sizeof(buf),format,t,lc);
99 if(n == 0) {
100 // should be big enough
101 //
102 // Note standard specifies that in case of the error
103 // the function returns 0, however 0 may be actually
104 // valid output value of for example empty format or an
105 // output of %p in some locales
106 //
107 // Thus we try to guess that 1024 would be enough.
108 std::vector<char> v(1024);
109 n = strftime_l(&v.front(),1024,format,t,lc);
110 return std::string(&v.front(),n);
111 }
112 return std::string(buf,n);
113 }
114 };
115
116 template<>
117 struct ftime_traits<wchar_t> {
ftimeboost::locale::impl_posix::ftime_traits118 static std::wstring ftime(wchar_t const *format,const struct tm *t,locale_t lc)
119 {
120 #ifdef HAVE_WCSFTIME_L
121 wchar_t buf[16];
122 size_t n=wcsftime_l(buf,sizeof(buf)/sizeof(buf[0]),format,t,lc);
123 if(n == 0) {
124 // should be big enough
125 //
126 // Note standard specifies that in case of the error
127 // the function returns 0, however 0 may be actually
128 // valid output value of for example empty format or an
129 // output of %p in some locales
130 //
131 // Thus we try to guess that 1024 would be enough.
132 std::vector<wchar_t> v(1024);
133 n = wcsftime_l(&v.front(),1024,format,t,lc);
134 }
135 return std::wstring(&v.front(),n);
136 #else
137 std::string enc = nl_langinfo_l(CODESET,lc);
138 std::string nformat = conv::from_utf<wchar_t>(format,enc);
139 std::string nres = ftime_traits<char>::ftime(nformat.c_str(),t,lc);
140 return conv::to_utf<wchar_t>(nres,enc);
141 #endif
142 }
143 };
144
145
146 template<typename CharType>
147 class time_put_posix : public std::time_put<CharType> {
148 public:
time_put_posix(boost::shared_ptr<locale_t> lc,size_t refs=0)149 time_put_posix(boost::shared_ptr<locale_t> lc, size_t refs = 0) :
150 std::time_put<CharType>(refs),
151 lc_(lc)
152 {
153 }
~time_put_posix()154 virtual ~time_put_posix()
155 {
156 }
157 typedef typename std::time_put<CharType>::iter_type iter_type;
158 typedef CharType char_type;
159 typedef std::basic_string<char_type> string_type;
160
do_put(iter_type out,std::ios_base &,CharType,std::tm const * tm,char format,char modifier) const161 virtual iter_type do_put(iter_type out,std::ios_base &/*ios*/,CharType /*fill*/,std::tm const *tm,char format,char modifier) const
162 {
163 char_type fmt[4] = { '%' , modifier != 0 ? modifier : format , modifier == 0 ? '\0' : format };
164 string_type res = ftime_traits<char_type>::ftime(fmt,tm,*lc_);
165 for(unsigned i=0;i<res.size();i++)
166 *out++ = res[i];
167 return out;
168 }
169
170 private:
171 boost::shared_ptr<locale_t> lc_;
172 };
173
174
175 template<typename CharType>
176 class ctype_posix;
177
178 template<>
179 class ctype_posix<char> : public std::ctype<char> {
180 public:
181
ctype_posix(boost::shared_ptr<locale_t> lc)182 ctype_posix(boost::shared_ptr<locale_t> lc)
183 {
184 lc_ = lc;
185 }
186
do_is(mask m,char c) const187 bool do_is(mask m,char c) const
188 {
189 if((m & space) && isspace_l(c,*lc_))
190 return true;
191 if((m & print) && isprint_l(c,*lc_))
192 return true;
193 if((m & cntrl) && iscntrl_l(c,*lc_))
194 return true;
195 if((m & upper) && isupper_l(c,*lc_))
196 return true;
197 if((m & lower) && islower_l(c,*lc_))
198 return true;
199 if((m & alpha) && isalpha_l(c,*lc_))
200 return true;
201 if((m & digit) && isdigit_l(c,*lc_))
202 return true;
203 if((m & xdigit) && isxdigit_l(c,*lc_))
204 return true;
205 if((m & punct) && ispunct_l(c,*lc_))
206 return true;
207 return false;
208 }
do_is(char const * begin,char const * end,mask * m) const209 char const *do_is(char const *begin,char const *end,mask *m) const
210 {
211 while(begin!=end) {
212 char c= *begin++;
213 int r=0;
214 if(isspace_l(c,*lc_))
215 r|=space;
216 if(isprint_l(c,*lc_))
217 r|=cntrl;
218 if(iscntrl_l(c,*lc_))
219 r|=space;
220 if(isupper_l(c,*lc_))
221 r|=upper;
222 if(islower_l(c,*lc_))
223 r|=lower;
224 if(isalpha_l(c,*lc_))
225 r|=alpha;
226 if(isdigit_l(c,*lc_))
227 r|=digit;
228 if(isxdigit_l(c,*lc_))
229 r|=xdigit;
230 if(ispunct_l(c,*lc_))
231 r|=punct;
232 // r actually should be mask, but some standard
233 // libraries (like STLPort)
234 // do not define operator | properly so using int+cast
235 *m++ = static_cast<mask>(r);
236 }
237 return begin;
238 }
do_scan_is(mask m,char const * begin,char const * end) const239 char const *do_scan_is(mask m,char const *begin,char const *end) const
240 {
241 while(begin!=end)
242 if(do_is(m,*begin))
243 return begin;
244 return begin;
245 }
do_scan_not(mask m,char const * begin,char const * end) const246 char const *do_scan_not(mask m,char const *begin,char const *end) const
247 {
248 while(begin!=end)
249 if(!do_is(m,*begin))
250 return begin;
251 return begin;
252 }
toupper(char c) const253 char toupper(char c) const
254 {
255 return toupper_l(c,*lc_);
256 }
toupper(char * begin,char const * end) const257 char const *toupper(char *begin,char const *end) const
258 {
259 for(;begin!=end;begin++)
260 *begin = toupper_l(*begin,*lc_);
261 return begin;
262 }
tolower(char c) const263 char tolower(char c) const
264 {
265 return tolower_l(c,*lc_);
266 }
tolower(char * begin,char const * end) const267 char const *tolower(char *begin,char const *end) const
268 {
269 for(;begin!=end;begin++)
270 *begin = tolower_l(*begin,*lc_);
271 return begin;
272 }
273 private:
274 boost::shared_ptr<locale_t> lc_;
275 };
276
277 template<>
278 class ctype_posix<wchar_t> : public std::ctype<wchar_t> {
279 public:
ctype_posix(boost::shared_ptr<locale_t> lc)280 ctype_posix(boost::shared_ptr<locale_t> lc)
281 {
282 lc_ = lc;
283 }
284
do_is(mask m,wchar_t c) const285 bool do_is(mask m,wchar_t c) const
286 {
287 if((m & space) && iswspace_l(c,*lc_))
288 return true;
289 if((m & print) && iswprint_l(c,*lc_))
290 return true;
291 if((m & cntrl) && iswcntrl_l(c,*lc_))
292 return true;
293 if((m & upper) && iswupper_l(c,*lc_))
294 return true;
295 if((m & lower) && iswlower_l(c,*lc_))
296 return true;
297 if((m & alpha) && iswalpha_l(c,*lc_))
298 return true;
299 if((m & digit) && iswdigit_l(c,*lc_))
300 return true;
301 if((m & xdigit) && iswxdigit_l(c,*lc_))
302 return true;
303 if((m & punct) && iswpunct_l(c,*lc_))
304 return true;
305 return false;
306 }
do_is(wchar_t const * begin,wchar_t const * end,mask * m) const307 wchar_t const *do_is(wchar_t const *begin,wchar_t const *end,mask *m) const
308 {
309 while(begin!=end) {
310 wchar_t c= *begin++;
311 int r=0;
312 if(iswspace_l(c,*lc_))
313 r|=space;
314 if(iswprint_l(c,*lc_))
315 r|=cntrl;
316 if(iswcntrl_l(c,*lc_))
317 r|=space;
318 if(iswupper_l(c,*lc_))
319 r|=upper;
320 if(iswlower_l(c,*lc_))
321 r|=lower;
322 if(iswalpha_l(c,*lc_))
323 r|=alpha;
324 if(iswdigit_l(c,*lc_))
325 r|=digit;
326 if(iswxdigit_l(c,*lc_))
327 r|=xdigit;
328 if(iswpunct_l(c,*lc_))
329 r|=punct;
330 // r actually should be mask, but some standard
331 // libraries (like STLPort)
332 // do not define operator | properly so using int+cast
333 *m++ = static_cast<mask>(r);
334 }
335 return begin;
336 }
do_scan_is(mask m,wchar_t const * begin,wchar_t const * end) const337 wchar_t const *do_scan_is(mask m,wchar_t const *begin,wchar_t const *end) const
338 {
339 while(begin!=end)
340 if(do_is(m,*begin))
341 return begin;
342 return begin;
343 }
do_scan_not(mask m,wchar_t const * begin,wchar_t const * end) const344 wchar_t const *do_scan_not(mask m,wchar_t const *begin,wchar_t const *end) const
345 {
346 while(begin!=end)
347 if(!do_is(m,*begin))
348 return begin;
349 return begin;
350 }
toupper(wchar_t c) const351 wchar_t toupper(wchar_t c) const
352 {
353 return towupper_l(c,*lc_);
354 }
toupper(wchar_t * begin,wchar_t const * end) const355 wchar_t const *toupper(wchar_t *begin,wchar_t const *end) const
356 {
357 for(;begin!=end;begin++)
358 *begin = towupper_l(*begin,*lc_);
359 return begin;
360 }
tolower(wchar_t c) const361 wchar_t tolower(wchar_t c) const
362 {
363 return tolower_l(c,*lc_);
364 }
tolower(wchar_t * begin,wchar_t const * end) const365 wchar_t const *tolower(wchar_t *begin,wchar_t const *end) const
366 {
367 for(;begin!=end;begin++)
368 *begin = tolower_l(*begin,*lc_);
369 return begin;
370 }
371 private:
372 boost::shared_ptr<locale_t> lc_;
373 };
374
375
376
377
378 struct basic_numpunct {
379 std::string grouping;
380 std::string thousands_sep;
381 std::string decimal_point;
basic_numpunctboost::locale::impl_posix::basic_numpunct382 basic_numpunct() :
383 decimal_point(".")
384 {
385 }
basic_numpunctboost::locale::impl_posix::basic_numpunct386 basic_numpunct(locale_t lc)
387 {
388 #ifdef __APPLE__
389 lconv *cv = localeconv_l(lc);
390 grouping = cv->grouping;
391 thousands_sep = cv->thousands_sep;
392 decimal_point = cv->decimal_point;
393 #else
394 thousands_sep = nl_langinfo_l(THOUSEP,lc);
395 decimal_point = nl_langinfo_l(RADIXCHAR,lc);
396 #ifdef GROUPING
397 grouping = nl_langinfo_l(GROUPING,lc);
398 #endif
399 #endif
400 }
401 };
402
403 template<typename CharType>
404 class num_punct_posix : public std::numpunct<CharType> {
405 public:
406 typedef std::basic_string<CharType> string_type;
num_punct_posix(locale_t lc,size_t refs=0)407 num_punct_posix(locale_t lc,size_t refs = 0) :
408 std::numpunct<CharType>(refs)
409 {
410 basic_numpunct np(lc);
411 to_str(np.thousands_sep,thousands_sep_,lc);
412 to_str(np.decimal_point,decimal_point_,lc);
413 grouping_ = np.grouping;
414 if(thousands_sep_.size() > 1)
415 grouping_ = std::string();
416 if(decimal_point_.size() > 1)
417 decimal_point_ = CharType('.');
418 }
to_str(std::string & s1,std::string & s2,locale_t)419 void to_str(std::string &s1,std::string &s2,locale_t /*lc*/)
420 {
421 s2.swap(s1);
422 }
to_str(std::string & s1,std::wstring & s2,locale_t lc)423 void to_str(std::string &s1,std::wstring &s2,locale_t lc)
424 {
425 s2=conv::to_utf<wchar_t>(s1,nl_langinfo_l(CODESET,lc));
426 }
do_decimal_point() const427 virtual CharType do_decimal_point() const
428 {
429 return *decimal_point_.c_str();
430 }
do_thousands_sep() const431 virtual CharType do_thousands_sep() const
432 {
433 return *thousands_sep_.c_str();
434 }
do_grouping() const435 virtual std::string do_grouping() const
436 {
437 return grouping_;
438 }
do_truename() const439 virtual string_type do_truename() const
440 {
441 static const char t[]="true";
442 return string_type(t,t+sizeof(t)-1);
443 }
do_falsename() const444 virtual string_type do_falsename() const
445 {
446 static const char t[]="false";
447 return string_type(t,t+sizeof(t)-1);
448 }
449 private:
450 string_type decimal_point_;
451 string_type thousands_sep_;
452 std::string grouping_;
453 };
454
455 template<typename CharType>
create_formatting_impl(std::locale const & in,boost::shared_ptr<locale_t> lc)456 std::locale create_formatting_impl(std::locale const &in,boost::shared_ptr<locale_t> lc)
457 {
458 std::locale tmp = std::locale(in,new num_punct_posix<CharType>(*lc));
459 tmp = std::locale(tmp,new ctype_posix<CharType>(lc));
460 tmp = std::locale(tmp,new time_put_posix<CharType>(lc));
461 tmp = std::locale(tmp,new num_format<CharType>(lc));
462 return tmp;
463 }
464
465 template<typename CharType>
create_parsing_impl(std::locale const & in,boost::shared_ptr<locale_t> lc)466 std::locale create_parsing_impl(std::locale const &in,boost::shared_ptr<locale_t> lc)
467 {
468 std::locale tmp = std::locale(in,new num_punct_posix<CharType>(*lc));
469 tmp = std::locale(tmp,new ctype_posix<CharType>(lc));
470 tmp = std::locale(tmp,new util::base_num_parse<CharType>());
471 return tmp;
472 }
473
474
create_formatting(std::locale const & in,boost::shared_ptr<locale_t> lc,character_facet_type type)475 std::locale create_formatting( std::locale const &in,
476 boost::shared_ptr<locale_t> lc,
477 character_facet_type type)
478 {
479 switch(type) {
480 case char_facet:
481 return create_formatting_impl<char>(in,lc);
482 case wchar_t_facet:
483 return create_formatting_impl<wchar_t>(in,lc);
484 default:
485 return in;
486 }
487 }
488
create_parsing(std::locale const & in,boost::shared_ptr<locale_t> lc,character_facet_type type)489 std::locale create_parsing( std::locale const &in,
490 boost::shared_ptr<locale_t> lc,
491 character_facet_type type)
492 {
493 switch(type) {
494 case char_facet:
495 return create_parsing_impl<char>(in,lc);
496 case wchar_t_facet:
497 return create_parsing_impl<wchar_t>(in,lc);
498 default:
499 return in;
500 }
501 }
502
503
504
505 } // impl_std
506 } // locale
507 } //boost
508
509
510
511 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
512