1 //////////////////////////////////////////////////////////////////////////////
2 // Name:        src/common/xlocale.cpp
3 // Purpose:     xlocale wrappers/impl to provide some xlocale wrappers
4 // Author:      Brian Vanderburg II, Vadim Zeitlin
5 // Created:     2008-01-07
6 // Copyright:   (c) 2008 Brian Vanderburg II
7 //                  2008 Vadim Zeitlin <vadim@wxwidgets.org>
8 // Licence:     wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10 
11 // ============================================================================
12 // declarations
13 // ============================================================================
14 
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18 
19 #include "wx/wxprec.h"
20 
21 #ifdef __BORLANDC__
22     #pragma hdrstop
23 #endif
24 
25 #if wxUSE_XLOCALE
26 
27 #ifndef WX_PRECOMP
28     #include "wx/module.h"
29 #endif
30 
31 #include "wx/xlocale.h"
32 
33 #include <errno.h>
34 #include <locale.h>
35 
36 // ----------------------------------------------------------------------------
37 // module globals
38 // ----------------------------------------------------------------------------
39 
40 // This is the C locale object, it is created on demand
41 static wxXLocale *gs_cLocale = NULL;
42 
43 wxXLocale wxNullXLocale;
44 
45 
46 // ============================================================================
47 // implementation
48 // ============================================================================
49 
50 // ----------------------------------------------------------------------------
51 // Module for gs_cLocale cleanup
52 // ----------------------------------------------------------------------------
53 
54 class wxXLocaleModule : public wxModule
55 {
56 public:
OnInit()57     virtual bool OnInit() { return true; }
OnExit()58     virtual void OnExit() { wxDELETE(gs_cLocale); }
59 
60     DECLARE_DYNAMIC_CLASS(wxXLocaleModule)
61 };
62 
IMPLEMENT_DYNAMIC_CLASS(wxXLocaleModule,wxModule)63 IMPLEMENT_DYNAMIC_CLASS(wxXLocaleModule, wxModule)
64 
65 
66 // ============================================================================
67 // wxXLocale implementation
68 // ============================================================================
69 
70 // ----------------------------------------------------------------------------
71 // common parts
72 // ----------------------------------------------------------------------------
73 
74 // Get the C locale
75 wxXLocale& wxXLocale::GetCLocale()
76 {
77     if ( !gs_cLocale )
78     {
79         // Notice that we need a separate variable because clang 3.1 refuses to
80         // cast nullptr (which is how NULL is defined in it) to anything.
81         static wxXLocaleCTag* const tag = NULL;
82         gs_cLocale = new wxXLocale(tag);
83     }
84 
85     return *gs_cLocale;
86 }
87 
88 #ifdef wxHAS_XLOCALE_SUPPORT
89 
wxXLocale(wxLanguage lang)90 wxXLocale::wxXLocale(wxLanguage lang)
91 {
92     const wxLanguageInfo * const info = wxLocale::GetLanguageInfo(lang);
93     if ( !info )
94     {
95         m_locale = NULL;
96     }
97     else
98     {
99         Init(info->GetLocaleName().c_str());
100     }
101 }
102 
103 #if wxCHECK_VISUALC_VERSION(8)
104 
105 // ----------------------------------------------------------------------------
106 // implementation using MSVC locale API
107 // ----------------------------------------------------------------------------
108 
Init(const char * loc)109 void wxXLocale::Init(const char *loc)
110 {
111     if (!loc || *loc == '\0')
112         return;
113 
114     m_locale = _create_locale(LC_ALL, loc);
115 }
116 
Free()117 void wxXLocale::Free()
118 {
119     if ( m_locale )
120         _free_locale(m_locale);
121 }
122 
123 #elif defined(HAVE_LOCALE_T)
124 
125 // ----------------------------------------------------------------------------
126 // implementation using xlocale API
127 // ----------------------------------------------------------------------------
128 
Init(const char * loc)129 void wxXLocale::Init(const char *loc)
130 {
131     if (!loc || *loc == '\0')
132         return;
133 
134     m_locale = newlocale(LC_ALL_MASK, loc, NULL);
135     if (!m_locale)
136     {
137         // NOTE: here we do something similar to what wxSetLocaleTryUTF8() does
138         //       in wxLocale code (but with newlocale() calls instead of wxSetlocale())
139         wxString buf(loc);
140         wxString buf2;
141         buf2 = buf + wxS(".UTF-8");
142         m_locale = newlocale(LC_ALL_MASK, buf2.c_str(), NULL);
143         if ( !m_locale )
144         {
145             buf2 = buf + wxS(".utf-8");
146             m_locale = newlocale(LC_ALL_MASK, buf2.c_str(), NULL);
147         }
148         if ( !m_locale )
149         {
150             buf2 = buf + wxS(".UTF8");
151             m_locale = newlocale(LC_ALL_MASK, buf2.c_str(), NULL);
152         }
153         if ( !m_locale )
154         {
155             buf2 = buf + wxS(".utf8");
156             m_locale = newlocale(LC_ALL_MASK, buf2.c_str(), NULL);
157         }
158     }
159 
160     // TODO: wxLocale performs many more manipulations of the given locale
161     //       string in the attempt to set a valid locale; reusing that code
162     //       (changing it to take a generic wxTryLocale callback) would be nice
163 }
164 
Free()165 void wxXLocale::Free()
166 {
167     if ( m_locale )
168         freelocale(m_locale);
169 }
170 
171 #else
172     #error "Unknown xlocale support."
173 #endif
174 
175 #endif // wxHAS_XLOCALE_SUPPORT
176 
177 #ifndef wxHAS_XLOCALE_SUPPORT
178 
179 // ============================================================================
180 // Implementation of wxFoo_l() functions for "C" locale without xlocale support
181 // ============================================================================
182 
183 // ----------------------------------------------------------------------------
184 // character classification and transformation functions
185 // ----------------------------------------------------------------------------
186 
187 // lookup table and macros for character type functions
188 #define CTYPE_ALNUM 0x0001
189 #define CTYPE_ALPHA 0x0002
190 #define CTYPE_CNTRL 0x0004
191 #define CTYPE_DIGIT 0x0008
192 #define CTYPE_GRAPH 0x0010
193 #define CTYPE_LOWER 0x0020
194 #define CTYPE_PRINT 0x0040
195 #define CTYPE_PUNCT 0x0080
196 #define CTYPE_SPACE 0x0100
197 #define CTYPE_UPPER 0x0200
198 #define CTYPE_XDIGIT 0x0400
199 
200 static const unsigned int gs_lookup[] =
201 {
202     0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004,
203     0x0004, 0x0104, 0x0104, 0x0104, 0x0104, 0x0104, 0x0004, 0x0004,
204     0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004,
205     0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004,
206     0x0140, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0,
207     0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0,
208     0x0459, 0x0459, 0x0459, 0x0459, 0x0459, 0x0459, 0x0459, 0x0459,
209     0x0459, 0x0459, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0,
210     0x00D0, 0x0653, 0x0653, 0x0653, 0x0653, 0x0653, 0x0653, 0x0253,
211     0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253,
212     0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253,
213     0x0253, 0x0253, 0x0253, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0,
214     0x00D0, 0x0473, 0x0473, 0x0473, 0x0473, 0x0473, 0x0473, 0x0073,
215     0x0073, 0x0073, 0x0073, 0x0073, 0x0073, 0x0073, 0x0073, 0x0073,
216     0x0073, 0x0073, 0x0073, 0x0073, 0x0073, 0x0073, 0x0073, 0x0073,
217     0x0073, 0x0073, 0x0073, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x0004
218 };
219 
220 
221 #define CTYPE_TEST(c, t) ( (c) <= 127 && (gs_lookup[(c)] & (t)) )
222 
223 
224 // ctype functions
225 #define GEN_ISFUNC(name, test) \
226 int name(const wxUniChar& c, const wxXLocale& loc) \
227 { \
228     wxCHECK(loc.IsOk(), false); \
229     return CTYPE_TEST(c.GetValue(), test); \
230 }
231 
GEN_ISFUNC(wxIsalnum_l,CTYPE_ALNUM)232 GEN_ISFUNC(wxIsalnum_l, CTYPE_ALNUM)
233 GEN_ISFUNC(wxIsalpha_l, CTYPE_ALPHA)
234 GEN_ISFUNC(wxIscntrl_l, CTYPE_CNTRL)
235 GEN_ISFUNC(wxIsdigit_l, CTYPE_DIGIT)
236 GEN_ISFUNC(wxIsgraph_l, CTYPE_GRAPH)
237 GEN_ISFUNC(wxIslower_l, CTYPE_LOWER)
238 GEN_ISFUNC(wxIsprint_l, CTYPE_PRINT)
239 GEN_ISFUNC(wxIspunct_l, CTYPE_PUNCT)
240 GEN_ISFUNC(wxIsspace_l, CTYPE_SPACE)
241 GEN_ISFUNC(wxIsupper_l, CTYPE_UPPER)
242 GEN_ISFUNC(wxIsxdigit_l, CTYPE_XDIGIT)
243 
244 int wxTolower_l(const wxUniChar& c, const wxXLocale& loc)
245 {
246     wxCHECK(loc.IsOk(), false);
247 
248     if(CTYPE_TEST(c.GetValue(), CTYPE_UPPER))
249     {
250         return c - 'A' + 'a';
251     }
252 
253     return c;
254 }
255 
wxToupper_l(const wxUniChar & c,const wxXLocale & loc)256 int wxToupper_l(const wxUniChar& c, const wxXLocale& loc)
257 {
258     wxCHECK(loc.IsOk(), false);
259 
260     if(CTYPE_TEST(c.GetValue(), CTYPE_LOWER))
261     {
262         return c - 'a' + 'A';
263     }
264 
265     return c;
266 }
267 
268 
269 // ----------------------------------------------------------------------------
270 // string --> number conversion functions
271 // ----------------------------------------------------------------------------
272 
273 /*
274     WARNING: the implementation of the wxStrtoX_l() functions below is unsafe
275              in a multi-threaded environment as we temporary change the locale
276              and if in the meanwhile an other thread performs some locale-dependent
277              operation, it may get unexpected results...
278              However this is the best we can do without reinventing the wheel in the
279              case !wxHAS_XLOCALE_SUPPORT...
280 */
281 
282 namespace
283 {
284 
285 // Helper class that changes LC_NUMERIC facet of the global locale in its ctor
286 // to "C" locale and restores it in its dtor later.
287 class CNumericLocaleSetter
288 {
289 public:
CNumericLocaleSetter()290     CNumericLocaleSetter()
291         : m_oldLocale(wxStrdupA(setlocale(LC_NUMERIC, NULL)))
292     {
293         if ( !wxSetlocale(LC_NUMERIC, "C") )
294         {
295             // Setting locale to "C" should really always work.
296             wxFAIL_MSG( wxS("Couldn't set LC_NUMERIC to \"C\"") );
297         }
298     }
299 
~CNumericLocaleSetter()300     ~CNumericLocaleSetter()
301     {
302         wxSetlocale(LC_NUMERIC, m_oldLocale);
303         free(m_oldLocale);
304     }
305 
306 private:
307     char * const m_oldLocale;
308 
309     wxDECLARE_NO_COPY_CLASS(CNumericLocaleSetter);
310 };
311 
312 } // anonymous namespace
313 
wxStrtod_l(const wchar_t * str,wchar_t ** endptr,const wxXLocale & loc)314 double wxStrtod_l(const wchar_t* str, wchar_t **endptr, const wxXLocale& loc)
315 {
316     wxCHECK( loc.IsOk(), 0. );
317 
318     CNumericLocaleSetter locSetter;
319 
320     return wxStrtod(str, endptr);
321 }
322 
wxStrtod_l(const char * str,char ** endptr,const wxXLocale & loc)323 double wxStrtod_l(const char* str, char **endptr, const wxXLocale& loc)
324 {
325     wxCHECK( loc.IsOk(), 0. );
326 
327     CNumericLocaleSetter locSetter;
328 
329     return wxStrtod(str, endptr);
330 }
331 
wxStrtol_l(const wchar_t * str,wchar_t ** endptr,int base,const wxXLocale & loc)332 long wxStrtol_l(const wchar_t* str, wchar_t **endptr, int base, const wxXLocale& loc)
333 {
334     wxCHECK( loc.IsOk(), 0 );
335 
336     CNumericLocaleSetter locSetter;
337 
338     return wxStrtol(str, endptr, base);
339 }
340 
wxStrtol_l(const char * str,char ** endptr,int base,const wxXLocale & loc)341 long wxStrtol_l(const char* str, char **endptr, int base, const wxXLocale& loc)
342 {
343     wxCHECK( loc.IsOk(), 0 );
344 
345     CNumericLocaleSetter locSetter;
346 
347     return wxStrtol(str, endptr, base);
348 }
349 
wxStrtoul_l(const wchar_t * str,wchar_t ** endptr,int base,const wxXLocale & loc)350 unsigned long wxStrtoul_l(const wchar_t* str, wchar_t **endptr, int base, const wxXLocale& loc)
351 {
352     wxCHECK( loc.IsOk(), 0 );
353 
354     CNumericLocaleSetter locSetter;
355 
356     return wxStrtoul(str, endptr, base);
357 }
358 
wxStrtoul_l(const char * str,char ** endptr,int base,const wxXLocale & loc)359 unsigned long wxStrtoul_l(const char* str, char **endptr, int base, const wxXLocale& loc)
360 {
361     wxCHECK( loc.IsOk(), 0 );
362 
363     CNumericLocaleSetter locSetter;
364 
365     return wxStrtoul(str, endptr, base);
366 }
367 
368 #endif // !defined(wxHAS_XLOCALE_SUPPORT)
369 
370 #endif // wxUSE_XLOCALE
371