From 555ed22ddc6df16f3e848de4c5534b97c1ddd32c Mon Sep 17 00:00:00 2001 From: Bruno Haible <bruno@clisp.org> Date: Fri, 25 Jan 2019 23:39:28 +0100 Subject: [PATCH] wcrtomb: Work around bug on Android 4.3. * m4/wcrtomb.m4 (gl_FUNC_WCRTOMB): Test also whether wcrtomb works in the C locale. * lib/wcrtomb.c (wcrtomb): Provide alternate implementation for Android, which does not have the 'wctomb' function. * doc/posix-functions/wcrtomb.texi: Mention the Android bug. * tests/test-wcrtomb.c (main): Accept argument '5'. * tests/test-wcrtomb.sh: Add tests in the POSIX locale. --- ChangeLog | 11 ++++++++ doc/posix-functions/wcrtomb.texi | 3 +++ lib/wcrtomb.c | 15 +++++++++-- m4/wcrtomb.m4 | 45 ++++++++++++++++++++++++++++++-- tests/test-wcrtomb.c | 4 +++ tests/test-wcrtomb.sh | 4 +++ 6 files changed, 78 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index a47fb01e43..5332fd738a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2019-01-25 Bruno Haible <bruno@clisp.org> + + wcrtomb: Work around bug on Android 4.3. + * m4/wcrtomb.m4 (gl_FUNC_WCRTOMB): Test also whether wcrtomb works in + the C locale. + * lib/wcrtomb.c (wcrtomb): Provide alternate implementation for Android, + which does not have the 'wctomb' function. + * doc/posix-functions/wcrtomb.texi: Mention the Android bug. + * tests/test-wcrtomb.c (main): Accept argument '5'. + * tests/test-wcrtomb.sh: Add tests in the POSIX locale. + 2019-01-25 Bruno Haible <bruno@clisp.org> setlocale: Work around bug on Android 4.3. diff --git a/doc/posix-functions/wcrtomb.texi b/doc/posix-functions/wcrtomb.texi index e3e7b5752c..4bdc50e772 100644 --- a/doc/posix-functions/wcrtomb.texi +++ b/doc/posix-functions/wcrtomb.texi @@ -12,6 +12,9 @@ Portability problems fixed by Gnulib: This function is missing on some platforms: Minix 3.1.8, HP-UX 11.00, IRIX 6.5, Solaris 2.6, mingw, Interix 3.5. @item +This function produces wrong characters in the C locale on some platforms: +Android 4.3. +@item This function returns 0 when the first argument is NULL in some locales on some platforms: AIX 4.3, OSF/1 5.1, Solaris 11.3. @end itemize diff --git a/lib/wcrtomb.c b/lib/wcrtomb.c index 9fc40cfc9e..8e56732bd4 100644 --- a/lib/wcrtomb.c +++ b/lib/wcrtomb.c @@ -27,8 +27,8 @@ size_t wcrtomb (char *s, wchar_t wc, mbstate_t *ps) { - /* This implementation of wcrtomb on top of wctomb() supports only - stateless encodings. ps must be in the initial state. */ + /* This implementation of wcrtomb supports only stateless encodings. + ps must be in the initial state. */ if (ps != NULL && !mbsinit (ps)) { errno = EINVAL; @@ -40,10 +40,21 @@ wcrtomb (char *s, wchar_t wc, mbstate_t *ps) return 1; else { +#if defined __ANDROID__ + /* Implement consistently with mbrtowc(): through a 1:1 correspondence, + as in ISO-8859-1. */ + if (wc >= 0 && wc <= 0xff) + { + *s = (unsigned char) wc; + return 1; + } +#else + /* Implement on top of wctomb(). */ int ret = wctomb (s, wc); if (ret >= 0) return ret; +#endif else { errno = EILSEQ; diff --git a/m4/wcrtomb.m4 b/m4/wcrtomb.m4 index f4f37f5670..fec22f34e0 100644 --- a/m4/wcrtomb.m4 +++ b/m4/wcrtomb.m4 @@ -1,4 +1,4 @@ -# wcrtomb.m4 serial 13 +# wcrtomb.m4 serial 14 dnl Copyright (C) 2008-2019 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -33,7 +33,9 @@ AC_DEFUN([gl_FUNC_WCRTOMB], else if test $REPLACE_MBSTATE_T = 1; then REPLACE_WCRTOMB=1 - else + fi + if test $REPLACE_WCRTOMB = 0; then + dnl On Android 4.3, wcrtomb produces wrong characters in the C locale. dnl On AIX 4.3, OSF/1 5.1 and Solaris <= 11.3, wcrtomb (NULL, 0, NULL) dnl sometimes returns 0 instead of 1. AC_REQUIRE([AC_PROG_CC]) @@ -42,6 +44,45 @@ AC_DEFUN([gl_FUNC_WCRTOMB], AC_REQUIRE([gt_LOCALE_JA]) AC_REQUIRE([gt_LOCALE_ZH_CN]) AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_CACHE_CHECK([whether wcrtomb works in the C locale], + [gl_cv_func_wcrtomb_works], + [AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include <string.h> +#include <stdlib.h> +/* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before + <wchar.h>. + BSD/OS 4.0.1 has a bug: <stddef.h>, <stdio.h> and <time.h> must be + included before <wchar.h>. */ +#include <stddef.h> +#include <stdio.h> +#include <wchar.h> +int main () +{ + mbstate_t state; + char out[64]; + int count; + memset (&state, 0, sizeof (state)); + out[0] = 'x'; + count = wcrtomb (out, L'a', &state); + return !(count == 1 && out[0] == 'a'); +}]])], + [gl_cv_func_wcrtomb_works=yes], + [gl_cv_func_wcrtomb_works=no], + [case "$host_os" in + # Guess no on Android. + linux*-android*) gl_cv_func_wcrtomb_works="guessing no";; + # Guess yes otherwise. + *) gl_cv_func_wcrtomb_works="guessing yes";; + esac + ]) + ]) + case "$gl_cv_func_wcrtomb_works" in + *yes) ;; + *) REPLACE_WCRTOMB=1 ;; + esac + fi + if test $REPLACE_WCRTOMB = 0; then AC_CACHE_CHECK([whether wcrtomb return value is correct], [gl_cv_func_wcrtomb_retval], [ diff --git a/tests/test-wcrtomb.c b/tests/test-wcrtomb.c index c4baf38b24..2f0b64b1e8 100644 --- a/tests/test-wcrtomb.c +++ b/tests/test-wcrtomb.c @@ -156,6 +156,10 @@ main (int argc, char *argv[]) check_character (input + 3, 4); } return 0; + + case '5': + /* C locale; tested above. */ + return 0; } return 1; diff --git a/tests/test-wcrtomb.sh b/tests/test-wcrtomb.sh index 3eda8f338c..c183505080 100755 --- a/tests/test-wcrtomb.sh +++ b/tests/test-wcrtomb.sh @@ -32,4 +32,8 @@ if test $LOCALE_ZH_CN != none; then || exit 1 fi +# Test in the POSIX locale. +LC_ALL=C ./test-wcrtomb${EXEEXT} 5 || exit 1 +LC_ALL=POSIX ./test-wcrtomb${EXEEXT} 5 || exit 1 + exit 0 -- 2.39.5