1
0
mirror of https://git.savannah.gnu.org/git/gnulib.git synced 2026-10-24 00:48:56 +03:00

wcrtomb: Make consistent with mbrtowc (regression 2016-04-09).

* m4/wcrtomb.m4 (gl_FUNC_WCRTOMB): Require gl_MBRTOWC_C_LOCALE and, if
needed, set REPLACE_WCRTOMB and define MBRTOWC_IN_C_LOCALE_MAYBE_EILSEQ.
* lib/mbrtowc.c (rpl_mbrtowc) [MBRTOWC_IN_C_LOCALE_MAYBE_EILSEQ]: In the
C locale, map 0x80..0xFF to 0xDF80..0xDFFF instead of 0x0080..0x00FF.
* lib/wcrtomb.c: Include hard-locale.h, <locale.h>.
(wcrtomb) [MBRTOWC_IN_C_LOCALE_MAYBE_EILSEQ]: In the C locale, map
0xDF80..0xDFFF to 0x80..0xFF.
* modules/wcrtomb (Depends-on): Add hard-locale.
* tests/test-wcrtomb.c (main): Check that wcrtomb does the inverse of
mbrtowc in the C locale.
This commit is contained in:
Bruno Haible
2026-09-20 16:27:54 +02:00
parent 026ae7f8e5
commit e2c3ad85ed
6 changed files with 62 additions and 5 deletions

View File

@@ -1,3 +1,17 @@
2026-09-20 Bruno Haible <bruno@clisp.org>
wcrtomb: Make consistent with mbrtowc (regression 2016-04-09).
* m4/wcrtomb.m4 (gl_FUNC_WCRTOMB): Require gl_MBRTOWC_C_LOCALE and, if
needed, set REPLACE_WCRTOMB and define MBRTOWC_IN_C_LOCALE_MAYBE_EILSEQ.
* lib/mbrtowc.c (rpl_mbrtowc) [MBRTOWC_IN_C_LOCALE_MAYBE_EILSEQ]: In the
C locale, map 0x80..0xFF to 0xDF80..0xDFFF instead of 0x0080..0x00FF.
* lib/wcrtomb.c: Include hard-locale.h, <locale.h>.
(wcrtomb) [MBRTOWC_IN_C_LOCALE_MAYBE_EILSEQ]: In the C locale, map
0xDF80..0xDFFF to 0x80..0xFF.
* modules/wcrtomb (Depends-on): Add hard-locale.
* tests/test-wcrtomb.c (main): Check that wcrtomb does the inverse of
mbrtowc in the C locale.
2026-09-19 Paul Eggert <eggert@cs.ucla.edu>
Pacify -Waddress on MS-Windows

View File

@@ -78,7 +78,7 @@ mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
# include "localcharset.h"
# include "streq-opt.h"
# if MBRTOWC_IN_C_LOCALE_MAYBE_EILSEQ
# if MBRTOWC_IN_C_LOCALE_MAYBE_EILSEQ /* glibc, Cygwin < 3.5 */
# include "hard-locale.h"
# include <locale.h>
# endif
@@ -342,11 +342,12 @@ rpl_mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
return 0;
# endif
# if MBRTOWC_IN_C_LOCALE_MAYBE_EILSEQ
# if MBRTOWC_IN_C_LOCALE_MAYBE_EILSEQ /* glibc, Cygwin < 3.5 */
/* In the C locale, map 0x80..0xFF to 0xDF80..0xDFFF. */
if ((size_t) -2 <= ret && n != 0 && ! hard_locale (LC_CTYPE))
{
unsigned char uc = *s;
*pwc = uc;
*pwc = 0xDF00 + uc;
return 1;
}
# endif

View File

@@ -23,6 +23,11 @@
#include <errno.h>
#include <stdlib.h>
#if MBRTOWC_IN_C_LOCALE_MAYBE_EILSEQ
# include "hard-locale.h"
# include <locale.h>
#endif
size_t
wcrtomb (char *s, wchar_t wc, mbstate_t *ps)
@@ -38,7 +43,8 @@ wcrtomb (char *s, wchar_t wc, mbstate_t *ps)
#if !HAVE_WCRTOMB /* HP-UX 11.00, mingw */ \
|| WCRTOMB_RETVAL_BUG /* Solaris 11.3, MSVC */ \
|| WCRTOMB_C_LOCALE_BUG /* Android */
|| WCRTOMB_C_LOCALE_BUG /* Android */ \
|| MBRTOWC_IN_C_LOCALE_MAYBE_EILSEQ /* glibc, Cygwin < 3.5 */
if (s == NULL)
/* We know the NUL wide character corresponds to the NUL character. */
return 1;
@@ -60,6 +66,15 @@ wcrtomb (char *s, wchar_t wc, mbstate_t *ps)
return (size_t)(-1);
}
# else
# if MBRTOWC_IN_C_LOCALE_MAYBE_EILSEQ /* glibc, Cygwin < 3.5 */
/* Implement consistently with mbrtowc(): through a 1:1 correspondence,
mapping 0xDF80..0xDFFF back to 0x80..0xFF. */
if (wc >= 0xDF80 && wc <= 0xDFFF && ! hard_locale (LC_CTYPE))
{
*s = (unsigned char) (wc - 0xDF00);
return 1;
}
# endif
return wcrtomb (s, wc, ps);
# endif
#else /* HP-UX 11.00, mingw */

View File

@@ -1,5 +1,5 @@
# wcrtomb.m4
# serial 24
# serial 25
dnl Copyright (C) 2008-2026 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -145,6 +145,15 @@ int main ()
REPLACE_WCRTOMB=1 ;;
esac
fi
dnl When we adjust mbrtowc in the C locale, we need to adjust wcrtomb as well, for consistency.
AC_REQUIRE([gl_MBRTOWC_C_LOCALE])
case "$gl_cv_func_mbrtowc_C_locale_sans_EILSEQ" in
*yes) ;;
*) AC_DEFINE([MBRTOWC_IN_C_LOCALE_MAYBE_EILSEQ], [1],
[Define if the mbrtowc function may signal encoding errors in the C locale.])
REPLACE_WCRTOMB=1
;;
esac
fi
])

View File

@@ -15,6 +15,7 @@ m4/codeset.m4
Depends-on:
wchar-h
extensions
hard-locale [test $HAVE_WCRTOMB = 0 || test $REPLACE_WCRTOMB = 1]
mbsinit [test $HAVE_WCRTOMB = 0 || test $REPLACE_WCRTOMB = 1]
configure.ac:

View File

@@ -114,6 +114,23 @@ main (int argc, char *argv[])
{
case '1':
/* C locale; tested above. */
#if !defined __ANDROID__
/* On Android ≥ 5.0, the default locale is the "C.UTF-8" locale, not the
"C" locale. Furthermore, when you attempt to set the "C" or "POSIX"
locale via setlocale(), what you get is a "C" locale with UTF-8
encoding, that is, effectively the "C.UTF-8" locale. */
/* Check that wcrtomb does the inverse of mbrtowc, in the C locale.
Recall that POSIX:2024 says about mbrtowc:
"In the POSIX locale an [EILSEQ] error cannot occur since all
byte values are valid characters."
Above we have only tested the ISO C "basic character set". */
for (int c = 0; c < 0x100; c++)
{
ret = wcrtomb (buf, btowc (c), NULL);
ASSERT (ret == 1);
ASSERT (buf[0] == (char) c);
}
#endif
return test_exit_status;
case '2':