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