Commit | Line | Data |
---|---|---|
6e4ae332 VZ |
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 | // RCS-ID: $Id$ | |
7 | // Copyright: (c) 2008 Brian Vanderburg II | |
8 | // 2008 Vadim Zeitlin <vadim@wxwidgets.org> | |
9 | // Licence: wxWindows licence | |
10 | /////////////////////////////////////////////////////////////////////////////// | |
11 | ||
12 | // ============================================================================ | |
13 | // declarations | |
14 | // ============================================================================ | |
15 | ||
16 | // ---------------------------------------------------------------------------- | |
17 | // headers | |
18 | // ---------------------------------------------------------------------------- | |
19 | ||
20 | #include "wx/wxprec.h" | |
21 | ||
22 | #ifdef __BORLANDC__ | |
23 | #pragma hdrstop | |
24 | #endif | |
25 | ||
26 | #if wxUSE_XLOCALE | |
27 | ||
28 | #ifndef WX_PRECOMP | |
29 | #include "wx/module.h" | |
30 | #endif | |
31 | ||
32 | #include "wx/xlocale.h" | |
33 | ||
28e0798f | 34 | #include <errno.h> |
c71498a1 | 35 | #include <locale.h> |
28e0798f | 36 | |
6e4ae332 VZ |
37 | // ---------------------------------------------------------------------------- |
38 | // module globals | |
39 | // ---------------------------------------------------------------------------- | |
40 | ||
41 | // This is the C locale object, it is created on demand | |
42 | static wxXLocale *gs_cLocale = NULL; | |
43 | ||
dad013ac FM |
44 | wxXLocale wxNullXLocale; |
45 | ||
46 | ||
6e4ae332 VZ |
47 | // ============================================================================ |
48 | // implementation | |
49 | // ============================================================================ | |
50 | ||
51 | // ---------------------------------------------------------------------------- | |
52 | // Module for gs_cLocale cleanup | |
53 | // ---------------------------------------------------------------------------- | |
54 | ||
55 | class wxXLocaleModule : public wxModule | |
56 | { | |
57 | public: | |
58 | virtual bool OnInit() { return true; } | |
59 | virtual void OnExit() { wxDELETE(gs_cLocale); } | |
60 | ||
61 | DECLARE_DYNAMIC_CLASS(wxXLocaleModule) | |
62 | }; | |
63 | ||
64 | IMPLEMENT_DYNAMIC_CLASS(wxXLocaleModule, wxModule) | |
65 | ||
66 | ||
67 | // ============================================================================ | |
68 | // wxXLocale implementation | |
69 | // ============================================================================ | |
70 | ||
71 | // ---------------------------------------------------------------------------- | |
72 | // common parts | |
73 | // ---------------------------------------------------------------------------- | |
74 | ||
75 | // Get the C locale | |
76 | wxXLocale& wxXLocale::GetCLocale() | |
77 | { | |
78 | if ( !gs_cLocale ) | |
79 | { | |
25859335 VZ |
80 | // NOTE: bcc551 has trouble doing static_cast with incomplete |
81 | // type definition. reinterpret_cast used as workaround | |
82 | gs_cLocale = new wxXLocale( reinterpret_cast<wxXLocaleCTag *>(NULL) ); | |
6e4ae332 VZ |
83 | } |
84 | ||
85 | return *gs_cLocale; | |
86 | } | |
87 | ||
45f5fbd4 VZ |
88 | #ifdef wxHAS_XLOCALE_SUPPORT |
89 | ||
6e4ae332 VZ |
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 | { | |
e340b786 | 99 | Init(info->GetLocaleName().c_str()); |
6e4ae332 VZ |
100 | } |
101 | } | |
102 | ||
6e4ae332 VZ |
103 | #if wxCHECK_VISUALC_VERSION(8) |
104 | ||
105 | // ---------------------------------------------------------------------------- | |
106 | // implementation using MSVC locale API | |
107 | // ---------------------------------------------------------------------------- | |
108 | ||
109 | void wxXLocale::Init(const char *loc) | |
110 | { | |
dad013ac FM |
111 | if (!loc || *loc == '\0') |
112 | return; | |
113 | ||
6e4ae332 VZ |
114 | m_locale = _create_locale(LC_ALL, loc); |
115 | } | |
116 | ||
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 | ||
129 | void wxXLocale::Init(const char *loc) | |
130 | { | |
dad013ac FM |
131 | if (!loc || *loc == '\0') |
132 | return; | |
133 | ||
6e4ae332 | 134 | m_locale = newlocale(LC_ALL_MASK, loc, NULL); |
dad013ac FM |
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"); | |
5337ab1b | 142 | m_locale = newlocale(LC_ALL_MASK, buf2.c_str(), NULL); |
dad013ac FM |
143 | if ( !m_locale ) |
144 | { | |
145 | buf2 = buf + wxS(".utf-8"); | |
5337ab1b | 146 | m_locale = newlocale(LC_ALL_MASK, buf2.c_str(), NULL); |
dad013ac FM |
147 | } |
148 | if ( !m_locale ) | |
149 | { | |
150 | buf2 = buf + wxS(".UTF8"); | |
5337ab1b | 151 | m_locale = newlocale(LC_ALL_MASK, buf2.c_str(), NULL); |
dad013ac FM |
152 | } |
153 | if ( !m_locale ) | |
154 | { | |
155 | buf2 = buf + wxS(".utf8"); | |
5337ab1b | 156 | m_locale = newlocale(LC_ALL_MASK, buf2.c_str(), NULL); |
dad013ac FM |
157 | } |
158 | } | |
03647350 | 159 | |
dad013ac FM |
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 | |
6e4ae332 VZ |
163 | } |
164 | ||
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 | ||
a243da29 | 200 | static const unsigned int gs_lookup[] = |
6e4ae332 VZ |
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 | ||
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 | ||
a4e53d46 | 244 | int wxTolower_l(const wxUniChar& c, const wxXLocale& loc) |
6e4ae332 VZ |
245 | { |
246 | wxCHECK(loc.IsOk(), false); | |
247 | ||
45f5fbd4 | 248 | if(CTYPE_TEST(c.GetValue(), CTYPE_UPPER)) |
6e4ae332 VZ |
249 | { |
250 | return c - 'A' + 'a'; | |
251 | } | |
252 | ||
253 | return c; | |
254 | } | |
255 | ||
a4e53d46 | 256 | int wxToupper_l(const wxUniChar& c, const wxXLocale& loc) |
6e4ae332 VZ |
257 | { |
258 | wxCHECK(loc.IsOk(), false); | |
259 | ||
45f5fbd4 | 260 | if(CTYPE_TEST(c.GetValue(), CTYPE_LOWER)) |
6e4ae332 VZ |
261 | { |
262 | return c - 'a' + 'A'; | |
263 | } | |
264 | ||
265 | return c; | |
266 | } | |
267 | ||
28e0798f FM |
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 | ||
cee25be7 VZ |
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: | |
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 | } | |
797a2706 | 298 | } |
28e0798f | 299 | |
cee25be7 VZ |
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 | |
28e0798f FM |
313 | |
314 | double wxStrtod_l(const wchar_t* str, wchar_t **endptr, const wxXLocale& loc) | |
315 | { | |
cee25be7 VZ |
316 | wxCHECK( loc.IsOk(), 0. ); |
317 | ||
318 | CNumericLocaleSetter locSetter; | |
319 | ||
320 | return wxStrtod(str, endptr); | |
28e0798f FM |
321 | } |
322 | ||
323 | double wxStrtod_l(const char* str, char **endptr, const wxXLocale& loc) | |
324 | { | |
cee25be7 VZ |
325 | wxCHECK( loc.IsOk(), 0. ); |
326 | ||
327 | CNumericLocaleSetter locSetter; | |
328 | ||
329 | return wxStrtod(str, endptr); | |
28e0798f FM |
330 | } |
331 | ||
332 | long wxStrtol_l(const wchar_t* str, wchar_t **endptr, int base, const wxXLocale& loc) | |
03647350 | 333 | { |
cee25be7 VZ |
334 | wxCHECK( loc.IsOk(), 0 ); |
335 | ||
336 | CNumericLocaleSetter locSetter; | |
337 | ||
338 | return wxStrtol(str, endptr, base); | |
28e0798f FM |
339 | } |
340 | ||
341 | long wxStrtol_l(const char* str, char **endptr, int base, const wxXLocale& loc) | |
342 | { | |
cee25be7 VZ |
343 | wxCHECK( loc.IsOk(), 0 ); |
344 | ||
345 | CNumericLocaleSetter locSetter; | |
346 | ||
347 | return wxStrtol(str, endptr, base); | |
28e0798f FM |
348 | } |
349 | ||
350 | unsigned long wxStrtoul_l(const wchar_t* str, wchar_t **endptr, int base, const wxXLocale& loc) | |
351 | { | |
cee25be7 VZ |
352 | wxCHECK( loc.IsOk(), 0 ); |
353 | ||
354 | CNumericLocaleSetter locSetter; | |
355 | ||
356 | return wxStrtoul(str, endptr, base); | |
28e0798f FM |
357 | } |
358 | ||
359 | unsigned long wxStrtoul_l(const char* str, char **endptr, int base, const wxXLocale& loc) | |
360 | { | |
cee25be7 VZ |
361 | wxCHECK( loc.IsOk(), 0 ); |
362 | ||
363 | CNumericLocaleSetter locSetter; | |
28e0798f | 364 | |
cee25be7 VZ |
365 | return wxStrtoul(str, endptr, base); |
366 | } | |
28e0798f | 367 | |
6e4ae332 VZ |
368 | #endif // !defined(wxHAS_XLOCALE_SUPPORT) |
369 | ||
370 | #endif // wxUSE_XLOCALE |