This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix libstdc++ usage of __ctype_b/__ctype_to*
- From: Jakub Jelinek <jakub at redhat dot com>
- To: Ulrich Drepper <drepper at redhat dot com>, Roland McGrath <roland at redhat dot com>, bkoz at redhat dot com, pcarlini at unitus dot it
- Cc: libstdc++ at gcc dot gnu dot org, gcc-patches at gcc dot gnu dot org
- Date: Sun, 1 Sep 2002 16:54:40 -0400
- Subject: [PATCH] Fix libstdc++ usage of __ctype_b/__ctype_to*
- References: <20020901022935.E7886@dhcp187.sf.frob.com> <20020901061330.Z7920@devserv.devel.redhat.com> <20020901034451.G7886@dhcp187.sf.frob.com> <20020901065254.B7920@devserv.devel.redhat.com> <20020901040933.I7886@dhcp187.sf.frob.com> <20020901095711.C7920@devserv.devel.redhat.com> <20020901102055.A5791@devserv.devel.redhat.com> <3D724B9A.6050908@redhat.com> <20020901145657.E7920@devserv.devel.redhat.com> <3D726A72.2080106@redhat.com>
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
On Sun, Sep 01, 2002 at 12:28:50PM -0700, Ulrich Drepper wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Jakub Jelinek wrote:
>
> > Well, I don't think it is that clear, since libstdc++-v3's private use
> > of __uselocale will not be in the way and if uselocale(NULL) != LC_GLOBAL_LOCALE,
> > [...]
>
> Let's do this:
>
> revert the changes to the ctype.h headers. Users will see possibly
> incorrect results for th ectype functions if uselocale is used. This is
> temporarily and can easily be worked around by the use of the _l variants.
>
> Once we have __thread support in the exported headers we will provide
> appropriate replacements for __ctype_b etc with will work transparently
> in most cases. Maybe some code in libstdc++ has to change but that's a
> separate issue.
Ok, I finally looked into the standard.
>From what I can read in ISO C++98, ctype<char>::classic_table() is supposed to
return LC_CTYPE __ctype_b mask table for the "C" locale (22.2.1.3.3), ie. my
reading of the source is that the current implementation is wrong.
It should return _S_c_locale->__ctype_b and if newlocale is not
supported it should either play with setlocale, or return its own array.
Returning __ctype_b is correct only if setlocale hasn't been called yet or
last has been called with LC_CTYPE or LC_ALL, "C".
And ctype<char>::ctype(const mask* __table, bool __del, size_t __refs)
constructor looks like it is supposed to use the user provided __table
if non-NULL, otherwise classic_table() (that's just a guess, I actually
couldn't find the exact wording anywhere, but it makes sense
to me, especially in the presence of ctype_byname and
ctype(__c_locale, ...)). So, all in all, I think really nothing has to
change in glibc CVS to make libstdc++-v3 happy (ie. __ctype_b doesn't
really have to be exported as default symver, at least not for
libstdc++-v3).
The following patch (on top of my 2002-08-30 and earlier 2002-09-01
patch) builds with current CVS glibc and passes its testsuite
with the expected:
# of expected passes 408
# of unexpected failures 1
# of unexpected successes 26
Ok to commit?
2002-09-01 Jakub Jelinek <jakub@redhat.com>
* config/os/gnu-linux/bits/ctype_noninline.h
(ctype<char>::classic_table): If _GLIBCPP_C_LOCALE_GNU, return
_S_c_locale->__ctype_b, otherwise temporarily switch to "C" locale
and return __ctype_b.
(ctype<char>::ctype(__c_locale, const mask*, bool, size_t)): If not
_GLIBCPP_C_LOCALE_GNU, temporarily switch to "C" locale and
initialize using __ctype_{b,tolower,toupper}.
(ctype<char>::ctype(const mask*, bool, size_t)): If
_GLIBCPP_C_LOCALE_GNU, initialize using
_S_c_locale->__ctype_{b,tolower,toupper}, otherwise temporarily
switch to "C" locale and initialize using __ctype_{b,tolower,toupper}.
--- libstdc++-v3/config/os/gnu-linux/bits/ctype_noninline.h.jj 2002-04-23 20:30:31.000000000 +0200
+++ libstdc++-v3/config/os/gnu-linux/bits/ctype_noninline.h 2002-09-01 22:32:32.000000000 +0200
@@ -34,16 +34,34 @@
// Information as gleaned from /usr/include/ctype.h
-#if _GLIBCPP_USE_SHADOW_HEADERS
+#if _GLIBCPP_C_LOCALE_GNU
+ const ctype_base::mask*
+ ctype<char>::classic_table() throw()
+ {
+ if (!_S_c_locale)
+ _S_create_c_locale(_S_c_locale, "C");
+ return _S_c_locale->__ctype_b;
+ }
+#else
+# if _GLIBCPP_USE_SHADOW_HEADERS
using _C_legacy::__ctype_toupper;
using _C_legacy::__ctype_tolower;
using _C_legacy::__ctype_b;
-#endif
+# endif
const ctype_base::mask*
ctype<char>::classic_table() throw()
- { return __ctype_b; }
-
+ {
+ const ctype_base::mask* __ret;
+ char* __old = strdup(setlocale(LC_CTYPE, NULL));
+ setlocale(LC_CTYPE, "C");
+ __ret = __ctype_b;
+ setlocale(__old);
+ free(__old);
+ return __ret;
+ }
+#endif
+
#if _GLIBCPP_C_LOCALE_GNU
ctype<char>::ctype(__c_locale __cloc, const mask* __table, bool __del,
size_t __refs)
@@ -57,17 +75,43 @@
#else
ctype<char>::ctype(__c_locale, const mask* __table, bool __del,
size_t __refs)
- : __ctype_abstract_base<char>(__refs), _M_del(__table != 0 && __del),
- _M_toupper(__ctype_toupper), _M_tolower(__ctype_tolower),
- _M_table(__table ? __table : classic_table())
- { _M_c_locale_ctype = _S_c_locale; }
+ : __ctype_abstract_base<char>(__refs), _M_del(__table != 0 && __del)
+ {
+ char* __old=strdup(setlocale(LC_CTYPE, NULL));
+ setlocale(LC_CTYPE, "C");
+ _M_toupper = __ctype_toupper;
+ _M_tolower = __ctype_tolower;
+ _M_table = __table ? __table : __ctype_b;
+ setlocale(__old);
+ free(__old);
+ _M_c_locale_ctype = _S_c_locale;
+ }
#endif
+#if _GLIBCPP_C_LOCALE_GNU
ctype<char>::ctype(const mask* __table, bool __del, size_t __refs) :
- __ctype_abstract_base<char>(__refs), _M_del(__table != 0 && __del),
- _M_toupper(__ctype_toupper), _M_tolower(__ctype_tolower),
- _M_table(__table ? __table : classic_table())
- { _M_c_locale_ctype = _S_c_locale; }
+ __ctype_abstract_base<char>(__refs), _M_del(__table != 0 && __del)
+ {
+ _M_c_locale_ctype = _S_c_locale;
+ _M_toupper = _M_c_locale_ctype->__ctype_toupper;
+ _M_tolower = _M_c_locale_ctype->__ctype_tolower;
+ _M_table = __table ? __table : _M_c_locale_ctype->__ctype_b;
+ }
+#else
+ ctype<char>::ctype(__c_locale, const mask* __table, bool __del,
+ size_t __refs)
+ : __ctype_abstract_base<char>(__refs), _M_del(__table != 0 && __del)
+ {
+ char* __old=strdup(setlocale(LC_CTYPE, NULL));
+ setlocale(LC_CTYPE, "C");
+ _M_toupper = __ctype_toupper;
+ _M_tolower = __ctype_tolower;
+ _M_table = __table ? __table : __ctype_b;
+ setlocale(__old);
+ free(__old);
+ _M_c_locale_ctype = _S_c_locale;
+ }
+#endif
char
ctype<char>::do_toupper(char __c) const
Jakub