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
This commit is contained in:
Václav Slavík
2007-04-23 20:42:13 +00:00
parent 1e085eeb89
commit cb352236d9
7 changed files with 126 additions and 20 deletions

View File

@@ -190,6 +190,14 @@
/* depending on the platform, Unicode build can either store wxStrings as /* depending on the platform, Unicode build can either store wxStrings as
wchar_t* or UTF-8 encoded char*: */ wchar_t* or UTF-8 encoded char*: */
#if wxUSE_UNICODE #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 #ifndef wxUSE_UNICODE_UTF8
#define wxUSE_UNICODE_UTF8 0 #define wxUSE_UNICODE_UTF8 0
#endif #endif

View File

@@ -19,6 +19,20 @@
#include <stdio.h> /* we use FILE below */ #include <stdio.h> /* 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 #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 **); char *strtok_r(char *, const char *, char **);
#endif #endif
@@ -99,7 +113,7 @@
#define wxToupper(c) _totupper((wxUChar)(wxChar)(c)) #define wxToupper(c) _totupper((wxUChar)(wxChar)(c))
/* locale.h functons */ /* locale.h functons */
#define wxSetlocale _tsetlocale #define wxSetlocale_ _tsetlocale
/* string.h functions */ /* string.h functions */
#define wxStrcat _tcscat #define wxStrcat _tcscat
@@ -476,7 +490,7 @@
#define wxToupper toupper #define wxToupper toupper
/* locale.h functons */ /* locale.h functons */
#define wxSetlocale setlocale #define wxSetlocale_ setlocale
/* string.h functions */ /* string.h functions */
#define wxStrcat strcat #define wxStrcat strcat
@@ -772,11 +786,14 @@ WXDLLIMPEXP_BASE wxChar * wxStrtok(wxChar *psz, const wxChar *delim, wxChar **sa
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
#ifndef wxSetlocale #ifndef wxSetlocale_
class WXDLLIMPEXP_BASE wxWCharBuffer; class WXDLLIMPEXP_BASE wxWCharBuffer;
WXDLLIMPEXP_BASE wxWCharBuffer wxSetlocale(int category, const wxChar *locale); WXDLLIMPEXP_BASE wxWCharBuffer wxSetlocale_(int category, const wxChar *locale);
#endif WXDLLIMPEXP_BASE wxWCharBuffer wxSetlocale(int category, const wxChar *locale);
#endif #else
WXDLLIMPEXP_BASE const wxChar *wxSetlocale(int category, const wxChar *locale);
#endif // defined(wxSetlocale_)
#endif // __cplusplus
/* stdio.h functions */ /* stdio.h functions */
#ifdef wxNEED_WX_STDIO_H #ifdef wxNEED_WX_STDIO_H

View File

@@ -513,6 +513,7 @@ GSocketGUIFunctionsTable* wxConsoleAppTraitsBase::GetSocketGUIFunctionsTable()
void wxAppTraitsBase::SetLocale() void wxAppTraitsBase::SetLocale()
{ {
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
wxUpdateLocaleIsUtf8();
} }
#endif #endif

View File

@@ -1600,10 +1600,14 @@ bool wxLocale::Init(const wxString& name,
#if defined(__UNIX__) && wxUSE_UNICODE && !defined(__WXMAC__) #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); wxMB2WXbuf l;
if ( !l && lc && lc[0] != 0 )
// 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 buf(lc);
wxString buf2; wxString buf2;
@@ -1625,10 +1629,15 @@ static wxWCharBuffer wxSetlocaleTryUTF(int c, const wxChar *lc)
l = wxSetlocale(c, buf2.c_str()); 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; return l;
} }
#else #else
#define wxSetlocaleTryUTF(c, lc) wxSetlocale(c, lc) #define wxSetlocaleTryUTF8(c, lc) wxSetlocale(c, lc)
#endif #endif
bool wxLocale::Init(int language, int flags) bool wxLocale::Init(int language, int flags)
@@ -1666,13 +1675,13 @@ bool wxLocale::Init(int language, int flags)
if (language != wxLANGUAGE_DEFAULT) if (language != wxLANGUAGE_DEFAULT)
locale = info->CanonicalName; locale = info->CanonicalName;
wxMB2WXbuf retloc = wxSetlocaleTryUTF(LC_ALL, locale); wxMB2WXbuf retloc = wxSetlocaleTryUTF8(LC_ALL, locale);
const wxString langOnly = locale.Left(2); const wxString langOnly = locale.Left(2);
if ( !retloc ) if ( !retloc )
{ {
// Some C libraries don't like xx_YY form and require xx only // 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 #if wxUSE_FONTMAP
@@ -1713,9 +1722,9 @@ bool wxLocale::Init(int language, int flags)
if ( !localeAlt.empty() ) if ( !localeAlt.empty() )
{ {
retloc = wxSetlocaleTryUTF(LC_ALL, localeAlt); retloc = wxSetlocaleTryUTF8(LC_ALL, localeAlt);
if ( !retloc ) 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. // Test if setting the locale works, then set it back.
wxMB2WXbuf oldLocale = wxSetlocale(LC_ALL, wxEmptyString); wxMB2WXbuf oldLocale = wxSetlocale(LC_ALL, wxEmptyString);
wxMB2WXbuf tmp = wxSetlocaleTryUTF(LC_ALL, info->CanonicalName); wxMB2WXbuf tmp = wxSetlocaleTryUTF8(LC_ALL, info->CanonicalName);
if ( !tmp ) if ( !tmp )
{ {
// Some C libraries don't like xx_YY form and require xx only // 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 ) if ( !tmp )
return false; return false;
} }

View File

@@ -804,14 +804,30 @@ int WXDLLEXPORT wxStrnicmp(const wxChar *s1, const wxChar *s2, size_t n)
} }
#endif #endif
#ifndef wxSetlocale #ifndef wxSetlocale_
WXDLLEXPORT wxWCharBuffer wxSetlocale(int category, const wxChar *locale) wxWCharBuffer wxSetlocale_(int category, const wxChar *locale)
{ {
char *localeOld = setlocale(category, wxConvLibc.cWX2MB(locale)); char *localeOld = setlocale(category, wxConvLibc.cWX2MB(locale));
return wxWCharBuffer(wxConvLibc.cMB2WC(localeOld)); 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) #if wxUSE_WCHAR_T && !defined(HAVE_WCSLEN)
WXDLLEXPORT size_t wxWcslen(const wchar_t *s) WXDLLEXPORT size_t wxWcslen(const wchar_t *s)
@@ -1350,3 +1366,56 @@ int wxRemove(const wxChar *path)
} }
#endif #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

View File

@@ -423,6 +423,7 @@ bool wxApp::Initialize(int& argc, wxChar **argv)
#else #else
init_result = gtk_init_check( &argcGTK, &argvGTK ); init_result = gtk_init_check( &argcGTK, &argvGTK );
#endif #endif
wxUpdateLocaleIsUtf8();
if ( argcGTK != argc ) if ( argcGTK != argc )
{ {

View File

@@ -362,6 +362,7 @@ static wxString GetSM()
void wxGUIAppTraits::SetLocale() void wxGUIAppTraits::SetLocale()
{ {
gtk_set_locale(); gtk_set_locale();
wxUpdateLocaleIsUtf8();
} }
#endif #endif