+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
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
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);
newdest = (char *) realloc (dest, newsize);
if (newdest == NULL)
{
+ errno = ENOMEM;
have_error = 1;
goto out;
}
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
+
+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';
- *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);