diff options
author | Corinna Vinschen <corinna@vinschen.de> | 2009-07-20 15:44:55 +0000 |
---|---|---|
committer | Corinna Vinschen <corinna@vinschen.de> | 2009-07-20 15:44:55 +0000 |
commit | 20fc2f493621f1f159bbea354e32a1d30b5f428a (patch) | |
tree | a0943ce4f47141ac69bde03caf8085ed2353ea30 /winsup/cygwin/syscalls.cc | |
parent | cb8ee36ae8a617fc6fddc36d4c2e76e7593d2765 (diff) | |
download | cygnal-20fc2f493621f1f159bbea354e32a1d30b5f428a.tar.gz cygnal-20fc2f493621f1f159bbea354e32a1d30b5f428a.tar.bz2 cygnal-20fc2f493621f1f159bbea354e32a1d30b5f428a.zip |
* 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.
Diffstat (limited to 'winsup/cygwin/syscalls.cc')
-rw-r--r-- | winsup/cygwin/syscalls.cc | 43 |
1 files changed, 37 insertions, 6 deletions
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 <sys/stat.h> #include <sys/vfs.h> /* needed for statfs */ @@ -36,6 +37,7 @@ details. */ #include <sys/uio.h> #include <ctype.h> #include <locale.h> +#include <wchar.h> #include <unistd.h> #include <sys/wait.h> #include <rpc.h> @@ -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; } |