////////////////////////////////////////////////////////////////////////////// // Name: src/common/xlocale.cpp // Purpose: xlocale wrappers/impl to provide some xlocale wrappers // Author: Brian Vanderburg II, Vadim Zeitlin // Created: 2008-01-07 // Copyright: (c) 2008 Brian Vanderburg II // 2008 Vadim Zeitlin // Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// // ============================================================================ // declarations // ============================================================================ // ---------------------------------------------------------------------------- // headers // ---------------------------------------------------------------------------- #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #if wxUSE_XLOCALE #ifndef WX_PRECOMP #include "wx/module.h" #endif #include "wx/xlocale.h" #include #include // ---------------------------------------------------------------------------- // module globals // ---------------------------------------------------------------------------- // This is the C locale object, it is created on demand static wxXLocale *gs_cLocale = NULL; wxXLocale wxNullXLocale; // ============================================================================ // implementation // ============================================================================ // ---------------------------------------------------------------------------- // Module for gs_cLocale cleanup // ---------------------------------------------------------------------------- class wxXLocaleModule : public wxModule { public: virtual bool OnInit() { return true; } virtual void OnExit() { wxDELETE(gs_cLocale); } DECLARE_DYNAMIC_CLASS(wxXLocaleModule) }; IMPLEMENT_DYNAMIC_CLASS(wxXLocaleModule, wxModule) // ============================================================================ // wxXLocale implementation // ============================================================================ // ---------------------------------------------------------------------------- // common parts // ---------------------------------------------------------------------------- // Get the C locale wxXLocale& wxXLocale::GetCLocale() { if ( !gs_cLocale ) { // Notice that we need a separate variable because clang 3.1 refuses to // cast nullptr (which is how NULL is defined in it) to anything. static wxXLocaleCTag* const tag = NULL; gs_cLocale = new wxXLocale(tag); } return *gs_cLocale; } #ifdef wxHAS_XLOCALE_SUPPORT wxXLocale::wxXLocale(wxLanguage lang) { const wxLanguageInfo * const info = wxLocale::GetLanguageInfo(lang); if ( !info ) { m_locale = NULL; } else { Init(info->GetLocaleName().c_str()); } } #if wxCHECK_VISUALC_VERSION(8) // ---------------------------------------------------------------------------- // implementation using MSVC locale API // ---------------------------------------------------------------------------- void wxXLocale::Init(const char *loc) { if (!loc || *loc == '\0') return; m_locale = _create_locale(LC_ALL, loc); } void wxXLocale::Free() { if ( m_locale ) _free_locale(m_locale); } #elif defined(HAVE_LOCALE_T) // ---------------------------------------------------------------------------- // implementation using xlocale API // ---------------------------------------------------------------------------- void wxXLocale::Init(const char *loc) { if (!loc || *loc == '\0') return; m_locale = newlocale(LC_ALL_MASK, loc, NULL); if (!m_locale) { // NOTE: here we do something similar to what wxSetLocaleTryUTF8() does // in wxLocale code (but with newlocale() calls instead of wxSetlocale()) wxString buf(loc); wxString buf2; buf2 = buf + wxS(".UTF-8"); m_locale = newlocale(LC_ALL_MASK, buf2.c_str(), NULL); if ( !m_locale ) { buf2 = buf + wxS(".utf-8"); m_locale = newlocale(LC_ALL_MASK, buf2.c_str(), NULL); } if ( !m_locale ) { buf2 = buf + wxS(".UTF8"); m_locale = newlocale(LC_ALL_MASK, buf2.c_str(), NULL); } if ( !m_locale ) { buf2 = buf + wxS(".utf8"); m_locale = newlocale(LC_ALL_MASK, buf2.c_str(), NULL); } } // TODO: wxLocale performs many more manipulations of the given locale // string in the attempt to set a valid locale; reusing that code // (changing it to take a generic wxTryLocale callback) would be nice } void wxXLocale::Free() { if ( m_locale ) freelocale(m_locale); } #else #error "Unknown xlocale support." #endif #endif // wxHAS_XLOCALE_SUPPORT #ifndef wxHAS_XLOCALE_SUPPORT // ============================================================================ // Implementation of wxFoo_l() functions for "C" locale without xlocale support // ============================================================================ // ---------------------------------------------------------------------------- // character classification and transformation functions // ---------------------------------------------------------------------------- // lookup table and macros for character type functions #define CTYPE_ALNUM 0x0001 #define CTYPE_ALPHA 0x0002 #define CTYPE_CNTRL 0x0004 #define CTYPE_DIGIT 0x0008 #define CTYPE_GRAPH 0x0010 #define CTYPE_LOWER 0x0020 #define CTYPE_PRINT 0x0040 #define CTYPE_PUNCT 0x0080 #define CTYPE_SPACE 0x0100 #define CTYPE_UPPER 0x0200 #define CTYPE_XDIGIT 0x0400 static const unsigned int gs_lookup[] = { 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0104, 0x0104, 0x0104, 0x0104, 0x0104, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0140, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x0459, 0x0459, 0x0459, 0x0459, 0x0459, 0x0459, 0x0459, 0x0459, 0x0459, 0x0459, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x0653, 0x0653, 0x0653, 0x0653, 0x0653, 0x0653, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x0473, 0x0473, 0x0473, 0x0473, 0x0473, 0x0473, 0x0073, 0x0073, 0x0073, 0x0073, 0x0073, 0x0073, 0x0073, 0x0073, 0x0073, 0x0073, 0x0073, 0x0073, 0x0073, 0x0073, 0x0073, 0x0073, 0x0073, 0x0073, 0x0073, 0x0073, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x0004 }; #define CTYPE_TEST(c, t) ( (c) <= 127 && (gs_lookup[(c)] & (t)) ) // ctype functions #define GEN_ISFUNC(name, test) \ int name(const wxUniChar& c, const wxXLocale& loc) \ { \ wxCHECK(loc.IsOk(), false); \ return CTYPE_TEST(c.GetValue(), test); \ } GEN_ISFUNC(wxIsalnum_l, CTYPE_ALNUM) GEN_ISFUNC(wxIsalpha_l, CTYPE_ALPHA) GEN_ISFUNC(wxIscntrl_l, CTYPE_CNTRL) GEN_ISFUNC(wxIsdigit_l, CTYPE_DIGIT) GEN_ISFUNC(wxIsgraph_l, CTYPE_GRAPH) GEN_ISFUNC(wxIslower_l, CTYPE_LOWER) GEN_ISFUNC(wxIsprint_l, CTYPE_PRINT) GEN_ISFUNC(wxIspunct_l, CTYPE_PUNCT) GEN_ISFUNC(wxIsspace_l, CTYPE_SPACE) GEN_ISFUNC(wxIsupper_l, CTYPE_UPPER) GEN_ISFUNC(wxIsxdigit_l, CTYPE_XDIGIT) int wxTolower_l(const wxUniChar& c, const wxXLocale& loc) { wxCHECK(loc.IsOk(), false); if(CTYPE_TEST(c.GetValue(), CTYPE_UPPER)) { return c - 'A' + 'a'; } return c; } int wxToupper_l(const wxUniChar& c, const wxXLocale& loc) { wxCHECK(loc.IsOk(), false); if(CTYPE_TEST(c.GetValue(), CTYPE_LOWER)) { return c - 'a' + 'A'; } return c; } // ---------------------------------------------------------------------------- // string --> number conversion functions // ---------------------------------------------------------------------------- /* WARNING: the implementation of the wxStrtoX_l() functions below is unsafe in a multi-threaded environment as we temporary change the locale and if in the meanwhile an other thread performs some locale-dependent operation, it may get unexpected results... However this is the best we can do without reinventing the wheel in the case !wxHAS_XLOCALE_SUPPORT... */ namespace { // Helper class that changes LC_NUMERIC facet of the global locale in its ctor // to "C" locale and restores it in its dtor later. class CNumericLocaleSetter { public: CNumericLocaleSetter() : m_oldLocale(wxStrdupA(setlocale(LC_NUMERIC, NULL))) { if ( !wxSetlocale(LC_NUMERIC, "C") ) { // Setting locale to "C" should really always work. wxFAIL_MSG( wxS("Couldn't set LC_NUMERIC to \"C\"") ); } } ~CNumericLocaleSetter() { wxSetlocale(LC_NUMERIC, m_oldLocale); free(m_oldLocale); } private: char * const m_oldLocale; wxDECLARE_NO_COPY_CLASS(CNumericLocaleSetter); }; } // anonymous namespace double wxStrtod_l(const wchar_t* str, wchar_t **endptr, const wxXLocale& loc) { wxCHECK( loc.IsOk(), 0. ); CNumericLocaleSetter locSetter; return wxStrtod(str, endptr); } double wxStrtod_l(const char* str, char **endptr, const wxXLocale& loc) { wxCHECK( loc.IsOk(), 0. ); CNumericLocaleSetter locSetter; return wxStrtod(str, endptr); } long wxStrtol_l(const wchar_t* str, wchar_t **endptr, int base, const wxXLocale& loc) { wxCHECK( loc.IsOk(), 0 ); CNumericLocaleSetter locSetter; return wxStrtol(str, endptr, base); } long wxStrtol_l(const char* str, char **endptr, int base, const wxXLocale& loc) { wxCHECK( loc.IsOk(), 0 ); CNumericLocaleSetter locSetter; return wxStrtol(str, endptr, base); } unsigned long wxStrtoul_l(const wchar_t* str, wchar_t **endptr, int base, const wxXLocale& loc) { wxCHECK( loc.IsOk(), 0 ); CNumericLocaleSetter locSetter; return wxStrtoul(str, endptr, base); } unsigned long wxStrtoul_l(const char* str, char **endptr, int base, const wxXLocale& loc) { wxCHECK( loc.IsOk(), 0 ); CNumericLocaleSetter locSetter; return wxStrtoul(str, endptr, base); } #endif // !defined(wxHAS_XLOCALE_SUPPORT) #endif // wxUSE_XLOCALE