Re: BUG #4186: set lc_messages does not work - Mailing list pgsql-bugs
From | Hiroshi Inoue |
---|---|
Subject | Re: BUG #4186: set lc_messages does not work |
Date | |
Msg-id | 493BFE54.7050300@tpf.co.jp Whole thread Raw |
In response to | Re: BUG #4186: set lc_messages does not work (Bruce Momjian <bruce@momjian.us>) |
List | pgsql-bugs |
Bruce Momjian wrote: > Tom Lane wrote: >> Magnus Hagander <magnus@hagander.net> writes: >>> Thomas H. wrote: >>>> so at least that explains the "changed" behaviour. nevertheless, >>>> LC_MESSAGES seems to be defunct - with the "locale" folder present, >>>> pg always picks the os' language and ignores the lc_message value. >>> This looks like I can reproduce though, at least on cvs head. Did this >>> work for you in previous versions? >> Maybe we were using a different build of gettext in the previous >> releases, one that didn't look at the same info as the current code? >> >> Anyway the patch mentioned at the start of the thread >> http://archives.postgresql.org/pgsql-patches/2008-02/msg00038.php >> purports to fix this. It doesn't seem to have gotten reviewed >> though. > > Where are we on this? Saito-san and I have been working on this item. The attached patch is for MSVC version and does the following when built under vc8 or later version MSVC. 1. Accepts Windows or ISO style locale name. 2. _putenv the ISO style locale name as LC_MESSAGES environemnt variable so as to be referenced by the gettext library. Note that we have to call _putenv() in msvcrt.dll not in each MSVC version's runtime library msvcrxx.dll. 3. Calls SetThreadLocale() if necessary. The currently used libintl3.dll(0.14.4.1592) seems to need this handling. ISTM it is badly built and ignores the setting of step 2. regards, Hiroshi Inoue Index: pg_locale.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v retrieving revision 1.42 diff -c -c -r1.42 pg_locale.c *** pg_locale.c 23 Sep 2008 09:20:36 -0000 1.42 --- pg_locale.c 7 Dec 2008 15:53:58 -0000 *************** *** 101,112 **** --- 101,303 ---- * LC_XXX variables have been set correctly. (Thank you Perl for making this * kluge necessary.) */ + + #if defined(WIN32) && defined(_MSC_VER) + typedef int (_cdecl *PUTENVPROC)(const char *); + #if defined(LC_MESSAGES) && (_MSC_VER >= 1400) + #define _TYPE_LOCALE_T_AVAILABLE + #include <shlwapi.h> + typedef const char * (_cdecl *NLLOCALENAMEPOSIXPROC)(int, const char *); + + /* + * Never use DLLGETVERSIONPROC typedef'd in Shlwapi.h. + * It's problematic and would cause a crash. + */ + typedef HRESULT (_cdecl *DLLGETVERSIONFUNC)(DLLVERSIONINFO *); + + static char get_lang[64] = ""; + static char get_country[64] = ""; + static LCID glcid = (LCID) -1; + + static BOOL CALLBACK lclist(LPTSTR lcname) + { + static char tmp_country[128] = ""; + DWORD lcid; + char llang[32], lcountry[32]; + + sscanf_s(lcname, "%x", &lcid); + GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME, llang, sizeof(llang)); + if (0 != _stricmp(llang, get_lang)) + return TRUE; + GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME, lcountry, sizeof(lcountry)); + if ('\0' == get_country[0]) + { + if (SUBLANG_DEFAULT == SUBLANGID(LANGIDFROMLCID(lcid))) + { + glcid = lcid; + return FALSE; + } + return TRUE; + } + if (0 == _stricmp(lcountry, get_country)) + { + glcid = lcid; + return FALSE; + } + return TRUE; + } + #endif /* defined(LC_MESSAGES) && (_MSC_VER >= 1400) */ + + /* + * This function can accept Windows or ISO style locale name. + * Calls SetThreadLocale() if neccesary. + * Sets the ISO style LC_MESSAGES environment variable using + * _putenv() in msvcrt.dll which may be referenced by gettext. + * Returns ISO style LC_MESSAGES locale name. + */ + static char *adjust_LC_MESSAGES(const char *locale, char *envbuf, char *new_locale) + { + #ifdef _TYPE_LOCALE_T_AVAILABLE + char *rtn_locale = locale; + bool isClocale = false; + LCID lcid = (LCID) -1; + int usecategory = LC_CTYPE; + _locale_t loct = NULL; + + if (0 == stricmp("c", locale) || + 0 == stricmp("posix", locale)) + isClocale = true; + if (isClocale) + loct = _create_locale(usecategory, "C"); + else + loct = _create_locale(usecategory, locale); + + if (NULL != loct) + { + lcid = loct->locinfo->lc_handle[usecategory]; + if (0 == lcid) + lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); + _free_locale(loct); + } + else + { + char del[16]; + int scount = sscanf_s(locale, "%[^_-.]%[_-.]%[^.]", get_lang, sizeof(get_lang), del, sizeof(del), get_country,sizeof(get_country)); + switch (scount) + { + case 1: + case 2: + get_country[0] = '\0'; + break; + case 3: + if ('.' == del[0]) + get_country[0] = '\0'; + break; + } + glcid = (LCID) -1; + EnumSystemLocales(lclist, LCID_SUPPORTED); + lcid = glcid; + } + if ((LCID) -1 == lcid) + return NULL; + else + { + /* + * Though GNU gettext FAQ says setting the environtment LC_MESSAGES etc variables + * determines the locale used by gettext, it doesn't seem true for 0.14.4.1952 + * binary version of libintl3.dll. To make sure we do a test and set not only the + * LC_MESSAGES variable but also the current thread's locale if the test shows that + * the DLL doesn't follow the specification(FAQ). + */ + static bool initCheck = true, setThread = false, setEnv = true; + HMODULE hModule; + DLLGETVERSIONFUNC DllGetVersion; + + if (initCheck && + NULL != (hModule = LoadLibrary("libintl3.dll")) && + NULL != (DllGetVersion = (DLLGETVERSIONFUNC) GetProcAddress(hModule, "DllGetVersion"))) + { + DLLVERSIONINFO2 dvi; + HRESULT hr; + NLLOCALENAMEPOSIXPROC locale_name_posix; + + dvi.info1.cbSize = sizeof(dvi); + hr = DllGetVersion((DLLVERSIONINFO *) &dvi); + if (SUCCEEDED(hr) && + MAKEDLLVERULL(0, 14, 4, 1952) == dvi.ullVersion && + NULL != (locale_name_posix = (NLLOCALENAMEPOSIXPROC) GetProcAddress(hModule, "_nl_locale_name_posix"))) + { + + /* + * Here we test the DLL's behavior. + * + * Does the function _nl_locale_name_posix() which is + * internally called by gettext() call setlocale()? + */ + if (NULL != locale_name_posix(LC_CTYPE, "ignore_this_value") && + NULL == locale_name_posix(LC_MESSAGES, "ignore_this_value")) + { + setThread = true; + elog(WARNING, "linking a mal-configured libintl3.dll?"); + } + } + } + initCheck = false; + if (NULL != hModule) + FreeLibrary(hModule); + if (setThread) + { + SetThreadLocale(lcid); + } + if (setEnv && !isClocale) + { + char isolang[64], isocrty[64]; + + GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME, isolang, sizeof(isolang)); + GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME, isocrty, sizeof(isocrty)); + snprintf(new_locale, LC_ENV_BUFSIZE - 1, "%s_%s", isolang, isocrty); + rtn_locale = new_locale; + } + } + #endif /* _TYPE_LOCALE_T_AVAILABLE */ + #if (_MSC_VER >= 1300) + { + /* + * Each MSVC version has its own _putenv() in its runtime library msvcrXX.dll. + * We call _putenv() in msvcrt.dll so as to be referenced by GnuWin32 library. + */ + HMODULE hmodule; + static PUTENVPROC putenvFunc = NULL; + + if (NULL == putenvFunc) + { + if (hmodule = GetModuleHandle("msvcrt"), NULL == hmodule) + return NULL; + putenvFunc = (PUTENVPROC)GetProcAddress(hmodule, "_putenv"); + } + if (NULL == putenvFunc) + return NULL; + snprintf(envbuf, LC_ENV_BUFSIZE - 1, "%s=%s", "LC_MESSAGES", rtn_locale); + if (putenvFunc(envbuf)) + return NULL; + /* Refresh msgid pool maintained by gettext? */ + textdomain("postgres"); + } + #endif /* _MSC_VER >= 1300 */ + + return rtn_locale; + } + #endif /* defined(WIN32) && defined(_MSC_VER) */ + char * pg_perm_setlocale(int category, const char *locale) { char *result; const char *envvar; char *envbuf; + #ifdef LC_MESSAGES + char newlocale[128]; + #endif /* LC_MESSAGES */ #ifndef WIN32 result = setlocale(category, locale); *************** *** 147,152 **** --- 338,347 ---- case LC_MESSAGES: envvar = "LC_MESSAGES"; envbuf = lc_messages_envbuf; + #if defined(WIN32) && defined(_MSC_VER) + if (result = adjust_LC_MESSAGES(result, envbuf, newlocale), NULL == result) + return NULL; + #endif /* WIN32 */ break; #endif case LC_MONETARY: *************** *** 165,170 **** --- 360,366 ---- elog(FATAL, "unrecognized LC category: %d", category); envvar = NULL; /* keep compiler quiet */ envbuf = NULL; + return NULL; break; } *************** *** 182,189 **** if (!SetEnvironmentVariable(envvar, result)) return NULL; if (_putenv(envbuf)) ! return NULL; ! #endif return result; } --- 378,385 ---- if (!SetEnvironmentVariable(envvar, result)) return NULL; if (_putenv(envbuf)) ! result = NULL; ! #endif /* WIN32 */ return result; }
pgsql-bugs by date: