Re: Incorrect information about setlocale behavior on native windows
Paul Eggert <[email protected]>
| Newsgroups | gmane.comp.lib.gnulib.bugs |
|---|---|
| Organization | UCLA Computer Science Department |
| Message-ID | <[email protected]> |
On 2026-08-21 01:14, Kirill Makurin wrote: > I believe that original impression of setting LC_CTYPE to "C" comes from "C" being the active locale before problematic `setlocale` call. Are you suggesting something like the attached patch to Gnulib? If not, what would be a better patch? Is it possible that sometimes setlocale leaves LC_CTYPE alone, and sometimes sets it to "C"? If so, the attached code patch would handle either case, but the documentation patch would need changing. I have not installed the attached patch, as I don't use MS-Windows and can't easily test it, and it's not obviously OK.
0001-setlocale-port-better-to-MS-Windows.patch
(text/x-patch, 5.5 KB)
From 85471114b8e46f200afb94b532f26a58cdfbc05c Mon Sep 17 00:00:00 2001 From: Paul Eggert <[email protected]> Date: Fri, 21 Aug 2026 09:44:22 -0700 Subject: [PATCH] setlocale: port better to MS-Windows Problem reported by Kirill Makurin in: https://lists.gnu.org/r/bug-gnulib/2026-08/msg00247.html * lib/setlocale.c (setlocale_improved): When setlocale(LC_ALL,...) misbehaves on MS-Windows, it can leave LC_CTYPE alone, instead of setting it to "C". --- ChangeLog | 9 ++++++++ doc/posix-functions/setlocale.texi | 4 ++-- lib/setlocale.c | 36 +++++++++++++++++++++--------- modules/setlocale | 1 + 4 files changed, 38 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index 44345023a7..6cc55b7015 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2026-08-21 Paul Eggert <[email protected]> + + setlocale: port better to MS-Windows + Problem reported by Kirill Makurin in: + https://lists.gnu.org/r/bug-gnulib/2026-08/msg00247.html + * lib/setlocale.c (setlocale_improved): + When setlocale(LC_ALL,...) misbehaves on MS-Windows, it + can leave LC_CTYPE alone, instead of setting it to "C". + 2026-08-21 Bruno Haible <[email protected]> getugroups: Clarify and optimize. diff --git a/doc/posix-functions/setlocale.texi b/doc/posix-functions/setlocale.texi index 25f8a9500a..3426dabe25 100644 --- a/doc/posix-functions/setlocale.texi +++ b/doc/posix-functions/setlocale.texi @@ -16,8 +16,8 @@ and @code{setlocale(@var{category},NULL)} both ignore the environment variables @code{LC_ALL}, @code{@var{category}}, and @code{LANG}. @item On Windows platforms (excluding Cygwin) and Cygwin 1.5.x, -@code{setlocale(LC_ALL,@var{name})} succeeds and sets the LC_CTYPE category to -@samp{C} when it does not support the encoding, instead of failing. +when an encoding is not supported @code{setlocale(LC_ALL,@var{name})} +succeeds without changing the LC_CTYPE category, instead of failing. @item On Windows platforms (excluding Cygwin), @code{setlocale} understands different locale names, that are not based on ISO 639 language names and ISO 3166 country diff --git a/lib/setlocale.c b/lib/setlocale.c index f40b6295d4..93322672bd 100644 --- a/lib/setlocale.c +++ b/lib/setlocale.c @@ -1452,6 +1452,19 @@ setlocale_improved (int category, const char *locale) if (base_name == NULL) base_name = gl_locale_name_default (); +# if defined _WIN32 && ! defined __CYGWIN__ + /* On native Windows, setlocale(LC_ALL,...) may succeed but + leave the LC_CTYPE category unchanged when it does not + support the specified encoding. To detect this below, + temporarily set the LC_CTYPE category to "C" first. */ + bool dotted_locale = strchr (base_name, '.') != NULL; + if (dotted_locale && setlocale (LC_CTYPE, "C") == NULL) + { + free (saved_locale); + return NULL; + } +# endif + unsigned int i; if (setlocale_unixlike (LC_ALL, base_name) != NULL) { @@ -1469,11 +1482,10 @@ setlocale_improved (int category, const char *locale) i = 0; } # if defined _WIN32 && ! defined __CYGWIN__ - /* On native Windows, setlocale(LC_ALL,...) may succeed but set the - LC_CTYPE category to an invalid value ("C") when it does not - support the specified encoding. Report a failure instead. */ - if (strchr (base_name, '.') != NULL - && streq (setlocale (LC_CTYPE, NULL), "C")) + /* Report a failure if setlocale(LC_ALL,...) succeeded but + left the LC_CTYPE category unchanged because it does not + support the specified encoding. */ + if (dotted_locale && streq (setlocale (LC_CTYPE, NULL), "C")) goto fail; # endif @@ -1685,16 +1697,20 @@ setlocale_improved (int category, const char *locale) if (saved_locale == NULL) return NULL; - if (setlocale_unixlike (LC_ALL, native_locale) == NULL) + /* On native Windows, setlocale(LC_ALL,...) may succeed but + leave the LC_CTYPE category unchanged when it does not + support the specified encoding. To detect this below, + temporarily set the LC_CTYPE category to "C" first. */ + if (setlocale (LC_CTYPE, "C") == NULL + || setlocale_unixlike (LC_ALL, native_locale) == NULL) { free (saved_locale); return NULL; } - /* On native Windows, setlocale(LC_ALL,...) may succeed but - set the LC_CTYPE category to an invalid value ("C") when - it does not support the specified encoding. Report a - failure instead. */ + /* Report a failure if setlocale(LC_ALL,...) succeeded but + left the LC_CTYPE category unchanged because it does not + support the specified encoding. */ if (streq (setlocale (LC_CTYPE, NULL), "C")) { /* Don't risk an endless recursion. */ diff --git a/modules/setlocale b/modules/setlocale index aff365ac95..76b7dd3c95 100644 --- a/modules/setlocale +++ b/modules/setlocale @@ -6,6 +6,7 @@ lib/setlocale.c m4/setlocale.m4 Depends-on: +bool locale-h stdcountof-h streq -- 2.53.0