<pre style='margin:0'>
Christopher Nielsen (mascguy) pushed a commit to branch master
in repository macports-legacy-support.

</pre>
<p><a href="https://github.com/macports/macports-legacy-support/commit/0b67cf1c08831cc54340b7be7c6ec0ad774b91cf">https://github.com/macports/macports-legacy-support/commit/0b67cf1c08831cc54340b7be7c6ec0ad774b91cf</a></p>
<pre style="white-space: pre; background: #F8F8F8">The following commit(s) were added to refs/heads/master by this push:
<span style='display:block; white-space:pre;color:#404040;'>     new 0b67cf1  stdio.h: add fmemopen (OS X < 10.13) - Credit: FreeBSD Project - License: BSD See: https://trac.macports.org/ticket/63785
</span>0b67cf1 is described below

<span style='display:block; white-space:pre;color:#808000;'>commit 0b67cf1c08831cc54340b7be7c6ec0ad774b91cf
</span>Author: Christopher Nielsen <mascguy@github.com>
AuthorDate: Tue Jul 4 14:23:55 2023 -0400

<span style='display:block; white-space:pre;color:#404040;'>    stdio.h: add fmemopen (OS X < 10.13)
</span><span style='display:block; white-space:pre;color:#404040;'>    - Credit: FreeBSD Project
</span><span style='display:block; white-space:pre;color:#404040;'>    - License: BSD
</span><span style='display:block; white-space:pre;color:#404040;'>    See: https://trac.macports.org/ticket/63785
</span>---
 README.md                       |   2 +-
 include/MacportsLegacySupport.h |   3 +
 include/stdio.h                 |   9 ++
 src/fmemopen.c                  | 260 +++++++++++++++++++++++++++++++++++
 test/test_fmemopen.c            | 298 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 571 insertions(+), 1 deletion(-)

<span style='display:block; white-space:pre;color:#808080;'>diff --git a/README.md b/README.md
</span><span style='display:block; white-space:pre;color:#808080;'>index c271050..d7dce54 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/README.md
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/README.md
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -71,7 +71,7 @@ Wrapped headers and replaced functions are:
</span>   <tr>
     <td><code>stdio.h</code></td>
     <td>Adds <code>dprintf</code>, <code>getline</code>, <code>getdelim</code>,
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        and <code>open_memstream</code> functions</td>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        <code>open_memstream</code>, and <code>fmemopen</code> functions</td>
</span>     <td>OSX10.6, OSX10.12 (open_memstream)</td>
   </tr>
   <tr>
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/include/MacportsLegacySupport.h b/include/MacportsLegacySupport.h
</span><span style='display:block; white-space:pre;color:#808080;'>index 98c58ea..ede0f6f 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/include/MacportsLegacySupport.h
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/include/MacportsLegacySupport.h
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -154,6 +154,9 @@
</span> /* open_memstream */
 #define __MP_LEGACY_SUPPORT_OPEN_MEMSTREAM__  (__APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101300)
 
<span style='display:block; white-space:pre;background:#e0ffe0;'>+/* fmemopen */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define __MP_LEGACY_SUPPORT_FMEMOPEN__  (__APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101300)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> /* pthread_setname_np */
 #define __MP_LEGACY_SUPPORT_PTHREAD_SETNAME_NP__  (__APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1060)
 
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/include/stdio.h b/include/stdio.h
</span><span style='display:block; white-space:pre;color:#808080;'>index e3e3897..3ddd718 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/include/stdio.h
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/include/stdio.h
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -67,6 +67,15 @@ __MP__END_DECLS
</span> 
 #endif /* __MP_LEGACY_SUPPORT_OPEN_MEMSTREAM__ */
 
<span style='display:block; white-space:pre;background:#e0ffe0;'>+/* fmemopen */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if __MP_LEGACY_SUPPORT_FMEMOPEN__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+__MP__BEGIN_DECLS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+FILE *fmemopen(void *buf, size_t size, const char *mode);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+__MP__END_DECLS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif /* __MP_LEGACY_SUPPORT_FMEMOPEN__ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> /* renameat */
 #if __MP_LEGACY_SUPPORT_ATCALLS__
 
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/fmemopen.c b/src/fmemopen.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 0000000..b040693
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/fmemopen.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,260 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*-
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Copyright (C) 2013 Pietro Cerutti <gahr@FreeBSD.org>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Redistribution and use in source and binary forms, with or without
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * modification, are permitted provided that the following conditions
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * are met:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * 1. Redistributions of source code must retain the above copyright
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *    notice, this list of conditions and the following disclaimer.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * 2. Redistributions in binary form must reproduce the above copyright
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *    notice, this list of conditions and the following disclaimer in the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *    documentation and/or other materials provided with the distribution.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * SUCH DAMAGE.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/cdefs.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <fcntl.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdbool.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <string.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+struct fmemopen_cookie
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  char  *buf;  /* pointer to the memory region */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  bool   own;  /* did we allocate the buffer ourselves? */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  char     bin;   /* is this a binary buffer? */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  size_t   size;  /* buffer length in bytes */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  size_t   len;  /* data length in bytes */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  size_t   off;  /* current offset into the buffer */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int  fmemopen_read(void *cookie, char *buf, int nbytes);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int  fmemopen_write(void *cookie, const char *buf, int nbytes);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static fpos_t  fmemopen_seek(void *cookie, fpos_t offset, int whence);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int  fmemopen_close(void *cookie);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+FILE *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+fmemopen(void * __restrict buf, size_t size, const char * __restrict mode)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  struct fmemopen_cookie *ck;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  FILE *f;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  int flags, rc;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * POSIX says we shall return EINVAL if size is 0.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (size == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    errno = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return (NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * Retrieve the flags as used by open(2) from the mode argument, and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * validate them.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  rc = __sflags(mode, &flags);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (rc == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    errno = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return (NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * There's no point in requiring an automatically allocated buffer
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * in write-only mode.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (!(flags & O_RDWR) && buf == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    errno = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return (NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  ck = malloc(sizeof(struct fmemopen_cookie));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (ck == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return (NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  ck->off  = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  ck->size = size;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* Check whether we have to allocate the buffer ourselves. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  ck->own = ((ck->buf = buf) == NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (ck->own) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ck->buf = malloc(size);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (ck->buf == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      free(ck);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      return (NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * POSIX distinguishes between w+ and r+, in that w+ is supposed to
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * truncate the buffer.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (ck->own || mode[0] == 'w') {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ck->buf[0] = '\0';
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* Check for binary mode. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  ck->bin = strchr(mode, 'b') != NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * The size of the current buffer contents is set depending on the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * mode:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * for append (text-mode), the position of the first NULL byte, or the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * size of the buffer if none is found
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * for append (binary-mode), the size of the buffer
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * for read, the size of the buffer
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * for write, 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  switch (mode[0]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  case 'a':
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ck->off = ck->len = strnlen(ck->buf, ck->size);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  case 'r':
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ck->len = size;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  case 'w':
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ck->len = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  f = funopen(ck,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      flags & O_WRONLY ? NULL : fmemopen_read, 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      flags & O_RDONLY ? NULL : fmemopen_write,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      fmemopen_seek, fmemopen_close);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (f == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (ck->own)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      free(ck->buf);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    free(ck);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return (NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (mode[0] == 'a')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    f->_flags |= __SAPP;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * Turn off buffering, so a write past the end of the buffer
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * correctly returns a short object count.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  setvbuf(f, NULL, _IONBF, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return (f);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+fmemopen_read(void *cookie, char *buf, int nbytes)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  struct fmemopen_cookie *ck = cookie;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (nbytes > ck->len - ck->off)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    nbytes = ck->len - ck->off;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (nbytes == 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return (0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  memcpy(buf, ck->buf + ck->off, nbytes);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  ck->off += nbytes;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return (nbytes);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+fmemopen_write(void *cookie, const char *buf, int nbytes)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  struct fmemopen_cookie *ck = cookie;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (nbytes > ck->size - ck->off)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    nbytes = ck->size - ck->off;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (nbytes == 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return (0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  memcpy(ck->buf + ck->off, buf, nbytes);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  ck->off += nbytes;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (ck->off > ck->len)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ck->len = ck->off;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * We append a NULL byte if all these conditions are met:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * - the buffer is not binary
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * - the buffer is not full
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   * - the data just written doesn't already end with a NULL byte
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (!ck->bin && ck->off < ck->size && ck->buf[ck->off - 1] != '\0')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ck->buf[ck->off] = '\0';
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return (nbytes);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static fpos_t
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+fmemopen_seek(void *cookie, fpos_t offset, int whence)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  struct fmemopen_cookie *ck = cookie;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  switch (whence) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  case SEEK_SET:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (offset > ck->size) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      errno = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      return (-1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ck->off = offset;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  case SEEK_CUR:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (ck->off + offset > ck->size) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      errno = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      return (-1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ck->off += offset;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  case SEEK_END:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (offset > 0 || -offset > ck->len) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      errno = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      return (-1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ck->off = ck->len + offset;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  default:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    errno = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return (-1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return (ck->off);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+fmemopen_close(void *cookie)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  struct fmemopen_cookie *ck = cookie;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (ck->own)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    free(ck->buf);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  free(ck);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return (0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/test/test_fmemopen.c b/test/test_fmemopen.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 0000000..f7be90a
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/test/test_fmemopen.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,298 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*-
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+Copyright (C) 2013 Pietro Cerutti <gahr@FreeBSD.org>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+Redistribution and use in source and binary forms, with or without
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+modification, are permitted provided that the following conditions
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+are met:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+1. Redistributions of source code must retain the above copyright
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   notice, this list of conditions and the following disclaimer.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+2. Redistributions in binary form must reproduce the above copyright
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   notice, this list of conditions and the following disclaimer in the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   documentation and/or other materials provided with the distribution.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+SUCH DAMAGE.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+*/
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Test basic FILE * functions (fread, fwrite, fseek, fclose) against
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * a FILE * retrieved using fmemopen()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/cdefs.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <assert.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <string.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <strings.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test_preexisting()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Use a pre-existing buffer.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char buf[512];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char buf2[512];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char str[]  = "Test writing some stuff";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char str2[] = "AAAAAAAAA";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char str3[] = "AAAA writing some stuff";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    FILE *fp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    size_t nofw, nofr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int rc;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Open a FILE * using fmemopen. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    fp = fmemopen(buf, sizeof(buf), "w");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(fp != NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Write to the buffer. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    nofw = fwrite(str, 1, sizeof(str), fp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(nofw == sizeof(str));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Close the FILE *. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    rc = fclose(fp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(rc == 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Re-open the FILE * to read back the data. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    fp = fmemopen(buf, sizeof(buf), "r");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(fp != NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Read from the buffer. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    bzero(buf2, sizeof(buf2));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    nofr = fread(buf2, 1, sizeof(buf2), fp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(nofr == sizeof(buf2));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Since a write on a FILE * retrieved by fmemopen
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * will add a '\0' (if there's space), we can check
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * the strings for equality.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(strcmp(str, buf2) == 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Close the FILE *. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    rc = fclose(fp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(rc == 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Now open a FILE * on the first 4 bytes of the string. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    fp = fmemopen(str, 4, "w");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(fp != NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Try to write more bytes than we shoud, we'll get a short count (4).
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    nofw = fwrite(str2, 1, sizeof(str2), fp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(nofw == 4);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Close the FILE *. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    rc = fclose(fp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Check that the string was not modified after the first 4 bytes. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(strcmp(str, str3) == 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test_autoalloc()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Let fmemopen allocate the buffer.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char str[] = "A quick test";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    FILE *fp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    long pos;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    size_t nofw, nofr, i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int rc;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Open a FILE * using fmemopen. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    fp = fmemopen(NULL, 512, "w+");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(fp != NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* fill the buffer */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    for (i = 0; i < 512; i++) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        nofw = fwrite("a", 1, 1, fp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        assert(nofw == 1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Get the current position into the stream. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    pos = ftell(fp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(pos == 512);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Try to write past the end, we should get a short object count (0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    nofw = fwrite("a", 1, 1, fp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(nofw == 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Close the FILE *. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    rc = fclose(fp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(rc == 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Open a FILE * using a wrong mode */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    fp = fmemopen(NULL, 512, "r");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(fp == NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    fp = fmemopen(NULL, 512, "w");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(fp == NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test_data_length()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Here we test that a read operation doesn't go past the end of the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * data actually written, and that a SEEK_END seeks from the end of the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * data, not of the whole buffer.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    FILE *fp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char buf[512] = {'\0'};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char str[]  = "Test data length. ";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char str2[] = "Do we have two sentences?";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char str3[sizeof(str) + sizeof(str2) -1];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    long pos;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    size_t nofw, nofr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int rc;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Open a FILE * for updating our buffer. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    fp = fmemopen(buf, sizeof(buf), "w+");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(fp != NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Write our string into the buffer. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    nofw = fwrite(str, 1, sizeof(str), fp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(nofw == sizeof(str));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Now seek to the end and check that ftell
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * gives us sizeof(str).
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    rc = fseek(fp, 0, SEEK_END);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(rc == 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    pos = ftell(fp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(pos == sizeof(str));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Close the FILE *. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    rc = fclose(fp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(rc == 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Reopen the buffer for appending. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    fp = fmemopen(buf, sizeof(buf), "a+");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(fp != NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* We should now be writing after the first string. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    nofw = fwrite(str2, 1, sizeof(str2), fp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(nofw == sizeof(str2));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Rewind the FILE *. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    rc = fseek(fp, 0, SEEK_SET);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(rc == 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Make sure we're at the beginning. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    pos = ftell(fp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(pos == 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Read the whole buffer. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    nofr = fread(str3, 1, sizeof(buf), fp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(nofr == sizeof(str3));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Make sure the two strings are there. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(strncmp(str3, str, sizeof(str) - 1) == 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(strncmp(str3 + sizeof(str) - 1, str2, sizeof(str2)) == 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Close the FILE *. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    rc = fclose(fp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(rc == 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test_binary()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Make sure that NULL bytes are never appended when opening a buffer
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * in binary mode.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    FILE *fp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char buf[20];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char str[] = "Test";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    size_t nofw;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int rc, i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Pre-fill the buffer. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    memset(buf, 'A', sizeof(buf));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Open a FILE * in binary mode. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    fp = fmemopen(buf, sizeof(buf), "w+b");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(fp != NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Write some data into it. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    nofw = fwrite(str, 1, strlen(str), fp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(nofw == strlen(str));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Make sure that the buffer doesn't contain any NULL bytes. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    for (i = 0; i < sizeof(buf); i++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        assert(buf[i] != '\0');
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Close the FILE *. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    rc = fclose(fp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(rc == 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test_append_binary_pos()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * For compatibility with other implementations (glibc), we set the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * position to 0 when opening an automatically allocated binary stream
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * for appending.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    FILE *fp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    fp = fmemopen(NULL, 16, "ab+");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(ftell(fp) == 0L);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    fclose(fp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Make sure that a pre-allocated buffer behaves correctly.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char buf[] = "Hello";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    fp = fmemopen(buf, sizeof(buf), "ab+");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(ftell(fp) == strlen(buf));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    fclose(fp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test_size_0()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * POSIX mandates that we return EINVAL if size is 0.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    FILE *fp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    fp = fmemopen(NULL, 0, "r+");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(fp == NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    assert(errno == EINVAL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+main(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    test_autoalloc();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    test_preexisting();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    test_data_length();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    test_binary();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    test_append_binary_pos();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    test_size_0();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return (0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span></pre><pre style='margin:0'>

</pre>