changeset 14042:1a75c9206d28

mbrtowc: Work around a Solaris 7 bug. * m4/mbrtowc.m4 (gl_MBRTOWC_NULL_ARG1): New macro. (gl_MBRTOWC_NULL_ARG2): Renamed from gl_MBRTOWC_NULL_ARG. (gl_FUNC_MBRTOWC): Update. Define MBRTOWC_NULL_ARG2_BUG instead of MBRTOWC_NULL_ARG_BUG. Invoke gl_MBRTOWC_NULL_ARG1 and define MBRTOWC_NULL_ARG1_BUG. * lib/mbrtowc.c (rpl_mbrtowc): Use MBRTOWC_NULL_ARG2_BUG instead of MBRTOWC_NULL_ARG_BUG. Handle MBRTOWC_NULL_ARG1_BUG. * tests/test-mbrtowc.c (main): Test support of a NULL first argument. * doc/posix-functions/mbrtowc.texi: Mention the Solaris 7 bug.
author Bruno Haible <bruno@clisp.org>
date Mon, 27 Dec 2010 14:28:11 +0100
parents 1bc2888f2fcb
children a184cac42a35
files ChangeLog doc/posix-functions/mbrtowc.texi lib/mbrtowc.c m4/mbrtowc.m4 tests/test-mbrtowc.c
diffstat 5 files changed, 137 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2010-12-27  Bruno Haible  <bruno@clisp.org>
+
+	mbrtowc: Work around a Solaris 7 bug.
+	* m4/mbrtowc.m4 (gl_MBRTOWC_NULL_ARG1): New macro.
+	(gl_MBRTOWC_NULL_ARG2): Renamed from gl_MBRTOWC_NULL_ARG.
+	(gl_FUNC_MBRTOWC): Update. Define MBRTOWC_NULL_ARG2_BUG instead of
+	MBRTOWC_NULL_ARG_BUG. Invoke gl_MBRTOWC_NULL_ARG1 and define
+	MBRTOWC_NULL_ARG1_BUG.
+	* lib/mbrtowc.c (rpl_mbrtowc): Use MBRTOWC_NULL_ARG2_BUG instead of
+	MBRTOWC_NULL_ARG_BUG. Handle MBRTOWC_NULL_ARG1_BUG.
+	* tests/test-mbrtowc.c (main): Test support of a NULL first argument.
+	* doc/posix-functions/mbrtowc.texi: Mention the Solaris 7 bug.
+
 2010-12-27  Jim Meyering  <meyering@redhat.com>
 
 	read-file.c: tweak syntax
--- a/doc/posix-functions/mbrtowc.texi
+++ b/doc/posix-functions/mbrtowc.texi
@@ -20,6 +20,9 @@
 some platforms:
 Solaris 8.
 @item
+This function fails if the @code{pwc} argument is NULL on some platforms:
+Solaris 7.
+@item
 This function does not ignore the @code{pwc} argument if the string argument is
 NULL on some platforms:
 OSF/1 5.1.
--- a/lib/mbrtowc.c
+++ b/lib/mbrtowc.c
@@ -321,7 +321,7 @@
 size_t
 rpl_mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
 {
-# if MBRTOWC_NULL_ARG_BUG || MBRTOWC_RETVAL_BUG
+# if MBRTOWC_NULL_ARG2_BUG || MBRTOWC_RETVAL_BUG
   if (s == NULL)
     {
       pwc = NULL;
@@ -379,7 +379,16 @@
     return ret;
   }
 # else
-  return mbrtowc (pwc, s, n, ps);
+  {
+#   if MBRTOWC_NULL_ARG1_BUG
+    wchar_t dummy;
+
+    if (pwc == NULL)
+      pwc = &dummy;
+#   endif
+
+    return mbrtowc (pwc, s, n, ps);
+  }
 # endif
 }
 
--- a/m4/mbrtowc.m4
+++ b/m4/mbrtowc.m4
@@ -1,4 +1,4 @@
-# mbrtowc.m4 serial 20
+# mbrtowc.m4 serial 21
 dnl Copyright (C) 2001-2002, 2004-2005, 2008-2010 Free Software Foundation,
 dnl Inc.
 dnl This file is free software; the Free Software Foundation
@@ -19,12 +19,20 @@
     if test $REPLACE_MBSTATE_T = 1; then
       REPLACE_MBRTOWC=1
     else
-      gl_MBRTOWC_NULL_ARG
+      gl_MBRTOWC_NULL_ARG1
+      gl_MBRTOWC_NULL_ARG2
       gl_MBRTOWC_RETVAL
       gl_MBRTOWC_NUL_RETVAL
-      case "$gl_cv_func_mbrtowc_null_arg" in
+      case "$gl_cv_func_mbrtowc_null_arg1" in
         *yes) ;;
-        *) AC_DEFINE([MBRTOWC_NULL_ARG_BUG], [1],
+        *) AC_DEFINE([MBRTOWC_NULL_ARG1_BUG], [1],
+             [Define if the mbrtowc function has the NULL pwc argument bug.])
+           REPLACE_MBRTOWC=1
+           ;;
+      esac
+      case "$gl_cv_func_mbrtowc_null_arg2" in
+        *yes) ;;
+        *) AC_DEFINE([MBRTOWC_NULL_ARG2_BUG], [1],
              [Define if the mbrtowc function has the NULL string argument bug.])
            REPLACE_MBRTOWC=1
            ;;
@@ -202,25 +210,95 @@
     ])
 ])
 
+dnl Test whether mbrtowc supports a NULL pwc argument correctly.
+dnl Result is gl_cv_func_mbrtowc_null_arg1.
+
+AC_DEFUN([gl_MBRTOWC_NULL_ARG1],
+[
+  AC_REQUIRE([AC_PROG_CC])
+  AC_REQUIRE([gt_LOCALE_FR_UTF8])
+  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+  AC_CACHE_CHECK([whether mbrtowc handles a NULL pwc argument],
+    [gl_cv_func_mbrtowc_null_arg1],
+    [
+      dnl Initial guess, used when cross-compiling or when no suitable locale
+      dnl is present.
+changequote(,)dnl
+      case "$host_os" in
+                  # Guess no on Solaris.
+        solaris*) gl_cv_func_mbrtowc_null_arg1="guessing no" ;;
+                  # Guess yes otherwise.
+        *)        gl_cv_func_mbrtowc_null_arg1="guessing yes" ;;
+      esac
+changequote([,])dnl
+      if test $LOCALE_FR_UTF8 != none; then
+        AC_RUN_IFELSE(
+          [AC_LANG_SOURCE([[
+#include <locale.h>
+#include <stdlib.h>
+#include <string.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 <time.h>
+#include <wchar.h>
+int main ()
+{
+  int result = 0;
+
+  if (setlocale (LC_ALL, "$LOCALE_FR_UTF8") != NULL)
+    {
+      char input[] = "\303\237er";
+      mbstate_t state;
+      wchar_t wc;
+      size_t ret;
+
+      memset (&state, '\0', sizeof (mbstate_t));
+      wc = (wchar_t) 0xBADFACE;
+      ret = mbrtowc (&wc, input, 5, &state);
+      if (ret != 2)
+        result |= 1;
+      if (!mbsinit (&state))
+        result |= 2;
+
+      memset (&state, '\0', sizeof (mbstate_t));
+      ret = mbrtowc (NULL, input, 5, &state);
+      if (ret != 2) /* Solaris 7 fails here: ret is -1.  */
+        result |= 4;
+      if (!mbsinit (&state))
+        result |= 8;
+    }
+  return result;
+}]])],
+          [gl_cv_func_mbrtowc_null_arg1=yes],
+          [gl_cv_func_mbrtowc_null_arg1=no],
+          [:])
+      fi
+    ])
+])
+
 dnl Test whether mbrtowc supports a NULL string argument correctly.
-dnl Result is gl_cv_func_mbrtowc_null_arg.
+dnl Result is gl_cv_func_mbrtowc_null_arg2.
 
-AC_DEFUN([gl_MBRTOWC_NULL_ARG],
+AC_DEFUN([gl_MBRTOWC_NULL_ARG2],
 [
   AC_REQUIRE([AC_PROG_CC])
   AC_REQUIRE([gt_LOCALE_FR_UTF8])
   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
   AC_CACHE_CHECK([whether mbrtowc handles a NULL string argument],
-    [gl_cv_func_mbrtowc_null_arg],
+    [gl_cv_func_mbrtowc_null_arg2],
     [
       dnl Initial guess, used when cross-compiling or when no suitable locale
       dnl is present.
 changequote(,)dnl
       case "$host_os" in
               # Guess no on OSF/1.
-        osf*) gl_cv_func_mbrtowc_null_arg="guessing no" ;;
+        osf*) gl_cv_func_mbrtowc_null_arg2="guessing no" ;;
               # Guess yes otherwise.
-        *)    gl_cv_func_mbrtowc_null_arg="guessing yes" ;;
+        *)    gl_cv_func_mbrtowc_null_arg2="guessing yes" ;;
       esac
 changequote([,])dnl
       if test $LOCALE_FR_UTF8 != none; then
@@ -253,8 +331,8 @@
     }
   return 0;
 }]])],
-          [gl_cv_func_mbrtowc_null_arg=yes],
-          [gl_cv_func_mbrtowc_null_arg=no],
+          [gl_cv_func_mbrtowc_null_arg2=yes],
+          [gl_cv_func_mbrtowc_null_arg2=no],
           [:])
       fi
     ])
--- a/tests/test-mbrtowc.c
+++ b/tests/test-mbrtowc.c
@@ -1,5 +1,5 @@
 /* Test of conversion of multibyte character to wide character.
-   Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2008-2010 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
@@ -143,6 +143,11 @@
           ASSERT (mbsinit (&state));
           input[1] = '\0';
 
+          /* Test support of NULL first argument.  */
+          ret = mbrtowc (NULL, input + 2, 3, &state);
+          ASSERT (ret == 1);
+          ASSERT (mbsinit (&state));
+
           wc = (wchar_t) 0xBADFACE;
           ret = mbrtowc (&wc, input + 2, 3, &state);
           ASSERT (ret == 1);
@@ -192,6 +197,11 @@
           ASSERT (mbsinit (&state));
           input[2] = '\0';
 
+          /* Test support of NULL first argument.  */
+          ret = mbrtowc (NULL, input + 3, 4, &state);
+          ASSERT (ret == 2);
+          ASSERT (mbsinit (&state));
+
           wc = (wchar_t) 0xBADFACE;
           ret = mbrtowc (&wc, input + 3, 4, &state);
           ASSERT (ret == 2);
@@ -250,6 +260,11 @@
           ASSERT (mbsinit (&state));
           input[4] = '\0';
 
+          /* Test support of NULL first argument.  */
+          ret = mbrtowc (NULL, input + 5, 3, &state);
+          ASSERT (ret == 2);
+          ASSERT (mbsinit (&state));
+
           wc = (wchar_t) 0xBADFACE;
           ret = mbrtowc (&wc, input + 5, 3, &state);
           ASSERT (ret == 2);
@@ -293,6 +308,11 @@
           ASSERT (mbsinit (&state));
           input[2] = '\0';
 
+          /* Test support of NULL first argument.  */
+          ret = mbrtowc (NULL, input + 3, 6, &state);
+          ASSERT (ret == 4);
+          ASSERT (mbsinit (&state));
+
           wc = (wchar_t) 0xBADFACE;
           ret = mbrtowc (&wc, input + 3, 6, &state);
           ASSERT (ret == 4);