@@ -1,4 +1,5 @@
/* Copyright (C) 1996-2022 Free Software Foundation, Inc.
+ Copyright The GNU Toolchain Authors.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -97,6 +98,30 @@ valid_locale_name (const char *name)
return 1;
}
+/* Return true if we have gconv modules to transform between the INTERNAL
+ encoding and CODESET. */
+static bool
+codeset_has_module (const char *codeset)
+{
+ struct __gconv_step *steps;
+ size_t nsteps;
+
+ char *ccodeset = (char *) alloca (strlen (codeset) + 3);
+ strip (ccodeset, codeset);
+
+ if (__gconv_find_transform ("INTERNAL", ccodeset, &steps, &nsteps, 0)
+ != __GCONV_OK)
+ return false;
+ __gconv_close_transform (steps, nsteps);
+
+ if (__gconv_find_transform (ccodeset, "INTERNAL", &steps, &nsteps, 0)
+ != __GCONV_OK)
+ return false;
+ __gconv_close_transform (steps, nsteps);
+
+ return true;
+}
+
struct __locale_data *
_nl_find_locale (const char *locale_path, size_t locale_path_len,
int category, const char **name)
@@ -199,6 +224,10 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
/* Memory allocate problem. */
return NULL;
+ /* The requested codeset does not have a converter, don't use it. */
+ if (codeset != NULL && !codeset_has_module (codeset))
+ return NULL;
+
/* If exactly this locale was already asked for we have an entry with
the complete name. */
locale_file = _nl_make_l10nflist (&_nl_locale_file_list[category],
@@ -247,6 +276,33 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
return NULL;
}
+ /* Get the codeset information from the locale file. */
+ static const int codeset_idx[] =
+ {
+ [__LC_CTYPE] = _NL_ITEM_INDEX (CODESET),
+ [__LC_NUMERIC] = _NL_ITEM_INDEX (_NL_NUMERIC_CODESET),
+ [__LC_TIME] = _NL_ITEM_INDEX (_NL_TIME_CODESET),
+ [__LC_COLLATE] = _NL_ITEM_INDEX (_NL_COLLATE_CODESET),
+ [__LC_MONETARY] = _NL_ITEM_INDEX (_NL_MONETARY_CODESET),
+ [__LC_MESSAGES] = _NL_ITEM_INDEX (_NL_MESSAGES_CODESET),
+ [__LC_PAPER] = _NL_ITEM_INDEX (_NL_PAPER_CODESET),
+ [__LC_NAME] = _NL_ITEM_INDEX (_NL_NAME_CODESET),
+ [__LC_ADDRESS] = _NL_ITEM_INDEX (_NL_ADDRESS_CODESET),
+ [__LC_TELEPHONE] = _NL_ITEM_INDEX (_NL_TELEPHONE_CODESET),
+ [__LC_MEASUREMENT] = _NL_ITEM_INDEX (_NL_MEASUREMENT_CODESET),
+ [__LC_IDENTIFICATION] = _NL_ITEM_INDEX (_NL_IDENTIFICATION_CODESET)
+ };
+ const struct __locale_data *data;
+ const char *locale_codeset;
+
+ data = (const struct __locale_data *) locale_file->data;
+ locale_codeset = (const char *) data->values[codeset_idx[category]].string;
+ assert (locale_codeset != NULL);
+
+ /* The locale codeset does not have a converter, don't use it. */
+ if (locale_codeset[0] != '\0' && !codeset_has_module (locale_codeset))
+ return NULL;
+
/* The LC_CTYPE category allows to check whether a locale is really
usable. If the locale name contains a charset name and the
charset name used in the locale (present in the LC_CTYPE data) is
@@ -255,31 +311,9 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
in the locale name. */
if (codeset != NULL)
{
- /* Get the codeset information from the locale file. */
- static const int codeset_idx[] =
- {
- [__LC_CTYPE] = _NL_ITEM_INDEX (CODESET),
- [__LC_NUMERIC] = _NL_ITEM_INDEX (_NL_NUMERIC_CODESET),
- [__LC_TIME] = _NL_ITEM_INDEX (_NL_TIME_CODESET),
- [__LC_COLLATE] = _NL_ITEM_INDEX (_NL_COLLATE_CODESET),
- [__LC_MONETARY] = _NL_ITEM_INDEX (_NL_MONETARY_CODESET),
- [__LC_MESSAGES] = _NL_ITEM_INDEX (_NL_MESSAGES_CODESET),
- [__LC_PAPER] = _NL_ITEM_INDEX (_NL_PAPER_CODESET),
- [__LC_NAME] = _NL_ITEM_INDEX (_NL_NAME_CODESET),
- [__LC_ADDRESS] = _NL_ITEM_INDEX (_NL_ADDRESS_CODESET),
- [__LC_TELEPHONE] = _NL_ITEM_INDEX (_NL_TELEPHONE_CODESET),
- [__LC_MEASUREMENT] = _NL_ITEM_INDEX (_NL_MEASUREMENT_CODESET),
- [__LC_IDENTIFICATION] = _NL_ITEM_INDEX (_NL_IDENTIFICATION_CODESET)
- };
- const struct __locale_data *data;
- const char *locale_codeset;
char *clocale_codeset;
char *ccodeset;
- data = (const struct __locale_data *) locale_file->data;
- locale_codeset =
- (const char *) data->values[codeset_idx[category]].string;
- assert (locale_codeset != NULL);
/* Note the length of the allocated memory: +3 for up to two slashes
and the NUL byte. */
clocale_codeset = (char *) alloca (strlen (locale_codeset) + 3);
@@ -125,11 +125,13 @@ test-input := \
test-input-data = $(addsuffix .in, $(test-input))
test-output := $(foreach s, .out .xout, \
$(addsuffix $s, $(basename $(test-input))))
+# Note that tst-invalid-charset depends on test5 and test6 being locales that
+# do not have valid charset converters.
ld-test-names := test1 test2 test3 test4 test5 test6 test7
ld-test-srcs := $(addprefix tests/,$(addsuffix .cm,$(ld-test-names)) \
$(addsuffix .def,$(ld-test-names)) \
$(addsuffix .ds,test5 test6) \
- test6.c trans.def)
+ trans.def)
fmon-tests = n01y12 n02n40 n10y31 n11y41 n12y11 n20n32 n30y20 n41n00 \
y01y10 y02n22 y22n42 y30y21 y32n31 y40y00 y42n21
@@ -163,6 +165,7 @@ tests = \
tst-c-utf8-consistency \
tst-digits \
tst-iconv-math-trans \
+ tst-invalid-charset \
tst-leaks \
tst-mbswcs1 \
tst-mbswcs2 \
@@ -423,7 +426,10 @@ $(objpfx)tst-langinfo-setlocale-static.out: tst-langinfo.sh \
'$(run-program-env)' '$(test-program-cmd-after-env)' > $@; \
$(evaluate-test)
+# These tests depend on tst-locale because they use the locales compiled by
+# that test.
$(objpfx)tst-digits.out: $(objpfx)tst-locale.out
+$(objpfx)tst-invalid-charset.out: $(objpfx)tst-locale.out
$(objpfx)tst-mbswcs6.out: $(addprefix $(objpfx),$(CTYPE_FILES))
endif
@@ -484,7 +490,8 @@ $(objpfx)mtrace-tst-leaks.out: $(objpfx)tst-leaks.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-leaks.mtrace > $@; \
$(evaluate-test)
-bug-setlocale1-ENV-only = LOCPATH=$(objpfx) LC_CTYPE=de_DE.UTF-8
+bug-setlocale1-ENV-only = GCONV_PATH=$(common-objpfx)iconvdata \
+ LOCPATH=$(objpfx) LC_CTYPE=de_DE.UTF-8
bug-setlocale1-static-ENV-only = $(bug-setlocale1-ENV-only)
$(objdir)/iconvdata/gconv-modules:
deleted file mode 100644
@@ -1,136 +0,0 @@
-/* Test program for character classes and mappings.
- Copyright (C) 1999-2022 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library 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
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <https://www.gnu.org/licenses/>. */
-
-#include <ctype.h>
-#include <locale.h>
-#include <wchar.h>
-
-
-int
-main (void)
-{
- const char lower[] = "abcdefghijklmnopqrstuvwxyz";
- const char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-#define LEN (sizeof (upper) - 1)
- const wchar_t wlower[] = L"abcdefghijklmnopqrstuvwxyz";
- const wchar_t wupper[] = L"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- int i;
- int result = 0;
-
- setlocale (LC_ALL, "test6");
-
- for (i = 0; i < LEN; ++i)
- {
- /* Test basic table handling (basic == not more than 256 characters).
- The charmaps swaps the normal lower-upper case meaning of the
- ASCII characters used in the source code while the Unicode mapping
- in the repertoire map has the normal correspondents. This test
- shows the independence of the tables for `char' and `wchar_t'
- characters. */
-
- if (islower (lower[i]))
- {
- printf ("islower ('%c') false\n", lower[i]);
- result = 1;
- }
- if (! isupper (lower[i]))
- {
- printf ("isupper ('%c') false\n", lower[i]);
- result = 1;
- }
-
- if (! islower (upper[i]))
- {
- printf ("islower ('%c') false\n", upper[i]);
- result = 1;
- }
- if (isupper (upper[i]))
- {
- printf ("isupper ('%c') false\n", upper[i]);
- result = 1;
- }
-
- if (toupper (lower[i]) != lower[i])
- {
- printf ("toupper ('%c') false\n", lower[i]);
- result = 1;
- }
- if (tolower (lower[i]) != upper[i])
- {
- printf ("tolower ('%c') false\n", lower[i]);
- result = 1;
- }
-
- if (tolower (upper[i]) != upper[i])
- {
- printf ("tolower ('%c') false\n", upper[i]);
- result = 1;
- }
- if (toupper (upper[i]) != lower[i])
- {
- printf ("toupper ('%c') false\n", upper[i]);
- result = 1;
- }
-
- if (iswlower (wupper[i]))
- {
- printf ("iswlower (L'%c') false\n", upper[i]);
- result = 1;
- }
- if (! iswupper (wupper[i]))
- {
- printf ("iswupper (L'%c') false\n", upper[i]);
- result = 1;
- }
-
- if (iswupper (wlower[i]))
- {
- printf ("iswupper (L'%c') false\n", lower[i]);
- result = 1;
- }
- if (! iswlower (wlower[i]))
- {
- printf ("iswlower (L'%c') false\n", lower[i]);
- result = 1;
- }
-
- if (towupper (wlower[i]) != wupper[i])
- {
- printf ("towupper ('%c') false\n", lower[i]);
- result = 1;
- }
- if (towlower (wlower[i]) != wlower[i])
- {
- printf ("towlower ('%c') false\n", lower[i]);
- result = 1;
- }
-
- if (towlower (wupper[i]) != wlower[i])
- {
- printf ("towlower ('%c') false\n", upper[i]);
- result = 1;
- }
- if (towupper (wupper[i]) != wupper[i])
- {
- printf ("towupper ('%c') false\n", upper[i]);
- result = 1;
- }
- }
-
- return result;
-}
new file mode 100644
@@ -0,0 +1,31 @@
+/* Test program to verify that setlocale fails for charsets that do not have a
+ converter.
+ Copyright The GNU Toolchain Authors.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <ctype.h>
+#include <locale.h>
+#include <wchar.h>
+
+
+int
+main (void)
+{
+ /* Fail if setlocale succeeds for any of these locales. */
+ return (setlocale (LC_ALL, "test5") != NULL
+ || setlocale (LC_ALL, "test6") != NULL);
+}