This is the mail archive of the newlib@sourceware.org mailing list for the newlib project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

fmemopen and open_memstream


After more debugging, I decided to submit open_memstream alongside fmemopen.

OK to commit?

2007-07-25  Eric Blake  <ebb9@byu.net>

	Implement fmemopen and open_memstream.
	* libc/stdio/fmemopen.c (_fmemopen_r, fmemopen): New file.
	* libc/stdio/open_memstream.c (_open_memstream_r, open_memstream):
	New file.
	* libc/include/stdio.h (fmemopen, open_memstream): Declare them.
	* libc/stdio/stdio.tex: Document them.
	* libc/stdio/Makefile.am (ELIX_4_SOURCES, CHEWOUT_FILES): Add
	fmemopen and open_memstream.
	* libc/stdio/Makefile.in: Regenerate.

Index: libc/stdio/fmemopen.c
===================================================================
RCS file: libc/stdio/fmemopen.c
diff -N libc/stdio/fmemopen.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libc/stdio/fmemopen.c	26 Jul 2007 02:40:55 -0000
@@ -0,0 +1,371 @@
+/* Copyright (C) 2007 Eric Blake
+ * Permission to use, copy, modify, and distribute this software
+ * is freely granted, provided that this notice is preserved.
+ */
+
+/*
+FUNCTION
+<<fmemopen>>---open a stream around a fixed-length string
+
+INDEX
+	fmemopen
+
+ANSI_SYNOPSIS
+	#include <stdio.h>
+	FILE *fmemopen(void *restrict <[buf]>, size_t <[size]>,
+		       const char *restrict <[mode]>);
+
+DESCRIPTION
+<<fmemopen>> creates a seekable <<FILE>> stream that wraps a
+fixed-length buffer of <[size]> bytes starting at <[buf]>.  The stream
+is opened with <[mode]> treated as in <<fopen>>, where append mode
+starts writing at the first NUL byte.  If <[buf]> is NULL, then
+<[size]> bytes are automatically provided as if by <<malloc>>, with
+the initial size of 0, and <[mode]> must contain <<+>> so that data
+can be read after it is written.
+
+The stream maintains a current position, which moves according to
+bytes read or written, and which can be one past the end of the array.
+The stream also maintains a current file size, which is never greater
+than <[size]>.  If <[mode]> starts with <<r>>, the position starts at
+<<0>>, and file size starts at <[size]> if <[buf]> was provided.  If
+<[mode]> starts with <<w>>, the position and file size start at <<0>>,
+and if <[buf]> was provided, the first byte is set to NUL.  If
+<[mode]> starts with <<a>>, the position and file size start at the
+location of the first NUL byte, or else <[size]> if <[buf]> was
+provided.
+
+When reading, NUL bytes have no significance, and reads cannot exceed
+the current file size.  When writing, the file size can increase up to
+<[size]> as needed, and NUL bytes may be embedded in the stream (see
+<<open_memstream>> for an alternative that automatically enlarges the
+buffer).  When the stream is flushed or closed after a write that
+changed the file size, a NUL byte is written at the current position
+if there is still room; if the stream is not also open for reading, a
+NUL byte is additionally written at the last byte of <[buf]> when the
+stream has exceeded <[size]>, so that a write-only <[buf]> is always
+NUL-terminated when the stream is flushed or closed (and the initial
+<[size]> should take this into account).  It is not possible to seek
+outside the bounds of <[size]>.  A NUL byte written during a flush is
+restored to its previous value when seeking elsewhere in the string.
+
+RETURNS
+The return value is an open FILE pointer on success.  On error,
+<<NULL>> is returned, and <<errno>> will be set to EINVAL if <[size]>
+is zero or <[mode]> is invalid, ENOMEM if <[buf]> was NULL and memory
+could not be allocated, or EMFILE if too many streams are already
+open.
+
+PORTABILITY
+This function is being added to POSIX 200x, but is not in POSIX 2001.
+
+Supporting OS subroutines required: <<sbrk>>.
+*/
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/lock.h>
+#include "local.h"
+
+/* Describe details of an open memstream.  */
+typedef struct fmemcookie {
+  void *storage; /* storage to free on close */
+  char *buf; /* buffer start */
+  size_t pos; /* current position */
+  size_t eof; /* current file size */
+  size_t max; /* maximum file size */
+  char append; /* nonzero if appending */
+  char writeonly; /* 1 if write-only */
+  char saved; /* saved character that lived at pos before write-only NUL */
+} fmemcookie;
+
+/* Read up to non-zero N bytes into BUF from stream described by
+   COOKIE; return number of bytes read (0 on EOF).  */
+static _READ_WRITE_RETURN_TYPE
+_DEFUN(fmemreader, (ptr, cookie, buf, n),
+       struct _reent *ptr _AND
+       void *cookie _AND
+       char *buf _AND
+       int n)
+{
+  fmemcookie *c = (fmemcookie *) cookie;
+  /* Can't read beyond current size, but EOF condition is not an error.  */
+  if (c->pos > c->eof)
+    return 0;
+  if (n >= c->eof - c->pos)
+    n = c->eof - c->pos;
+  memcpy (buf, c->buf + c->pos, n);
+  c->pos += n;
+  return n;
+}
+
+/* Write up to non-zero N bytes of BUF into the stream described by COOKIE,
+   returning the number of bytes written or EOF on failure.  */
+static _READ_WRITE_RETURN_TYPE
+_DEFUN(fmemwriter, (ptr, cookie, buf, n),
+       struct _reent *ptr _AND
+       void *cookie _AND
+       const char *buf _AND
+       int n)
+{
+  fmemcookie *c = (fmemcookie *) cookie;
+  int adjust = 0; /* true if at EOF, but still need to write NUL.  */
+
+  /* Append always seeks to eof; otherwise, if we have previously done
+     a seek beyond eof, ensure all intermediate bytes are NUL.  */
+  if (c->append)
+    c->pos = c->eof;
+  else if (c->pos > c->eof)
+    memset (c->buf + c->eof, '\0', c->pos - c->eof);
+  /* Do not write beyond EOF; saving room for NUL on write-only stream.  */
+  if (c->pos + n > c->max - c->writeonly)
+    {
+      adjust = c->writeonly;
+      n = c->max - c->pos;
+    }
+  /* Now n is the number of bytes being modified, and adjust is 1 if
+     the last byte is NUL instead of from buf.  Write a NUL if
+     write-only; or if read-write, eof changed, and there is still
+     room.  When we are within the file contents, remember what we
+     overwrite so we can restore it if we seek elsewhere later.  */
+  if (c->pos + n > c->eof)
+    {
+      c->eof = c->pos + n;
+      if (c->eof - adjust < c->max)
+	c->saved = c->buf[c->eof - adjust] = '\0';
+    }
+  else if (c->writeonly)
+    {
+      if (n)
+	{
+	  c->saved = c->buf[c->pos + n - adjust];
+	  c->buf[c->pos + n - adjust] = '\0';
+	}
+      else
+	adjust = 0;
+    }
+  c->pos += n;
+  if (n - adjust)
+    memcpy (c->buf + c->pos - n, buf, n - adjust);
+  else
+    {
+      ptr->_errno = ENOSPC;
+      return EOF;
+    }
+  return n;
+}
+
+/* Seek to position POS relative to WHENCE within stream described by
+   COOKIE; return resulting position or fail with EOF.  */
+static _fpos_t
+_DEFUN(fmemseeker, (ptr, cookie, pos, whence),
+       struct _reent *ptr _AND
+       void *cookie _AND
+       _fpos_t pos _AND
+       int whence)
+{
+  fmemcookie *c = (fmemcookie *) cookie;
+#ifndef __LARGE64_FILES
+  off_t offset = (off_t) pos;
+#else /* __LARGE64_FILES */
+  _off64_t offset = (_off64_t) pos;
+#endif /* __LARGE64_FILES */
+
+  if (whence == SEEK_CUR)
+    offset += c->pos;
+  else if (whence == SEEK_END)
+    offset += c->eof;
+  if (offset < 0)
+    {
+      ptr->_errno = EINVAL;
+      offset = -1;
+    }
+  else if (offset > c->max)
+    {
+      ptr->_errno = ENOSPC;
+      offset = -1;
+    }
+#ifdef __LARGE64_FILES
+  else if ((_fpos_t) offset != offset)
+    {
+      ptr->_errno = EOVERFLOW;
+      offset = -1;
+    }
+#endif /* __LARGE64_FILES */
+  else
+    {
+      if (c->writeonly && c->pos < c->eof)
+	{
+	  c->buf[c->pos] = c->saved;
+	  c->saved = '\0';
+	}
+      c->pos = offset;
+      if (c->writeonly && c->pos < c->eof)
+	{
+	  c->saved = c->buf[c->pos];
+	  c->buf[c->pos] = '\0';
+	}
+    }
+  return (_fpos_t) offset;
+}
+
+/* Seek to position POS relative to WHENCE within stream described by
+   COOKIE; return resulting position or fail with EOF.  */
+#ifdef __LARGE64_FILES
+static _fpos64_t
+_DEFUN(fmemseeker64, (ptr, cookie, pos, whence),
+       struct _reent *ptr _AND
+       void *cookie _AND
+       _fpos64_t pos _AND
+       int whence)
+{
+  _off64_t offset = (_off64_t) pos;
+  fmemcookie *c = (fmemcookie *) cookie;
+  if (whence == SEEK_CUR)
+    offset += c->pos;
+  else if (whence == SEEK_END)
+    offset += c->eof;
+  if (offset < 0)
+    {
+      ptr->_errno = EINVAL;
+      offset = -1;
+    }
+  else if (offset > c->max)
+    {
+      ptr->_errno = ENOSPC;
+      offset = -1;
+    }
+  else
+    {
+      if (c->writeonly && c->pos < c->eof)
+	{
+	  c->buf[c->pos] = c->saved;
+	  c->saved = '\0';
+	}
+      c->pos = offset;
+      if (c->writeonly && c->pos < c->eof)
+	{
+	  c->saved = c->buf[c->pos];
+	  c->buf[c->pos] = '\0';
+	}
+    }
+  return (_fpos64_t) offset;
+}
+#endif /* __LARGE64_FILES */
+
+/* Reclaim resources used by stream described by COOKIE.  */
+static int
+_DEFUN(fmemcloser, (ptr, cookie),
+       struct _reent *ptr _AND
+       void *cookie)
+{
+  fmemcookie *c = (fmemcookie *) cookie;
+  _free_r (ptr, c->storage);
+  return 0;
+}
+
+/* Open a memstream around buffer BUF of SIZE bytes, using MODE.
+   Return the new stream, or fail with NULL.  */
+FILE *
+_DEFUN(_fmemopen_r, (ptr, buf, size, mode),
+       struct _reent *ptr _AND
+       void *buf _AND
+       size_t size _AND
+       const char *mode)
+{
+  FILE *fp;
+  fmemcookie *c;
+  int flags;
+  int dummy;
+
+  if ((flags = __sflags (ptr, mode, &dummy)) == 0)
+    return NULL;
+  if (!size || !(buf || flags & __SAPP))
+    {
+      ptr->_errno = EINVAL;
+      return NULL;
+    }
+  if ((fp = __sfp (ptr)) == NULL)
+    return NULL;
+  if ((c = (fmemcookie *) _malloc_r (ptr, sizeof *c + (buf ? 0 : size)))
+      == NULL)
+    {
+      __sfp_lock_acquire ();
+      fp->_flags = 0;		/* release */
+#ifndef __SINGLE_THREAD__
+      __lock_close_recursive (fp->_lock);
+#endif
+      __sfp_lock_release ();
+      return NULL;
+    }
+
+  c->storage = c;
+  c->max = size;
+  /* 9 modes to worry about.  */
+  /* w/a, buf or no buf: Guarantee a NUL after any file writes.  */
+  c->writeonly = (flags & __SWR) != 0;
+  c->saved = '\0';
+  if (!buf)
+    {
+      /* r+/w+/a+, and no buf: file starts empty.  */
+      c->buf = (char *) (c + 1);
+      *(char *) buf = '\0';
+      c->pos = c->eof = 0;
+      c->append = (flags & __SAPP) != 0;
+    }
+  else
+    {
+      c->buf = (char *) buf;
+      switch (*mode)
+	{
+	case 'a':
+	  /* a/a+ and buf: position and size at first NUL.  */
+	  buf = memchr (c->buf, '\0', size);
+	  c->eof = c->pos = buf ? (char *) buf - c->buf : size;
+	  if (!buf && c->writeonly)
+	    /* a: guarantee a NUL within size even if no writes.  */
+	    c->buf[size - 1] = '\0';
+	  c->append = 1;
+	  break;
+	case 'r':
+	  /* r/r+ and buf: read at beginning, full size available.  */
+	  c->pos = c->append = 0;
+	  c->eof = size;
+	  break;
+	case 'w':
+	  /* w/w+ and buf: write at beginning, truncate to empty.  */
+	  c->pos = c->append = c->eof = 0;
+	  *c->buf = '\0';
+	  break;
+	default:
+	  abort ();
+	}
+    }
+
+  _flockfile (fp);
+  fp->_file = -1;
+  fp->_flags = flags;
+  fp->_cookie = c;
+  fp->_read = flags & (__SRD | __SRW) ? fmemreader : NULL;
+  fp->_write = flags & (__SWR | __SRW) ? fmemwriter : NULL;
+  fp->_seek = fmemseeker;
+#ifdef __LARGE64_FILES
+  fp->_seek64 = fmemseeker64;
+  fp->_flags |= __SL64;
+#endif
+  fp->_close = fmemcloser;
+  _funlockfile (fp);
+  return fp;
+}
+
+#ifndef _REENT_ONLY
+FILE *
+_DEFUN(fmemopen, (buf, size, mode),
+       void *buf _AND
+       size_t size _AND
+       const char *mode)
+{
+  return _fmemopen_r (_REENT, buf, size, mode);
+}
+#endif /* !_REENT_ONLY */
Index: libc/stdio/open_memstream.c
===================================================================
RCS file: libc/stdio/open_memstream.c
diff -N libc/stdio/open_memstream.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libc/stdio/open_memstream.c	26 Jul 2007 02:40:55 -0000
@@ -0,0 +1,330 @@
+/* Copyright (C) 2007 Eric Blake
+ * Permission to use, copy, modify, and distribute this software
+ * is freely granted, provided that this notice is preserved.
+ */
+
+/*
+FUNCTION
+<<open_memstream>>---open a write stream around an arbitrary-length string
+
+INDEX
+	open_memstream
+
+ANSI_SYNOPSIS
+	#include <stdio.h>
+	FILE *open_memstream(char **restrict <[buf]>,
+			     size_t *restrict <[size]>);
+
+DESCRIPTION
+<<open_memstream>> creates a seekable <<FILE>> stream that wraps an
+arbitrary-length buffer, created as if by <<malloc>>.  The current
+contents of *<[buf]> are ignored; this implementation uses *<[size]>
+as a hint of the maximum size expected, but does not fail if the hint
+was wrong.  The parameters <[buf]> and <[size]> are later stored
+through following any call to <<fflush>> or <<fclose>>, set to the
+current address and usable size of the allocated string; although
+after fflush, the pointer is only valid until another stream operation
+that results in a write.  Behavior is undefined if the user alters
+either *<[buf]> or *<[size]> prior to <<fclose>>.
+
+The stream is write-only, since the user can directly read *<[buf]>
+after a flush; see <<fmemopen>> for a way to wrap a string with a
+readable stream.  The user is responsible for calling <<free>> on
+the final *<[buf]> after <<fclose>>.
+
+Any time the stream is flushed, a NUL byte is written at the current
+position (but is not counted in the buffer length), so that the string
+is always NUL-terminated after at most *<[size]> bytes.  However, data
+previously written beyond the current stream offset is not lost, and
+the NUL byte written during a flush is restored to its previous value
+when seeking elsewhere in the string.
+
+RETURNS
+The return value is an open FILE pointer on success.  On error,
+<<NULL>> is returned, and <<errno>> will be set to EINVAL if <[buf]>
+or <[size]> is NULL, ENOMEM if memory could not be allocated, or
+EMFILE if too many streams are already open.
+
+PORTABILITY
+This function is being added to POSIX 200x, but is not in POSIX 2001.
+
+Supporting OS subroutines required: <<sbrk>>.
+*/
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/lock.h>
+#include "local.h"
+
+#ifndef __LARGE64_FILES
+# define OFF_T off_t
+#else
+# define OFF_T _off64_t
+#endif
+
+/* Describe details of an open memstream.  */
+typedef struct memstream {
+  void *storage; /* storage to free on close */
+  char **pbuf; /* pointer to the current buffer */
+  size_t *psize; /* pointer to the current size, smaller of pos or eof */
+  size_t pos; /* current position */
+  size_t eof; /* current file size */
+  size_t max; /* current malloc buffer size, always > eof */
+  char saved; /* saved character that lived at *psize before NUL */
+} memstream;
+
+/* Write up to non-zero N bytes of BUF into the stream described by COOKIE,
+   returning the number of bytes written or EOF on failure.  */
+static _READ_WRITE_RETURN_TYPE
+_DEFUN(memwriter, (ptr, cookie, buf, n),
+       struct _reent *ptr _AND
+       void *cookie _AND
+       const char *buf _AND
+       int n)
+{
+  memstream *c = (memstream *) cookie;
+  char *cbuf = *c->pbuf;
+
+  /* size_t is unsigned, but off_t is signed.  Don't let stream get so
+     big that user cannot do ftello.  */
+  if (sizeof (OFF_T) == sizeof (size_t) && (ssize_t) (c->pos + n) < 0)
+    {
+      ptr->_errno = EFBIG;
+      return EOF;
+    }
+  /* Grow the buffer, if necessary.  Choose a geometric growth factor
+     to avoid quadratic realloc behavior, but use a rate less than
+     (1+sqrt(5))/2 to accomodate malloc overhead.  Overallocate, so
+     that we can add a trailing \0 without reallocating.  The new
+     allocation should thus be max(prev_size*1.5, c->pos+n+1). */
+  if (c->pos + n >= c->max)
+    {
+      size_t newsize = c->max * 3 / 2;
+      if (newsize < c->pos + n + 1)
+	newsize = c->pos + n + 1;
+      cbuf = _realloc_r (ptr, cbuf, newsize);
+      if (! cbuf)
+	return EOF; /* errno already set to ENOMEM */
+      *c->pbuf = cbuf;
+      c->max = newsize;
+    }
+  /* If we have previously done a seek beyond eof, ensure all
+     intermediate bytes are NUL.  */
+  if (c->pos > c->eof)
+    memset (cbuf + c->eof, '\0', c->pos - c->eof);
+  memcpy (cbuf + c->pos, buf, n);
+  c->pos += n;
+  /* If the user has previously written further, remember what the
+     trailing NUL is overwriting.  Otherwise, extend the stream.  */
+  if (c->pos > c->eof)
+    c->eof = c->pos;
+  else
+    c->saved = cbuf[c->pos];
+  cbuf[c->pos] = '\0';
+  *c->psize = c->pos;
+  return n;
+}
+
+/* Seek to position POS relative to WHENCE within stream described by
+   COOKIE; return resulting position or fail with EOF.  */
+static _fpos_t
+_DEFUN(memseeker, (ptr, cookie, pos, whence),
+       struct _reent *ptr _AND
+       void *cookie _AND
+       _fpos_t pos _AND
+       int whence)
+{
+  memstream *c = (memstream *) cookie;
+  OFF_T offset = (OFF_T) pos;
+
+  if (whence == SEEK_CUR)
+    offset += c->pos;
+  else if (whence == SEEK_END)
+    offset += c->eof;
+  if (offset < 0)
+    {
+      ptr->_errno = EINVAL;
+      offset = -1;
+    }
+  else if ((size_t) offset != offset)
+    {
+      ptr->_errno = ENOSPC;
+      offset = -1;
+    }
+#ifdef __LARGE64_FILES
+  else if ((_fpos_t) offset != offset)
+    {
+      ptr->_errno = EOVERFLOW;
+      offset = -1;
+    }
+#endif /* __LARGE64_FILES */
+  else
+    {
+      if (c->pos < c->eof)
+	{
+	  (*c->pbuf)[c->pos] = c->saved;
+	  c->saved = '\0';
+	}
+      c->pos = offset;
+      if (c->pos < c->eof)
+	{
+	  c->saved = (*c->pbuf)[c->pos];
+	  (*c->pbuf)[c->pos] = '\0';
+	  *c->psize = c->pos;
+	}
+      else
+	*c->psize = c->eof;
+    }
+  return (_fpos_t) offset;
+}
+
+/* Seek to position POS relative to WHENCE within stream described by
+   COOKIE; return resulting position or fail with EOF.  */
+#ifdef __LARGE64_FILES
+static _fpos64_t
+_DEFUN(memseeker64, (ptr, cookie, pos, whence),
+       struct _reent *ptr _AND
+       void *cookie _AND
+       _fpos64_t pos _AND
+       int whence)
+{
+  _off64_t offset = (_off64_t) pos;
+  memstream *c = (memstream *) cookie;
+
+  if (whence == SEEK_CUR)
+    offset += c->pos;
+  else if (whence == SEEK_END)
+    offset += c->eof;
+  if (offset < 0)
+    {
+      ptr->_errno = EINVAL;
+      offset = -1;
+    }
+  else if ((size_t) offset != offset)
+    {
+      ptr->_errno = ENOSPC;
+      offset = -1;
+    }
+  else
+    {
+      if (c->pos < c->eof)
+	{
+	  (*c->pbuf)[c->pos] = c->saved;
+	  c->saved = '\0';
+	}
+      c->pos = offset;
+      if (c->pos < c->eof)
+	{
+	  c->saved = (*c->pbuf)[c->pos];
+	  (*c->pbuf)[c->pos] = '\0';
+	  *c->psize = c->pos;
+	}
+      else
+	*c->psize = c->eof;
+    }
+  return (_fpos64_t) offset;
+}
+#endif /* __LARGE64_FILES */
+
+/* Reclaim resources used by stream described by COOKIE.  */
+static int
+_DEFUN(memcloser, (ptr, cookie),
+       struct _reent *ptr _AND
+       void *cookie)
+{
+  memstream *c = (memstream *) cookie;
+  char *buf;
+
+  /* Be nice and try to reduce any unused memory.  */
+  buf = _realloc_r (ptr, *c->pbuf, *c->psize + 1);
+  if (buf)
+    *c->pbuf = buf;
+  _free_r (ptr, c->storage);
+  return 0;
+}
+
+/* Open a memstream that tracks a dynamic buffer in BUF and SIZE.
+   Return the new stream, or fail with NULL.  */
+FILE *
+_DEFUN(_open_memstream_r, (ptr, buf, size),
+       struct _reent *ptr _AND
+       char **buf _AND
+       size_t *size)
+{
+  FILE *fp;
+  memstream *c;
+  int flags;
+
+  if (!buf || !size)
+    {
+      ptr->_errno = EINVAL;
+      return NULL;
+    }
+  if ((fp = __sfp (ptr)) == NULL)
+    return NULL;
+  if ((c = (memstream *) _malloc_r (ptr, sizeof *c)) == NULL)
+    {
+      __sfp_lock_acquire ();
+      fp->_flags = 0;		/* release */
+#ifndef __SINGLE_THREAD__
+      __lock_close_recursive (fp->_lock);
+#endif
+      __sfp_lock_release ();
+      return NULL;
+    }
+  /* Use *size as a hint for initial sizing, but bound the initial
+     malloc between 64 bytes (same as asprintf, to avoid frequent
+     mallocs on small strings) and 64k bytes (to avoid overusing the
+     heap if *size was garbage).  */
+  c->max = *size;
+  if (c->max < 64)
+    c->max = 64;
+  else if (c->max > 64 * 1024)
+    c->max = 64 * 1024;
+  *size = 0;
+  *buf = _malloc_r (ptr, c->max);
+  if (!*buf)
+    {
+      __sfp_lock_acquire ();
+      fp->_flags = 0;		/* release */
+#ifndef __SINGLE_THREAD__
+      __lock_close_recursive (fp->_lock);
+#endif
+      __sfp_lock_release ();
+      _free_r (ptr, c);
+      return NULL;
+    }
+  **buf = '\0';
+
+  c->storage = c;
+  c->pbuf = buf;
+  c->psize = size;
+  c->eof = 0;
+  c->saved = '\0';
+
+  _flockfile (fp);
+  fp->_file = -1;
+  fp->_flags = __SWR;
+  fp->_cookie = c;
+  fp->_read = NULL;
+  fp->_write = memwriter;
+  fp->_seek = memseeker;
+#ifdef __LARGE64_FILES
+  fp->_seek64 = memseeker64;
+  fp->_flags |= __SL64;
+#endif
+  fp->_close = memcloser;
+  _funlockfile (fp);
+  return fp;
+}
+
+#ifndef _REENT_ONLY
+FILE *
+_DEFUN(open_memstream, (buf, size),
+       char **buf _AND
+       size_t *size)
+{
+  return _open_memstream_r (_REENT, buf, size);
+}
+#endif /* !_REENT_ONLY */
Index: libc/stdio/stdio.tex
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/stdio.tex,v
retrieving revision 1.9
diff -u -p -r1.9 stdio.tex
--- libc/stdio/stdio.tex	19 Jul 2007 03:42:21 -0000	1.9
+++ libc/stdio/stdio.tex	26 Jul 2007 02:40:55 -0000
@@ -37,6 +37,7 @@ structure.
 * fgetpos::     Record position in a stream or file
 * fgets::       Get character string from a file or stream
 * fileno::      Get file descriptor associated with stream
+* fmemopen::    Open a stream around a fixed-length buffer
 * fopen::       Open a file
 * fopencookie:: Open a stream with custom callbacks
 * fputc::       Write a character on a stream or file
@@ -57,6 +58,7 @@ structure.
 * gets::        Get character string from standard input (obsolete)
 * getw::        Get a word (int) from a file or stream
 * mktemp::      Generate unused file name
+* open_memstream::	Open a write stream around an arbitrary-length buffer
 * perror::      Print an error message on standard error
 * putc::        Write a character on a stream or file (macro)
 * putc_unlocked::	Write a character on a stream or file (macro)
@@ -124,6 +126,9 @@ structure.
 @include stdio/fileno.def
 
 @page
+@include stdio/fmemopen.def
+
+@page
 @include stdio/fopen.def
 
 @page
@@ -184,6 +189,9 @@ structure.
 @include stdio/mktemp.def
 
 @page
+@include stdio/open_memstream.def
+
+@page
 @include stdio/perror.def
 
 @page
Index: libc/stdio/Makefile.am
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/Makefile.am,v
retrieving revision 1.26
diff -u -p -r1.26 Makefile.am
--- libc/stdio/Makefile.am	13 Jul 2007 17:07:28 -0000	1.26
+++ libc/stdio/Makefile.am	26 Jul 2007 02:40:55 -0000
@@ -117,8 +117,10 @@ ELIX_4_SOURCES = \
 	asnprintf.c		\
 	diprintf.c		\
 	dprintf.c		\
+	fmemopen.c		\
 	fopencookie.c		\
 	funopen.c		\
+	open_memstream.c	\
 	vasniprintf.c		\
 	vasnprintf.c
 endif !ELIX_LEVEL_3
@@ -179,6 +181,7 @@ CHEWOUT_FILES = \
 	fgetpos.def		\
 	fgets.def		\
 	fileno.def		\
+	fmemopen.def		\
 	fopen.def		\
 	fopencookie.def		\
 	fputc.def		\
@@ -199,6 +202,7 @@ CHEWOUT_FILES = \
 	gets.def		\
 	getw.def		\
 	mktemp.def		\
+	open_memstream.def	\
 	perror.def		\
 	putc.def		\
 	putc_u.def		\
@@ -244,6 +248,7 @@ $(lpfx)fclose.$(oext): local.h
 $(lpfx)fdopen.$(oext): local.h
 $(lpfx)fflush.$(oext): local.h
 $(lpfx)findfp.$(oext): local.h
+$(lpfx)fmemopen.$(oext): local.h
 $(lpfx)fopen.$(oext): local.h
 $(lpfx)fopencookie.$(oext): local.h
 $(lpfx)fputs.$(oext): fvwrite.h
Index: libc/include/stdio.h
===================================================================
RCS file: /cvs/src/src/newlib/libc/include/stdio.h,v
retrieving revision 1.47
diff -u -p -r1.47 stdio.h
--- libc/include/stdio.h	13 Jul 2007 20:37:53 -0000	1.47
+++ libc/include/stdio.h	26 Jul 2007 02:40:55 -0000
@@ -244,11 +244,9 @@ char *	_EXFUN(asnprintf, (char *, size_t
                _ATTRIBUTE ((__format__ (__printf__, 3, 4))));
 int	_EXFUN(asprintf, (char **, const char *, ...)
                _ATTRIBUTE ((__format__ (__printf__, 2, 3))));
-#ifndef dprintf
+#ifndef diprintf
 int	_EXFUN(diprintf, (int, const char *, ...)
                _ATTRIBUTE ((__format__ (__printf__, 2, 3))));
-int	_EXFUN(dprintf, (int, const char *, ...)
-               _ATTRIBUTE ((__format__ (__printf__, 2, 3))));
 #endif
 int	_EXFUN(fcloseall, (_VOID));
 int	_EXFUN(fiprintf, (FILE *, const char *, ...)
@@ -278,8 +276,6 @@ int	_EXFUN(vasprintf, (char **, const ch
                _ATTRIBUTE ((__format__ (__printf__, 2, 0))));
 int	_EXFUN(vdiprintf, (int, const char *, __VALIST)
                _ATTRIBUTE ((__format__ (__printf__, 2, 0))));
-int	_EXFUN(vdprintf, (int, const char *, __VALIST)
-               _ATTRIBUTE ((__format__ (__printf__, 2, 0))));
 int	_EXFUN(vfiprintf, (FILE *, const char *, __VALIST)
                _ATTRIBUTE ((__format__ (__printf__, 2, 0))));
 int	_EXFUN(vfiscanf, (FILE *, const char *, __VALIST)
@@ -306,7 +302,7 @@ int	_EXFUN(vsscanf, (const char *, const
 #endif /* !__STRICT_ANSI__ */
 
 /*
- * Routines in POSIX 1003.1.
+ * Routines in POSIX 1003.1:2001.
  */
 
 #ifndef __STRICT_ANSI__
@@ -330,6 +326,26 @@ int	_EXFUN(putchar_unlocked, (int));
 #endif /* ! __STRICT_ANSI__ */
 
 /*
+ * Routines in POSIX 1003.1:200x.
+ */
+
+#ifndef __STRICT_ANSI__
+# ifndef _REENT_ONLY
+#  ifndef dprintf
+int	_EXFUN(dprintf, (int, const char *, ...)
+               _ATTRIBUTE ((__format__ (__printf__, 2, 3))));
+#  endif
+FILE *	_EXFUN(fmemopen, (void *, size_t, const char *));
+/* getdelim - see __getdelim for now */
+/* getline - see __getline for now */
+FILE *	_EXFUN(open_memstream, (char **, size_t *));
+/* renameat - unimplemented for now */
+int	_EXFUN(vdprintf, (int, const char *, __VALIST)
+               _ATTRIBUTE ((__format__ (__printf__, 2, 0))));
+# endif
+#endif
+
+/*
  * Recursive versions of the above.
  */
 
@@ -354,6 +370,7 @@ int	_EXFUN(_fiprintf_r, (struct _reent *
                _ATTRIBUTE ((__format__ (__printf__, 3, 4))));
 int	_EXFUN(_fiscanf_r, (struct _reent *, FILE *, const char *, ...)
                _ATTRIBUTE ((__format__ (__scanf__, 3, 4))));
+FILE *	_EXFUN(_fmemopen_r, (struct _reent *, void *, size_t, const char *));
 FILE *	_EXFUN(_fopen_r, (struct _reent *, const char *, const char *));
 int	_EXFUN(_fprintf_r, (struct _reent *, FILE *, const char *, ...)
                _ATTRIBUTE ((__format__ (__printf__, 3, 4))));
@@ -376,6 +393,7 @@ int	_EXFUN(_iscanf_r, (struct _reent *, 
                _ATTRIBUTE ((__format__ (__scanf__, 2, 3))));
 int	_EXFUN(_mkstemp_r, (struct _reent *, char *));
 char *	_EXFUN(_mktemp_r, (struct _reent *, char *));
+FILE *	_EXFUN(_open_memstream_r, (struct _reent *, char **, size_t *));
 void	_EXFUN(_perror_r, (struct _reent *, const char *));
 int	_EXFUN(_printf_r, (struct _reent *, const char *, ...)
                _ATTRIBUTE ((__format__ (__printf__, 2, 3))));



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]