Formerly ../stdio/memstream.c.~9~
authorroland <roland>
Wed, 1 Jul 1992 01:36:30 +0000 (01:36 +0000)
committerroland <roland>
Wed, 1 Jul 1992 01:36:30 +0000 (01:36 +0000)
stdio/memstream.c

index b31eaaf..e6e660a 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
 This file is part of the GNU C Library.
 
 The GNU C Library is free software; you can redistribute it and/or
@@ -20,7 +20,6 @@ Cambridge, MA 02139, USA.  */
 #include <stdio.h>
 #include <stdlib.h>
 
-
 struct memstream_info
   {
     char **buffer;
@@ -33,12 +32,30 @@ DEFUN(enlarge_buffer, (stream, c),
       register FILE *stream AND int c)
 {
   struct memstream_info *info = (struct memstream_info *) stream->__cookie;
-  char *newbuf;
+  size_t need;
+
+  if (stream->__put_limit != stream->__buffer)
+    /* Record how much has actually been written into the buffer.  */
+    *info->bufsize = stream->__bufp - stream->__buffer;
+
+  if (stream->__target > *info->bufsize)
+    /* Our target (where the buffer maps to) is always zero except when
+       the user just did a SEEK_END fseek.  If he sought within the
+       buffer, we need do nothing and will zero the target below.  If he
+       sought past the end of the object, grow and zero-fill the buffer
+       up to the target address.  */
+    need = stream->__target;
+  else
+    need = *info->bufsize + (c == EOF ? 0 : 1);
 
-  *info->bufsize = stream->__bufp - stream->__buffer;
-  if (stream->__put_limit - stream->__bufp < 1)
+  if (stream->__bufsize < need)
     {
-      stream->__bufsize += 100;
+      /* Enlarge the buffer.  */
+      char *newbuf;
+      if (stream->__bufsize * 2 < need)
+       stream->__bufsize = need;
+      else
+       stream->__bufsize *= 2;
       newbuf = (char *) realloc ((PTR) stream->__buffer, stream->__bufsize);
       *info->buffer = newbuf;
       if (newbuf == NULL)
@@ -49,11 +66,21 @@ DEFUN(enlarge_buffer, (stream, c),
          stream->__error = 1;
          return;
        }
-
       stream->__buffer = newbuf;
-      stream->__bufp = stream->__buffer + *info->bufsize;
-      stream->__get_limit = stream->__put_limit;
-      stream->__put_limit = stream->__buffer + stream->__bufsize;
+    }
+
+  stream->__target = stream->__offset = 0;
+  stream->__get_limit = stream->__bufp = stream->__buffer + *info->bufsize;
+  stream->__put_limit = stream->__buffer + stream->__bufsize;
+
+  need -= stream->__bufp - stream->__buffer;
+  if (c != EOF)
+    --need;
+  if (need > 0)
+    {
+      /* We are extending the buffer after an fseek; zero-fill new space.  */
+      bzero (stream->__bufp, need);
+      stream->__bufp += need;
     }
 
   if (c != EOF)
@@ -62,6 +89,31 @@ DEFUN(enlarge_buffer, (stream, c),
     *stream->__bufp = '\0';
 }
 
+/* Seek function for memstreams.
+   There is no external state to munge.  */
+
+static int
+DEFUN(seek, (cookie, pos, whence),
+      PTR cookie AND fpos_t *pos AND int whence)
+{
+  switch (whence)
+    {
+    case SEEK_SET:
+    case SEEK_CUR:
+      return 0;
+
+    case SEEK_END:
+      /* Return the position relative to the end of the object.
+        fseek has just flushed us, so the info is consistent.  */
+      *pos += ((struct memstream_info *) cookie)->bufsize;
+      return 0;
+
+    default:
+      __libc_fatal ("memstream::seek called with bogus WHENCE\n");
+      return -1;
+    }
+}
+
 static int
 DEFUN(free_info, (cookie), PTR cookie)
 {
@@ -78,7 +130,7 @@ DEFUN(free_info, (cookie), PTR cookie)
 
   return 0;
 }
-
+\f
 /* Open a stream that writes into a malloc'd buffer that is expanded as
    necessary.  *BUFLOC and *SIZELOC are updated with the buffer's location
    and the number of characters written on fflush or fclose.  */
@@ -95,7 +147,7 @@ DEFUN(open_memstream, (bufloc, sizeloc),
       return NULL;
     }
 
-  stream = fmemopen ((char *) NULL, BUFSIZ, "w");
+  stream = fmemopen ((char *) NULL, BUFSIZ, "w+");
   if (stream == NULL)
     return NULL;
 
@@ -109,6 +161,7 @@ DEFUN(open_memstream, (bufloc, sizeloc),
     }
 
   stream->__room_funcs.__output = enlarge_buffer;
+  stream->__io_funcs.__seek = seek;
   stream->__io_funcs.__close = free_info;
   stream->__cookie = (PTR) info;
   stream->__userbuf = 1;