From cb352236d9c7228e336a98c2c1a22e933c67e449 Mon Sep 17 00:00:00 2001 From: =?utf8?q?V=C3=A1clav=20Slav=C3=ADk?= Date: Mon, 23 Apr 2007 20:42:13 +0000 Subject: [PATCH] added code for checking if the current locale is UTF-8 at runtime git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@45609 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/chartype.h | 8 +++++ include/wx/wxcrt.h | 31 +++++++++++++---- src/common/appbase.cpp | 1 + src/common/intl.cpp | 29 ++++++++++------ src/common/wxcrt.cpp | 75 ++++++++++++++++++++++++++++++++++++++++-- src/gtk/app.cpp | 1 + src/gtk/utilsgtk.cpp | 1 + 7 files changed, 126 insertions(+), 20 deletions(-) diff --git a/include/wx/chartype.h b/include/wx/chartype.h index e5ddbf0c9a..ea5b9f93c6 100644 --- a/include/wx/chartype.h +++ b/include/wx/chartype.h @@ -190,6 +190,14 @@ /* depending on the platform, Unicode build can either store wxStrings as wchar_t* or UTF-8 encoded char*: */ #if wxUSE_UNICODE + // FIXME-UTF8: what would be better place for this? + #if defined(wxUSE_UTF8_LOCALE_ONLY) && !defined(wxUSE_UNICODE_UTF8) + #error "wxUSE_UTF8_LOCALE_ONLY only makes sense with wxUSE_UNICODE_UTF8" + #endif + #ifndef wxUSE_UTF8_LOCALE_ONLY + #define wxUSE_UTF8_LOCALE_ONLY 0 + #endif + #ifndef wxUSE_UNICODE_UTF8 #define wxUSE_UNICODE_UTF8 0 #endif diff --git a/include/wx/wxcrt.h b/include/wx/wxcrt.h index 461feba702..74a63624d6 100644 --- a/include/wx/wxcrt.h +++ b/include/wx/wxcrt.h @@ -19,6 +19,20 @@ #include /* we use FILE below */ +#ifdef __cplusplus + #if wxUSE_UNICODE_UTF8 + // flag indicating whether the current locale uses UTF-8 or not; must be + // updated every time the locale is changed! + #if !wxUSE_UTF8_LOCALE_ONLY + extern WXDLLIMPEXP_BASE bool wxLocaleIsUtf8; + #endif + // function used to update the flag: + extern WXDLLIMPEXP_BASE void wxUpdateLocaleIsUtf8(); + #else // !wxUSE_UNICODE_UTF8 + inline WXDLLIMPEXP_BASE void wxUpdateLocaleIsUtf8() {} + #endif // wxUSE_UNICODE_UTF8/!wxUSE_UNICODE_UTF8 +#endif // __cplusplus + #if defined(HAVE_STRTOK_R) && defined(__DARWIN__) && defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS char *strtok_r(char *, const char *, char **); #endif @@ -99,7 +113,7 @@ #define wxToupper(c) _totupper((wxUChar)(wxChar)(c)) /* locale.h functons */ - #define wxSetlocale _tsetlocale + #define wxSetlocale_ _tsetlocale /* string.h functions */ #define wxStrcat _tcscat @@ -476,7 +490,7 @@ #define wxToupper toupper /* locale.h functons */ - #define wxSetlocale setlocale + #define wxSetlocale_ setlocale /* string.h functions */ #define wxStrcat strcat @@ -772,11 +786,14 @@ WXDLLIMPEXP_BASE wxChar * wxStrtok(wxChar *psz, const wxChar *delim, wxChar **sa #endif #ifdef __cplusplus -#ifndef wxSetlocale -class WXDLLIMPEXP_BASE wxWCharBuffer; -WXDLLIMPEXP_BASE wxWCharBuffer wxSetlocale(int category, const wxChar *locale); -#endif -#endif + #ifndef wxSetlocale_ + class WXDLLIMPEXP_BASE wxWCharBuffer; + WXDLLIMPEXP_BASE wxWCharBuffer wxSetlocale_(int category, const wxChar *locale); + WXDLLIMPEXP_BASE wxWCharBuffer wxSetlocale(int category, const wxChar *locale); + #else + WXDLLIMPEXP_BASE const wxChar *wxSetlocale(int category, const wxChar *locale); + #endif // defined(wxSetlocale_) +#endif // __cplusplus /* stdio.h functions */ #ifdef wxNEED_WX_STDIO_H diff --git a/src/common/appbase.cpp b/src/common/appbase.cpp index 53d05a50fd..79cfe27e25 100644 --- a/src/common/appbase.cpp +++ b/src/common/appbase.cpp @@ -513,6 +513,7 @@ GSocketGUIFunctionsTable* wxConsoleAppTraitsBase::GetSocketGUIFunctionsTable() void wxAppTraitsBase::SetLocale() { setlocale(LC_ALL, ""); + wxUpdateLocaleIsUtf8(); } #endif diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 7f92290966..f8129005d8 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -1600,10 +1600,14 @@ bool wxLocale::Init(const wxString& name, #if defined(__UNIX__) && wxUSE_UNICODE && !defined(__WXMAC__) -static wxWCharBuffer wxSetlocaleTryUTF(int c, const wxChar *lc) +static wxWCharBuffer wxSetlocaleTryUTF8(int c, const wxChar *lc) { - wxMB2WXbuf l = wxSetlocale(c, lc); - if ( !l && lc && lc[0] != 0 ) + wxMB2WXbuf l; + + // NB: We prefer to set UTF-8 locale if it's possible and only fall back to + // non-UTF-8 locale if it fails + + if ( lc && lc[0] != 0 ) { wxString buf(lc); wxString buf2; @@ -1625,10 +1629,15 @@ static wxWCharBuffer wxSetlocaleTryUTF(int c, const wxChar *lc) l = wxSetlocale(c, buf2.c_str()); } } + + // if we can't set UTF-8 locale, try non-UTF-8 one: + if ( !l ) + l = wxSetlocale(c, lc); + return l; } #else -#define wxSetlocaleTryUTF(c, lc) wxSetlocale(c, lc) +#define wxSetlocaleTryUTF8(c, lc) wxSetlocale(c, lc) #endif bool wxLocale::Init(int language, int flags) @@ -1666,13 +1675,13 @@ bool wxLocale::Init(int language, int flags) if (language != wxLANGUAGE_DEFAULT) locale = info->CanonicalName; - wxMB2WXbuf retloc = wxSetlocaleTryUTF(LC_ALL, locale); + wxMB2WXbuf retloc = wxSetlocaleTryUTF8(LC_ALL, locale); const wxString langOnly = locale.Left(2); if ( !retloc ) { // Some C libraries don't like xx_YY form and require xx only - retloc = wxSetlocaleTryUTF(LC_ALL, langOnly); + retloc = wxSetlocaleTryUTF8(LC_ALL, langOnly); } #if wxUSE_FONTMAP @@ -1713,9 +1722,9 @@ bool wxLocale::Init(int language, int flags) if ( !localeAlt.empty() ) { - retloc = wxSetlocaleTryUTF(LC_ALL, localeAlt); + retloc = wxSetlocaleTryUTF8(LC_ALL, localeAlt); if ( !retloc ) - retloc = wxSetlocaleTryUTF(LC_ALL, localeAlt.Left(2)); + retloc = wxSetlocaleTryUTF8(LC_ALL, localeAlt.Left(2)); } } @@ -2741,11 +2750,11 @@ bool wxLocale::IsAvailable(int lang) // Test if setting the locale works, then set it back. wxMB2WXbuf oldLocale = wxSetlocale(LC_ALL, wxEmptyString); - wxMB2WXbuf tmp = wxSetlocaleTryUTF(LC_ALL, info->CanonicalName); + wxMB2WXbuf tmp = wxSetlocaleTryUTF8(LC_ALL, info->CanonicalName); if ( !tmp ) { // Some C libraries don't like xx_YY form and require xx only - tmp = wxSetlocaleTryUTF(LC_ALL, info->CanonicalName.Left(2)); + tmp = wxSetlocaleTryUTF8(LC_ALL, info->CanonicalName.Left(2)); if ( !tmp ) return false; } diff --git a/src/common/wxcrt.cpp b/src/common/wxcrt.cpp index 93b509bdb8..3d12a3bee7 100644 --- a/src/common/wxcrt.cpp +++ b/src/common/wxcrt.cpp @@ -804,14 +804,30 @@ int WXDLLEXPORT wxStrnicmp(const wxChar *s1, const wxChar *s2, size_t n) } #endif -#ifndef wxSetlocale -WXDLLEXPORT wxWCharBuffer wxSetlocale(int category, const wxChar *locale) +#ifndef wxSetlocale_ +wxWCharBuffer wxSetlocale_(int category, const wxChar *locale) { char *localeOld = setlocale(category, wxConvLibc.cWX2MB(locale)); return wxWCharBuffer(wxConvLibc.cMB2WC(localeOld)); } -#endif + +wxWCharBuffer wxSetlocale(int category, const wxChar *locale) +{ + wxWCharBuffer rv = wxSetlocale_(category, locale); + if ( rv ) + wxUpdateLocaleIsUtf8(); + return rv; +} +#else // defined(wxSetlocale_) +const wxChar *wxSetlocale(int category, const wxChar *locale) +{ + const wxChar *rv = wxSetlocale_(category, locale); + if ( rv ) + wxUpdateLocaleIsUtf8(); + return rv; +} +#endif // wxSetlocale_ defined or not #if wxUSE_WCHAR_T && !defined(HAVE_WCSLEN) WXDLLEXPORT size_t wxWcslen(const wchar_t *s) @@ -1350,3 +1366,56 @@ int wxRemove(const wxChar *path) } #endif + + +// ---------------------------------------------------------------------------- +// wxLocaleIsUtf8 +// ---------------------------------------------------------------------------- + +#if wxUSE_UNICODE_UTF8 + +#if !wxUSE_UTF8_LOCALE_ONLY +bool wxLocaleIsUtf8 = false; // the safer setting if not known +#endif + +static bool wxIsLocaleUtf8() +{ + // NB: we intentionally don't use wxLocale::GetSystemEncodingName(), + // because a) it may be unavailable in some builds and b) has slightly + // different semantics (default locale instead of current) + +#if defined(HAVE_LANGINFO_H) && defined(CODESET) + // GNU libc provides current character set this way (this conforms to + // Unix98) + const char *charset = nl_langinfo(CODESET); + if ( charset ) + { + // "UTF-8" is used by modern glibc versions, but test other variants + // as well, just in case: + return strcmp(charset, "UTF-8") == 0 || + strcmp(charset, "utf-8") == 0 || + strcmp(charset, "UTF8") == 0 || + strcmp(charset, "utf8") == 0; + } + else // nl_langinfo() failed +#endif + { + // we don't know what charset libc is using, so assume the worst + // to be safe: + return false; + } +} + +void wxUpdateLocaleIsUtf8() +{ +#if wxUSE_UTF8_LOCALE_ONLY + if ( !wxIsLocaleUtf8() ) + { + wxLogFatalError(_T("This program requires UTF-8 locale to run.")); + } +#else // !wxUSE_UTF8_LOCALE_ONLY + wxLocaleIsUtf8 = wxIsLocaleUtf8(); +#endif +} + +#endif // wxUSE_UTF8_LOCALE_ONLY diff --git a/src/gtk/app.cpp b/src/gtk/app.cpp index 464b36b665..14b556b2e5 100644 --- a/src/gtk/app.cpp +++ b/src/gtk/app.cpp @@ -423,6 +423,7 @@ bool wxApp::Initialize(int& argc, wxChar **argv) #else init_result = gtk_init_check( &argcGTK, &argvGTK ); #endif + wxUpdateLocaleIsUtf8(); if ( argcGTK != argc ) { diff --git a/src/gtk/utilsgtk.cpp b/src/gtk/utilsgtk.cpp index c0d0309f95..13bc7c448c 100644 --- a/src/gtk/utilsgtk.cpp +++ b/src/gtk/utilsgtk.cpp @@ -362,6 +362,7 @@ static wxString GetSM() void wxGUIAppTraits::SetLocale() { gtk_set_locale(); + wxUpdateLocaleIsUtf8(); } #endif -- 2.45.2