changeset 7912:57ae1482adc0

Make the API of mem_cd_iconv more useful.
author Bruno Haible <bruno@clisp.org>
date Sun, 21 Jan 2007 20:36:25 +0000
parents 548a756cade0
children 36d66034ca77
files ChangeLog lib/striconv.c lib/striconv.h tests/test-striconv.c
diffstat 4 files changed, 47 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2007-01-21  Bruno Haible  <bruno@clisp.org>
+
+	* lib/striconv.h (mem_cd_iconv): Change specification.
+	* lib/striconv.c (mem_cd_iconv): Don't free the user-supplied original
+	result buffer.
+	(str_cd_iconv): Update.
+	* tests/test-striconv.c (main): Update.
+
 2007-01-21  Bruno Haible  <bruno@clisp.org>
 
 	* gnulib-tool: Fix test whether sed is GNU sed supporting --posix.
--- a/lib/striconv.c
+++ b/lib/striconv.c
@@ -118,15 +118,17 @@
       *lengthp = 0;
       return 0;
     }
-  result =
-    (char *) (*resultp != NULL ? realloc (*resultp, length) : malloc (length));
-  if (result == NULL)
+  if (*resultp != NULL && *lengthp >= length)
+    result = *resultp;
+  else
     {
-      errno = ENOMEM;
-      return -1;
+      result = (char *) malloc (length);
+      if (result == NULL)
+	{
+	  errno = ENOMEM;
+	  return -1;
+	}
     }
-  *resultp = result;
-  *lengthp = length;
 
   /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug.  */
 # if defined _LIBICONV_VERSION \
@@ -153,7 +155,7 @@
 	    if (errno == EINVAL)
 	      break;
 	    else
-	      return -1;
+	      goto fail;
 	  }
 # if !defined _LIBICONV_VERSION && !defined __GLIBC__
 	/* Irix iconv() inserts a NUL byte if it cannot convert.
@@ -163,7 +165,7 @@
 	else if (res > 0)
 	  {
 	    errno = EILSEQ;
-	    return -1;
+	    goto fail;
 	  }
 # endif
       }
@@ -174,14 +176,28 @@
       size_t res = iconv (cd, NULL, NULL, &outptr, &outsize);
 
       if (res == (size_t)(-1))
-	return -1;
+	goto fail;
     }
 # endif
     if (outsize != 0)
       abort ();
   }
 
+  *resultp = result;
+  *lengthp = length;
+
   return 0;
+
+ fail:
+  {
+    if (result != *resultp)
+      {
+	int saved_errno = errno;
+	free (result);
+	errno = saved_errno;
+      }
+    return -1;
+  }
 # undef tmpbufsize
 }
 
@@ -202,18 +218,14 @@
      Therefore we cannot use the second, faster algorithm.  */
 
   char *result = NULL;
-  size_t length;
+  size_t length = 0;
   int retval = mem_cd_iconv (src, strlen (src), cd, &result, &length);
   char *final_result;
 
   if (retval < 0)
     {
       if (result != NULL)
-	{
-	  int saved_errno = errno;
-	  free (result);
-	  errno = saved_errno;
-	}
+	abort ();
       return NULL;
     }
 
--- a/lib/striconv.h
+++ b/lib/striconv.h
@@ -1,5 +1,5 @@
 /* Charset conversion.
-   Copyright (C) 2001-2004, 2006 Free Software Foundation, Inc.
+   Copyright (C) 2001-2004, 2006-2007 Free Software Foundation, Inc.
    Written by Bruno Haible and Simon Josefsson.
 
    This program is free software; you can redistribute it and/or modify
@@ -35,12 +35,13 @@
 /* Convert an entire string from one encoding to another, using iconv.
    The original string is at [SRC,...,SRC+SRCLEN-1].
    The conversion descriptor is passed as CD.
-   *RESULTP should initially contain NULL or a malloced memory block.
-   May change the size of the allocated memory block in *RESULTP, storing
-   its new address in *RESULTP and its new length in *LENGTHP.
+   *RESULTP and *LENGTH should initially be a scratch buffer and its size,
+   or *RESULTP can initially be NULL.
+   May erase the contents of the memory at *RESULTP.
    Return value: 0 if successful, otherwise -1 and errno set.
-   If successful, the resulting string is stored in *RESULTP and its length
-   in *LENGTHP.  */
+   If successful: The resulting string is stored in *RESULTP and its length
+   in *LENGTHP.  *RESULTP is set to a freshly allocated memory block, or is
+   unchanged if no dynamic memory allocation was necessary.  */
 extern int mem_cd_iconv (const char *src, size_t srclen, iconv_t cd,
 			 char **resultp, size_t *lengthp);
 
--- a/tests/test-striconv.c
+++ b/tests/test-striconv.c
@@ -52,7 +52,7 @@
     static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
     static const char expected[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
     char *result = NULL;
-    size_t length;
+    size_t length = 0;
     int retval = mem_cd_iconv (input, strlen (input), cd_88591_to_utf8,
 			       &result, &length);
     ASSERT (retval == 0);
@@ -66,7 +66,7 @@
     static const char input[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
     static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
     char *result = NULL;
-    size_t length;
+    size_t length = 0;
     int retval = mem_cd_iconv (input, strlen (input), cd_utf8_to_88591,
 			       &result, &length);
     ASSERT (retval == 0);
@@ -79,7 +79,7 @@
   {
     static const char input[] = "\342\202\254"; /* EURO SIGN */
     char *result = NULL;
-    size_t length;
+    size_t length = 0;
     int retval = mem_cd_iconv (input, strlen (input), cd_utf8_to_88591,
 			       &result, &length);
     ASSERT (retval == -1 && errno == EILSEQ);
@@ -90,7 +90,7 @@
   {
     static const char input[] = "\342";
     char *result = NULL;
-    size_t length;
+    size_t length = 0;
     int retval = mem_cd_iconv (input, strlen (input), cd_utf8_to_88591,
 			       &result, &length);
     ASSERT (retval == 0);