+2011-02-11 Bruno Haible <bruno@clisp.org>
+
+ setlocale: Workaround native Windows bug.
+ * lib/setlocale.c (rpl_setlocale): On native Windows, when setlocale
+ succeeds but sets LC_CTYPE to "C", report a failure.
+ * tests/test-setlocale2.sh: New file.
+ * tests/test-setlocale2.c: New file.
+ * modules/setlocale-tests (Files): Add the new files.
+ (Makefile.am): Enable test-setlocale2.sh test.
+ * doc/posix-functions/setlocale.texi: Mention workaround.
+
2011-02-11 Bruno Haible <bruno@clisp.org>
Tests for module 'setlocale'.
ignores the environment variables @code{LC_ALL}, @code{@var{category}}, and
@code{LANG}.
@item
+On Windows platforms (excluding Cygwin), @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.
+@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
names.
@code{setlocale(LC_ALL,NULL)} always returns @code{"C"}.
@item
On Cygwin 1.7.0, only the charset portion of a locale designation is honored.
-@item
-On Windows platforms (excluding Cygwin), @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.
@end itemize
if (setlocale_unixlike (LC_ALL, base_name) == NULL)
goto fail;
+# if (defined _WIN32 || 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
+ && strcmp (setlocale (LC_CTYPE, NULL), "C") == 0)
+ goto fail;
+# endif
for (i = 0; i < sizeof (categories) / sizeof (categories[0]); i++)
{
}
}
else
- return setlocale_single (category, locale);
+ {
+# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+ if (category == LC_ALL && locale != NULL && strchr (locale, '.') != NULL)
+ {
+ char *saved_locale;
+
+ /* Back up the old locale. */
+ saved_locale = setlocale (LC_ALL, NULL);
+ if (saved_locale == NULL)
+ return NULL;
+ saved_locale = strdup (saved_locale);
+ if (saved_locale == NULL)
+ return NULL;
+
+ if (setlocale_unixlike (LC_ALL, 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. */
+ if (strcmp (setlocale (LC_CTYPE, NULL), "C") == 0)
+ {
+ if (saved_locale[0] != '\0') /* don't risk an endless recursion */
+ setlocale (LC_ALL, saved_locale);
+ free (saved_locale);
+ return NULL;
+ }
+
+ /* It was really successful. */
+ free (saved_locale);
+ return setlocale (LC_ALL, NULL);
+ }
+ else
+# endif
+ return setlocale_single (category, locale);
+ }
}
#endif
Files:
tests/test-setlocale1.sh
tests/test-setlocale1.c
+tests/test-setlocale2.sh
+tests/test-setlocale2.c
tests/signature.h
tests/macros.h
m4/locale-fr.m4
gt_LOCALE_ZH_CN
Makefile.am:
-TESTS += test-setlocale1.sh
+TESTS += test-setlocale1.sh test-setlocale2.sh
TESTS_ENVIRONMENT += \
LOCALE_FR='@LOCALE_FR@' \
LOCALE_FR_UTF8='@LOCALE_FR_UTF8@' \
LOCALE_JA='@LOCALE_JA@' \
LOCALE_ZH_CN='@LOCALE_ZH_CN@'
-check_PROGRAMS += test-setlocale1
+check_PROGRAMS += test-setlocale1 test-setlocale2
--- /dev/null
+/* Test of setting the current locale.
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <locale.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+main ()
+{
+ /* Try to set the locale by implicitly looking at the LC_ALL environment
+ variable. */
+ if (setlocale (LC_ALL, "") != NULL)
+ /* It was successful. Check whether LC_CTYPE is non-trivial. */
+ if (strcmp (setlocale (LC_CTYPE, NULL), "C") == 0)
+ {
+ fprintf (stderr, "setlocale did not fail for implicit %s\n",
+ getenv ("LC_ALL"));
+ return 1;
+ }
+
+ /* Reset the locale. */
+ if (setlocale (LC_ALL, "C") == NULL)
+ return 1;
+
+ /* Try to set the locale by explicitly looking at the LC_ALL environment
+ variable. */
+ if (setlocale (LC_ALL, getenv ("LC_ALL")) != NULL)
+ /* It was successful. Check whether LC_CTYPE is non-trivial. */
+ if (strcmp (setlocale (LC_CTYPE, NULL), "C") == 0)
+ {
+ fprintf (stderr, "setlocale did not fail for explicit %s\n",
+ getenv ("LC_ALL"));
+ return 1;
+ }
+
+ return 0;
+}
--- /dev/null
+#!/bin/sh
+
+# Test locale names with likely unsupported encoding in Unix syntax.
+for name in ar_SA.ISO-8859-1 fr_FR.CP1251 zh_TW.GB18030 zh_CN.BIG5; do
+ LC_ALL=$name ./test-setlocale2${EXEEXT} 1 || exit 1
+done
+
+# Test locale names with likely unsupported encoding in native Windows syntax.
+for name in "Arabic_Saudi Arabia.1252" "Arabic_Saudi Arabia.65001" \
+ French_France.65001 Japanese_Japan.65001 Turkish_Turkey.65001 \
+ Chinese_Taiwan.65001 Chinese_China.54936 Chinese_China.65001; do
+ LC_ALL=$name ./test-setlocale2${EXEEXT} 1 || exit 1
+done
+
+exit 0