diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 9e78d09dd..ebe1f7275 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,19 @@ +2009-07-20 Corinna Vinschen + + * wincap.h (wincaps::has_always_all_codepages): New element. + * wincap.cc: Implement above element throughout. + * wchar.h (__sjis_mbtowc): Declare. + (__eucjp_mbtowc): Ditto. + (__gbk_mbtowc): Ditto. + (__kr_mbtowc): Ditto. + (__big5_mbtowc): Ditto. + * syscalls.cc (internal_setlocale): Convert to char * function. + Return parameter by default. Return NULL if request to use a + charset can't be satisfied due to missing codepage support in the + underlying OS. Fix comment. + (setlocale): Store original locale. Restore to original locale if + internal_setlocale returns NULL. + 2009-07-20 Corinna Vinschen * fork.cc (fork): Create local tmp_pathbuf. Explain why. diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 6f2de057a..64d9001e3 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -24,6 +24,7 @@ details. */ #define pwrite __FOO_pwrite #include "winsup.h" +#include "winnls.h" #include "miscfuncs.h" #include #include /* needed for statfs */ @@ -36,6 +37,7 @@ details. */ #include #include #include +#include #include #include #include @@ -4031,32 +4033,61 @@ unlinkat (int dirfd, const char *pathname, int flags) return (flags & AT_REMOVEDIR) ? rmdir (path) : unlink (path); } -static void -internal_setlocale () +static char * +internal_setlocale (char *ret) { - if (*cygheap->locale.charset == 'A') + if (*__locale_charset () == 'A') { cygheap->locale.mbtowc = __utf8_mbtowc; cygheap->locale.wctomb = __utf8_wctomb; } else { + if (!wincap.has_always_all_codepages ()) + { + /* Prior to Windows Vista, many codepages are not installed by + default, or can be deinstalled. The following codepages require + that the respective conversion tables are installed into the OS. + So we check if they are installed and if not, setlocale should + fail. */ + CPINFO cpi; + UINT cp = 0; + if (__mbtowc == __sjis_mbtowc) + cp = 932; + else if (__mbtowc == __eucjp_mbtowc) + cp = 20932; + else if (__mbtowc == __gbk_mbtowc) + cp = 963; + else if (__mbtowc == __kr_mbtowc) + cp = 949; + else if (__mbtowc == __big5_mbtowc) + cp = 950; + if (cp && !GetCPInfo (cp, &cpi) + && GetLastError () == ERROR_INVALID_PARAMETER) + return NULL; + } cygheap->locale.mbtowc = __mbtowc; cygheap->locale.wctomb = __wctomb; } strcpy (cygheap->locale.charset, __locale_charset ()); /* Each setlocale potentially changes the multibyte representation - of the CWD. Therefore we have to rest the CWD's posix path and + of the CWD. Therefore we have to reset the CWD's posix path and reevaluate the next time it's used. */ /* FIXME: Other buffered paths might be affected as well. */ cygheap->cwd.reset_posix (); + return ret; } extern "C" char * setlocale (int category, const char *locale) { + char old[(LC_MESSAGES + 1) * (ENCODING_LEN + 1/*"/"*/ + 1)]; + if (locale && (category == LC_ALL || category == LC_CTYPE) + && !wincap.has_always_all_codepages ()) + stpcpy (old, _setlocale_r (_REENT, category, NULL)); char *ret = _setlocale_r (_REENT, category, locale); - if (ret && locale && (category == LC_ALL || category == LC_CTYPE)) - internal_setlocale (); + if (ret && locale && (category == LC_ALL || category == LC_CTYPE) + && !(ret = internal_setlocale (ret))) + _setlocale_r (_REENT, category, old); return ret; } diff --git a/winsup/cygwin/wchar.h b/winsup/cygwin/wchar.h index fc8eb3858..f989b7d11 100644 --- a/winsup/cygwin/wchar.h +++ b/winsup/cygwin/wchar.h @@ -28,6 +28,11 @@ extern mbtowc_f __ascii_mbtowc; extern mbtowc_f __utf8_mbtowc; extern mbtowc_f __iso_mbtowc; extern mbtowc_f __cp_mbtowc; +extern mbtowc_f __sjis_mbtowc; +extern mbtowc_f __eucjp_mbtowc; +extern mbtowc_f __gbk_mbtowc; +extern mbtowc_f __kr_mbtowc; +extern mbtowc_f __big5_mbtowc; typedef int wctomb_f (struct _reent *, char *, wchar_t, const char *, mbstate_t *); diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc index 774925ec7..84e530d3f 100644 --- a/winsup/cygwin/wincap.cc +++ b/winsup/cygwin/wincap.cc @@ -56,6 +56,7 @@ wincaps wincap_unknown __attribute__((section (".cygwin_dll_common"), shared)) = has_broken_udf:false, has_console_handle_problem:false, has_broken_alloc_console:false, + has_always_all_codepages:false, }; wincaps wincap_nt4 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -94,6 +95,7 @@ wincaps wincap_nt4 __attribute__((section (".cygwin_dll_common"), shared)) = { has_broken_udf:false, has_console_handle_problem:false, has_broken_alloc_console:false, + has_always_all_codepages:false, }; wincaps wincap_nt4sp4 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -132,6 +134,7 @@ wincaps wincap_nt4sp4 __attribute__((section (".cygwin_dll_common"), shared)) = has_broken_udf:false, has_console_handle_problem:false, has_broken_alloc_console:false, + has_always_all_codepages:false, }; wincaps wincap_2000 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -170,6 +173,7 @@ wincaps wincap_2000 __attribute__((section (".cygwin_dll_common"), shared)) = { has_broken_udf:true, has_console_handle_problem:false, has_broken_alloc_console:false, + has_always_all_codepages:false, }; wincaps wincap_2000sp4 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -208,6 +212,7 @@ wincaps wincap_2000sp4 __attribute__((section (".cygwin_dll_common"), shared)) = has_broken_udf:true, has_console_handle_problem:false, has_broken_alloc_console:false, + has_always_all_codepages:false, }; wincaps wincap_xp __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -246,6 +251,7 @@ wincaps wincap_xp __attribute__((section (".cygwin_dll_common"), shared)) = { has_broken_udf:true, has_console_handle_problem:false, has_broken_alloc_console:false, + has_always_all_codepages:false, }; wincaps wincap_xpsp1 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -284,6 +290,7 @@ wincaps wincap_xpsp1 __attribute__((section (".cygwin_dll_common"), shared)) = { has_broken_udf:true, has_console_handle_problem:false, has_broken_alloc_console:false, + has_always_all_codepages:false, }; wincaps wincap_xpsp2 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -322,6 +329,7 @@ wincaps wincap_xpsp2 __attribute__((section (".cygwin_dll_common"), shared)) = { has_broken_udf:true, has_console_handle_problem:false, has_broken_alloc_console:false, + has_always_all_codepages:false, }; wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -360,6 +368,7 @@ wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = { has_broken_udf:true, has_console_handle_problem:false, has_broken_alloc_console:false, + has_always_all_codepages:false, }; wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -398,6 +407,7 @@ wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = { has_broken_udf:false, has_console_handle_problem:false, has_broken_alloc_console:false, + has_always_all_codepages:true, }; wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -436,6 +446,7 @@ wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = { has_broken_udf:false, has_console_handle_problem:true, has_broken_alloc_console:true, + has_always_all_codepages:true, }; wincapc wincap __attribute__((section (".cygwin_dll_common"), shared)); diff --git a/winsup/cygwin/wincap.h b/winsup/cygwin/wincap.h index ed6eaa9c9..74955ff63 100644 --- a/winsup/cygwin/wincap.h +++ b/winsup/cygwin/wincap.h @@ -48,6 +48,7 @@ struct wincaps unsigned has_broken_udf : 1; unsigned has_console_handle_problem : 1; unsigned has_broken_alloc_console : 1; + unsigned has_always_all_codepages : 1; }; class wincapc @@ -102,6 +103,7 @@ public: bool IMPLEMENT (has_broken_udf) bool IMPLEMENT (has_console_handle_problem) bool IMPLEMENT (has_broken_alloc_console) + bool IMPLEMENT (has_always_all_codepages) #undef IMPLEMENT };