Merge branch 'master' of ssh://haible@git.sv.gnu.org/srv/git/gnulib
authorBruno Haible <bruno@clisp.org>
Sat, 7 Mar 2009 15:32:42 +0000 (16:32 +0100)
committerBruno Haible <bruno@clisp.org>
Sat, 7 Mar 2009 15:32:42 +0000 (16:32 +0100)
lib/memxfrm.c
lib/memxfrm.h

index 9b29c52d94c1f00f261022cb7ea209434e5a0c2e..dc6eda1fa25617e49ee1952cef00d0421f738236 100644 (file)
@@ -25,7 +25,7 @@
 #include <string.h>
 
 char *
-memxfrm (char *s, size_t n, size_t *lengthp)
+memxfrm (char *s, size_t n, char *resultbuf, size_t *lengthp)
 {
   /* Result accumulator.  */
   char *result;
@@ -35,10 +35,18 @@ memxfrm (char *s, size_t n, size_t *lengthp)
   char orig_sentinel;
 
   /* Initial memory allocation.  */
-  allocated = (n > 0 ? n : 1);
-  result = (char *) malloc (allocated);
-  if (result == NULL)
-    goto out_of_memory_2;
+  if (resultbuf != NULL && *lengthp > 0)
+    {
+      result = resultbuf;
+      allocated = *lengthp;
+    }
+  else
+    {
+      allocated = (n > 0 ? n : 1);
+      result = (char *) malloc (allocated);
+      if (result == NULL)
+       goto out_of_memory_2;
+    }
   length = 0;
 
   /* Add sentinel.byte.  */
@@ -72,7 +80,12 @@ memxfrm (char *s, size_t n, size_t *lengthp)
                char *new_result;
 
                allocated = 2 * allocated;
-               new_result = (char *) realloc (result, allocated);
+               if (allocated < 64)
+                 allocated = 64;
+               if (result == resultbuf)
+                 new_result = (char *) malloc (allocated);
+               else
+                 new_result = (char *) realloc (result, allocated);
                if (new_result == NULL)
                  goto out_of_memory_1;
                result = new_result;
@@ -93,7 +106,7 @@ memxfrm (char *s, size_t n, size_t *lengthp)
   }
 
   /* Shrink the allocated memory if possible.  */
-  if ((length > 0 ? length : 1) < allocated)
+  if (result != resultbuf && (length > 0 ? length : 1) < allocated)
     {
       char *memory = (char *) realloc (result, length > 0 ? length : 1);
       if (memory != NULL)
@@ -107,14 +120,16 @@ memxfrm (char *s, size_t n, size_t *lengthp)
  fail:
   {
     int saved_errno = errno;
-    free (result);
+    if (result != resultbuf)
+      free (result);
     s[n] = orig_sentinel;
     errno = saved_errno;
     return NULL;
   }
 
  out_of_memory_1:
-  free (result);
+  if (result != resultbuf)
+    free (result);
   s[n] = orig_sentinel;
  out_of_memory_2:
   errno = ENOMEM;
index 6354633186ab43d3c622788ce386972f1d2f2afb..d78900a70749b9321e808e12439c515d424f3bc5 100644 (file)
@@ -33,10 +33,12 @@ extern "C" {
    restored before this function returns.
    The result of this function depends on the LC_COLLATE category of the
    current locale.
-   If successful, return the freshly allocated transformed string and set
-   *LENGTHP to its length,
+   If successful: If resultbuf is not NULL and the result fits into *lengthp
+   bytes, it is put in resultbuf, and resultbuf is returned.  Otherwise, a
+   freshly allocated string is returned.  In both cases, *lengthp is set to the
+   length of the returned string.
    Upon failure, return NULL, with errno set.  */
-extern char * memxfrm (char *s, size_t n, size_t *lengthp);
+extern char * memxfrm (char *s, size_t n, char *resultbuf, size_t *lengthp);
 
 
 #ifdef __cplusplus