Make the API of mem_cd_iconv more useful.
authorBruno Haible <bruno@clisp.org>
Sun, 21 Jan 2007 20:36:25 +0000 (20:36 +0000)
committerBruno Haible <bruno@clisp.org>
Sun, 21 Jan 2007 20:36:25 +0000 (20:36 +0000)
ChangeLog
lib/striconv.c
lib/striconv.h
tests/test-striconv.c

index 73b8a78..a6a27d8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 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.
 
 2007-01-20  Jim Meyering  <jim@meyering.net>
index 731a148..b2490a7 100644 (file)
@@ -118,15 +118,17 @@ mem_cd_iconv (const char *src, size_t srclen, iconv_t cd,
       *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 @@ mem_cd_iconv (const char *src, size_t srclen, iconv_t cd,
            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 @@ mem_cd_iconv (const char *src, size_t srclen, iconv_t cd,
        else if (res > 0)
          {
            errno = EILSEQ;
-           return -1;
+           goto fail;
          }
 # endif
       }
@@ -174,14 +176,28 @@ mem_cd_iconv (const char *src, size_t srclen, iconv_t cd,
       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 @@ str_cd_iconv (const char *src, iconv_t cd)
      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;
     }
 
index dd75ade..00f2cca 100644 (file)
@@ -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 @@ extern "C" {
 /* 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);
 
index fec7948..8fb662c 100644 (file)
@@ -52,7 +52,7 @@ main ()
     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 @@ main ()
     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 @@ main ()
   {
     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 @@ main ()
   {
     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);