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