changeset 7724:5e8da40a33c5

Merge changes from the haible-private branch.
author Bruno Haible <bruno@clisp.org>
date Tue, 12 Dec 2006 12:50:14 +0000
parents 4275ae4f3f05
children 4ca3b4452773
files ChangeLog lib/iconvme.c
diffstat 2 files changed, 115 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2006-12-12  Bruno Haible  <bruno@clisp.org>
+
+	Merge these changes.
+	2006-09-05  Bruno Haible  <bruno@clisp.org>
+	* lib/iconvme.c (iconv_string): No need to save and restore errno when
+	iconv_alloc succeeded.
+	(iconv_alloc): Don't assume that malloc() or realloc(), when failing,
+	sets errno to ENOMEM. (malloc on GNU/kFreeBSD doesn't.) No need to
+	test for " && dest " at the end - dest is always != NULL there. Call
+	iconv with 4xNULL arguments initially, to reset the state. Call iconv
+	with 2xNULL arguments, also to flush the state storage. Handle the
+	IRIX iconv behaviour. Realloc the final result, to throw away unused
+	memory.
+
 2006-12-11  Paul Eggert  <eggert@cs.ucla.edu>
 
 	* m4/openat.m4 (gl_FUNC_OPENAT): Don't compile mkdirat
--- a/lib/iconvme.c
+++ b/lib/iconvme.c
@@ -73,21 +73,24 @@
 
   dest = iconv_alloc (cd, str);
 
-  {
-    int save_errno = errno;
-
-    if (iconv_close (cd) < 0 && dest)
-      {
-	int save_errno2 = errno;
-	/* If we didn't have a real error before, make sure we restore
-	   the iconv_close error below. */
-	free (dest);
-	dest = NULL;
-	errno = save_errno2;
-      }
-    else
-      errno = save_errno;
-  }
+  if (dest == NULL)
+    {
+      int saved_errno = errno;
+      iconv_close (cd);
+      errno = saved_errno;
+    }
+  else
+    {
+      if (iconv_close (cd) < 0)
+	{
+	  int saved_errno2 = errno;
+	  /* If we didn't have a real error before, make sure we restore
+	     the iconv_close error below. */
+	  free (dest);
+	  dest = NULL;
+	  errno = saved_errno2;
+	}
+    }
 #else
   errno = ENOSYS;
 #endif
@@ -126,7 +129,17 @@
 
   outp = dest = (char *) malloc (outbuf_size);
   if (dest == NULL)
-    return NULL;
+    {
+      errno = ENOMEM;
+      return NULL;
+    }
+
+  /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug.  */
+# if defined _LIBICONV_VERSION \
+    || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
+  /* Set to the initial state.  */
+  iconv (cd, NULL, NULL, NULL, NULL);
+# endif
 
 again:
   err = iconv (cd, &p, &inbytes_remaining, &outp, &outbytes_remaining);
@@ -154,6 +167,7 @@
 	    newdest = (char *) realloc (dest, newsize);
 	    if (newdest == NULL)
 	      {
+		errno = ENOMEM;
 		have_error = 1;
 		goto out;
 	      }
@@ -176,11 +190,80 @@
 	  break;
 	}
     }
+# if !defined _LIBICONV_VERSION && (defined sgi || defined __sgi)
+  /* Irix iconv() inserts a NUL byte if it cannot convert.  */
+  else if (err > 0)
+    {
+      errno = EILSEQ;
+      have_error = 1;
+      goto out;
+    }
+# endif
 
-  *outp = '\0';
+again2:
+  err = iconv (cd, NULL, NULL, &outp, &outbytes_remaining);
+
+  if (err == (size_t) -1)
+    {
+      switch (errno)
+	{
+	case E2BIG:
+	  {
+	    size_t used = outp - dest;
+	    size_t newsize = outbuf_size * 2;
+	    char *newdest;
+
+	    if (newsize <= outbuf_size)
+	      {
+		errno = ENOMEM;
+		have_error = 1;
+		goto out;
+	      }
+	    newdest = (char *) realloc (dest, newsize);
+	    if (newdest == NULL)
+	      {
+		errno = ENOMEM;
+		have_error = 1;
+		goto out;
+	      }
+	    dest = newdest;
+	    outbuf_size = newsize;
+
+	    outp = dest + used;
+	    outbytes_remaining = outbuf_size - used - 1;	/* -1 for NUL */
+
+	    goto again2;
+	  }
+	  break;
+
+	default:
+	  have_error = 1;
+	  break;
+	}
+    }
+# if !defined _LIBICONV_VERSION && (defined sgi || defined __sgi)
+  /* Irix iconv() inserts a NUL byte if it cannot convert.  */
+  else if (err > 0)
+    {
+      errno = EILSEQ;
+      have_error = 1;
+      goto out;
+    }
+# endif
+
+  *outp++ = '\0';
+
+  /* Give away unused memory.  */
+  if (outp - dest < outbuf_size)
+    {
+      char *newdest = (char *) realloc (dest, outp - dest);
+
+      if (newdest != NULL)
+	dest = newdest;
+    }
 
 out:
-  if (have_error && dest)
+  if (have_error)
     {
       int save_errno = errno;
       free (dest);