Module Name:    src
Committed By:   tnozaki
Date:           Fri Sep 24 09:21:53 UTC 2010

Modified Files:
        src/include: stdio.h
        src/lib/libc: shlib_version
        src/lib/libc/stdio: Makefile.inc
Added Files:
        src/lib/libc/stdio: fmemopen.c
        src/tests/lib/libc/stdio: Makefile t_fmemopen.c

Log Message:
add fmemopen(3) derrived from POSIX:2008.
libc minor bump.


To generate a diff of this commit:
cvs rdiff -u -r1.77 -r1.78 src/include/stdio.h
cvs rdiff -u -r1.218 -r1.219 src/lib/libc/shlib_version
cvs rdiff -u -r1.37 -r1.38 src/lib/libc/stdio/Makefile.inc
cvs rdiff -u -r0 -r1.1 src/lib/libc/stdio/fmemopen.c
cvs rdiff -u -r0 -r1.1 src/tests/lib/libc/stdio/Makefile \
    src/tests/lib/libc/stdio/t_fmemopen.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/include/stdio.h
diff -u src/include/stdio.h:1.77 src/include/stdio.h:1.78
--- src/include/stdio.h:1.77	Mon Sep  6 14:52:26 2010
+++ src/include/stdio.h	Fri Sep 24 09:21:53 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: stdio.h,v 1.77 2010/09/06 14:52:26 christos Exp $	*/
+/*	$NetBSD: stdio.h,v 1.78 2010/09/24 09:21:53 tnozaki Exp $	*/
 
 /*-
  * Copyright (c) 1990, 1993
@@ -508,6 +508,11 @@
 #define putchar_unlocked(x)	putc_unlocked(x, stdout)
 #endif /* _POSIX_C_SOURCE >= 199506 || _XOPEN_SOURCE >= 500 || _REENTRANT... */
 
+#if (_POSIX_C_SOURCE - 0) >= 200809L || (_XOPEN_SOURCE - 0) >= 700 || \
+    defined(_NETBSD_SOURCE)
+FILE *fmemopen(void * __restrict, size_t, const char * __restrict);
+#endif
+
 #if _FORTIFY_SOURCE > 0
 #include <ssp/stdio.h>
 #endif

Index: src/lib/libc/shlib_version
diff -u src/lib/libc/shlib_version:1.218 src/lib/libc/shlib_version:1.219
--- src/lib/libc/shlib_version:1.218	Mon Jun  7 13:52:29 2010
+++ src/lib/libc/shlib_version	Fri Sep 24 09:21:53 2010
@@ -1,4 +1,4 @@
-#	$NetBSD: shlib_version,v 1.218 2010/06/07 13:52:29 tnozaki Exp $
+#	$NetBSD: shlib_version,v 1.219 2010/09/24 09:21:53 tnozaki Exp $
 #	Remember to update distrib/sets/lists/base/shl.* when changing
 #
 # things we wish to do on next major version bump:
@@ -31,4 +31,4 @@
 #   it's insufficient bitwidth to implement all ctype class.
 #   see isblank's comment in ctype.h.
 major=12
-minor=173
+minor=174

Index: src/lib/libc/stdio/Makefile.inc
diff -u src/lib/libc/stdio/Makefile.inc:1.37 src/lib/libc/stdio/Makefile.inc:1.38
--- src/lib/libc/stdio/Makefile.inc:1.37	Mon Sep  6 14:52:55 2010
+++ src/lib/libc/stdio/Makefile.inc	Fri Sep 24 09:21:53 2010
@@ -1,5 +1,5 @@
 #	from: @(#)Makefile.inc	5.7 (Berkeley) 6/27/91
-#	$NetBSD: Makefile.inc,v 1.37 2010/09/06 14:52:55 christos Exp $
+#	$NetBSD: Makefile.inc,v 1.38 2010/09/24 09:21:53 tnozaki Exp $
 
 # stdio sources
 .PATH: ${.CURDIR}/stdio
@@ -20,6 +20,7 @@
 	vasprintf.c vdprintf.c vfprintf.c vfscanf.c vfwprintf.c vfwscanf.c \
 	vprintf.c vscanf.c vsnprintf.c vsnprintf_ss.c vsscanf.c vswprintf.c \
 	vswscanf.c vwprintf.c vwscanf.c wbuf.c wprintf.c wscanf.c wsetup.c
+SRCS+=	fmemopen.c
 
 .if !defined(AUDIT)
 SRCS+=	gets.c sprintf.c vsprintf.c tempnam.c tmpnam.c mktemp.c

Added files:

Index: src/lib/libc/stdio/fmemopen.c
diff -u /dev/null src/lib/libc/stdio/fmemopen.c:1.1
--- /dev/null	Fri Sep 24 09:21:53 2010
+++ src/lib/libc/stdio/fmemopen.c	Fri Sep 24 09:21:53 2010
@@ -0,0 +1,216 @@
+/* $NetBSD: fmemopen.c,v 1.1 2010/09/24 09:21:53 tnozaki Exp $ */
+
+/*-
+ * Copyright (c)2007, 2010 Takehiko NOZAKI,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: fmemopen.c,v 1.1 2010/09/24 09:21:53 tnozaki Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "reentrant.h"
+#include "local.h"
+
+struct fmemopen_cookie {
+	char *head, *tail, *cur, *eob;
+};
+
+static int
+fmemopen_read(void *cookie, char *buf, int nbytes)
+{
+	struct fmemopen_cookie *p;
+	char *s;
+
+	_DIAGASSERT(cookie != NULL);
+	_DIAGASSERT(buf != NULL && nbytes > 0);
+
+	p = (struct fmemopen_cookie *)cookie;
+	s = p->cur;
+	do {
+		if (p->cur == p->tail)
+			break;
+		*buf++ = *p->cur++;
+	} while (--nbytes > 0);
+
+	return (int)(p->cur - s);
+}
+
+static int
+fmemopen_write(void *cookie, const char *buf, int nbytes)
+{
+	struct fmemopen_cookie *p;
+	char *s, *t;
+
+	_DIAGASSERT(cookie != NULL);
+	_DIAGASSERT(buf != NULL && nbytes > 0);
+
+	p = (struct fmemopen_cookie *)cookie;
+	if (p->cur >= p->tail)
+		return 0;
+	s = p->cur;
+	t = p->tail - 1;
+	do {
+		if (p->cur == t) {
+			if (*buf == '\0')
+				*p->cur++ = *buf++;
+			break;
+		}
+		*p->cur++ = *buf++;
+	} while (--nbytes > 0);
+	*p->cur = '\0';
+	if (p->cur > p->eob)
+		p->eob = p->cur;
+
+	return (int)(p->cur - s);
+}
+
+static fpos_t
+fmemopen_seek(void *cookie, fpos_t offset, int whence)
+{
+	struct fmemopen_cookie *p;
+ 
+	_DIAGASSERT(cookie != NULL);
+
+	p = (struct fmemopen_cookie *)cookie;
+	switch (whence) {
+	case SEEK_SET:
+		break;
+	case SEEK_CUR:
+		offset += p->cur - p->head;
+		break;
+	case SEEK_END:
+		offset += p->eob - p->head;
+		break;
+	default:
+		errno = EINVAL;
+		goto error;
+	}
+	if (offset >= (fpos_t)0 && offset <= p->tail - p->head) {
+		p->cur = p->head + offset;
+		return (fpos_t)(p->cur - p->head);
+	}
+error:
+	return (fpos_t)-1;
+}
+
+static int
+fmemopen_close0(void *cookie)
+{
+	_DIAGASSERT(cookie != NULL);
+
+	free(cookie);
+
+	return 0;
+}
+
+static int
+fmemopen_close1(void *cookie)
+{
+	struct fmemopen_cookie *p;
+
+	_DIAGASSERT(cookie != NULL);
+
+	p = (struct fmemopen_cookie *)cookie;
+	free(p->head);
+	free(p);
+
+	return 0;
+}
+
+
+FILE *
+fmemopen(void * __restrict buf, size_t size, const char * __restrict mode)
+{
+	int oflags;
+	FILE *fp;
+	struct fmemopen_cookie *cookie;
+
+	if (size < (size_t)1) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	fp = __sfp();
+	if (fp == NULL)
+		return NULL;
+	fp->_file = -1;
+
+	fp->_flags = __sflags(mode, &oflags);
+	if (fp->_flags == 0)
+		return NULL;
+
+	if ((oflags & O_RDWR) == 0 && buf == NULL) {
+		errno = EINVAL;
+		goto release;
+	}
+
+	cookie = malloc(sizeof(*cookie));
+	if (cookie == NULL)
+		goto release;
+
+	if (buf == NULL) {
+		cookie->head = malloc(size);
+		if (cookie->head == NULL) {
+			free(cookie);
+			goto release;
+		}
+		*cookie->head = '\0';
+		fp->_close = &fmemopen_close1;
+	} else {
+		cookie->head = (char *)buf;
+		if (oflags & O_TRUNC)
+			*cookie->head = '\0';
+		fp->_close = &fmemopen_close0;
+	}
+
+	cookie->tail = cookie->head + size;
+	cookie->eob  = cookie->head;
+	do {
+		if (*cookie->eob == '\0')
+			break;
+		++cookie->eob;
+	} while (--size > 0);
+
+	cookie->cur = (oflags & O_APPEND) ? cookie->eob : cookie->head;
+
+	fp->_write  = (fp->_flags & __SRD) ? NULL : &fmemopen_write;
+	fp->_read   = (fp->_flags & __SWR) ? NULL : &fmemopen_read;
+	fp->_seek   = &fmemopen_seek;
+	fp->_cookie = (void *)cookie;
+
+	return fp;
+
+release:
+	fp->_flags = 0;
+	return NULL;
+}

Index: src/tests/lib/libc/stdio/Makefile
diff -u /dev/null src/tests/lib/libc/stdio/Makefile:1.1
--- /dev/null	Fri Sep 24 09:21:53 2010
+++ src/tests/lib/libc/stdio/Makefile	Fri Sep 24 09:21:53 2010
@@ -0,0 +1,9 @@
+# $NetBSD: Makefile,v 1.1 2010/09/24 09:21:53 tnozaki Exp $
+
+.include <bsd.own.mk>
+
+TESTSDIR=	${TESTSBASE}/lib/libc/stdio
+
+TESTS_C+=	t_fmemopen
+
+.include <bsd.test.mk>
Index: src/tests/lib/libc/stdio/t_fmemopen.c
diff -u /dev/null src/tests/lib/libc/stdio/t_fmemopen.c:1.1
--- /dev/null	Fri Sep 24 09:21:53 2010
+++ src/tests/lib/libc/stdio/t_fmemopen.c	Fri Sep 24 09:21:53 2010
@@ -0,0 +1,1170 @@
+/* $NetBSD: t_fmemopen.c,v 1.1 2010/09/24 09:21:53 tnozaki Exp $ */
+
+/*-
+ * Copyright (c)2010 Takehiko NOZAKI,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#if defined(__NetBSD__)
+#include <atf-c.h>
+#else
+#if defined(__linux__)
+#define _GNU_SOURCE
+#include <features.h>
+#endif
+#include <assert.h>
+#include <stdio.h>
+#define ATF_TC(arg0)		static void arg0##_head(void)
+#define ATF_TC_HEAD(arg0, arg1)	static void arg0##_head()
+#define atf_tc_set_md_var(arg0, arg1, ...) do {	\
+	printf(__VA_ARGS__);			\
+	puts("");				\
+} while (/*CONSTCOND*/0)
+#define ATF_TC_BODY(arg0, arg1)	static void arg0##_body()
+#define ATF_CHECK(arg0)		assert(arg0)
+#define ATF_TP_ADD_TCS(arg0)	int main(void)
+#define ATF_TP_ADD_TC(arg0, arg1) arg1##_head(); arg1##_body()
+#define atf_no_error()		0
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+const char *mode_rwa[] = {
+    "r", "rb", "r+", "rb+", "r+b",
+    "w", "wb", "w+", "wb+", "w+b",
+    "a", "ab", "a+", "ab+", "a+b",
+    NULL
+};
+
+const char *mode_r[] = { "r", "rb", "r+", "rb+", "r+b", NULL };
+const char *mode_w[] = { "w", "wb", "w+", "wb+", "w+b", NULL };
+const char *mode_a[] = { "a", "ab", "a+", "ab+", "a+b", NULL }; 
+
+struct testcase {
+	const char *s;
+	size_t n;
+} testcases[] = {
+#define TESTSTR(s)	{ s, sizeof(s)-1 }
+	TESTSTR("\0he quick brown fox jumps over the lazy dog"),
+	TESTSTR("T\0e quick brown fox jumps over the lazy dog"),
+	TESTSTR("Th\0 quick brown fox jumps over the lazy dog"),
+	TESTSTR("The\0quick brown fox jumps over the lazy dog"),
+	TESTSTR("The \0uick brown fox jumps over the lazy dog"),
+	TESTSTR("The q\0ick brown fox jumps over the lazy dog"),
+	TESTSTR("The qu\0ck brown fox jumps over the lazy dog"),
+	TESTSTR("The qui\0k brown fox jumps over the lazy dog"),
+	TESTSTR("The quic\0 brown fox jumps over the lazy dog"),
+	TESTSTR("The quick\0brown fox jumps over the lazy dog"),
+	TESTSTR("The quick \0rown fox jumps over the lazy dog"),
+	TESTSTR("The quick b\0own fox jumps over the lazy dog"),
+	TESTSTR("The quick br\0wn fox jumps over the lazy dog"),
+	TESTSTR("The quick bro\0n fox jumps over the lazy dog"),
+	TESTSTR("The quick brow\0 fox jumps over the lazy dog"),
+	TESTSTR("The quick brown\0fox jumps over the lazy dog"),
+	TESTSTR("The quick brown \0ox jumps over the lazy dog"),
+	TESTSTR("The quick brown f\0x jumps over the lazy dog"),
+	TESTSTR("The quick brown fo\0 jumps over the lazy dog"),
+	TESTSTR("The quick brown fox\0jumps over the lazy dog"),
+	TESTSTR("The quick brown fox \0umps over the lazy dog"),
+	TESTSTR("The quick brown fox j\0mps over the lazy dog"),
+	TESTSTR("The quick brown fox ju\0ps over the lazy dog"),
+	TESTSTR("The quick brown fox jum\0s over the lazy dog"),
+	TESTSTR("The quick brown fox jump\0 over the lazy dog"),
+	TESTSTR("The quick brown fox jumps\0over the lazy dog"),
+	TESTSTR("The quick brown fox jumps \0ver the lazy dog"),
+	TESTSTR("The quick brown fox jumps o\0er the lazy dog"),
+	TESTSTR("The quick brown fox jumps ov\0r the lazy dog"),
+	TESTSTR("The quick brown fox jumps ove\0 the lazy dog"),
+	TESTSTR("The quick brown fox jumps over\0the lazy dog"),
+	TESTSTR("The quick brown fox jumps over \0he lazy dog"),
+	TESTSTR("The quick brown fox jumps over t\0e lazy dog"),
+	TESTSTR("The quick brown fox jumps over th\0 lazy dog"),
+	TESTSTR("The quick brown fox jumps over the\0lazy dog"),
+	TESTSTR("The quick brown fox jumps over the \0azy dog"),
+	TESTSTR("The quick brown fox jumps over the l\0zy dog"),
+	TESTSTR("The quick brown fox jumps over the la\0y dog"),
+	TESTSTR("The quick brown fox jumps over the laz\0 dog"),
+	TESTSTR("The quick brown fox jumps over the lazy\0dog"),
+	TESTSTR("The quick brown fox jumps over the lazy \0og"),
+	TESTSTR("The quick brown fox jumps over the lazy d\0g"),
+	TESTSTR("The quick brown fox jumps over the lazy do\0"),
+	TESTSTR("The quick brown fox jumps over the lazy dog"),
+	{ NULL, 0 },
+};
+
+ATF_TC(test00);
+ATF_TC_HEAD(test00, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "test00");
+}
+ATF_TC_BODY(test00, tc)
+{
+	const char **p;
+	char buf[BUFSIZ];
+	FILE *fp;
+
+	for (p = &mode_rwa[0]; *p != NULL; ++p) {
+		fp = fmemopen(&buf[0], sizeof(buf), *p);
+/*
+ * Upon successful completion, fmemopen() shall return a pointer to the
+ * object controlling the stream.
+ */
+		ATF_CHECK(fp != NULL);
+
+		ATF_CHECK(fclose(fp) == 0);
+	}
+}
+
+ATF_TC(test01);
+ATF_TC_HEAD(test01, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "test01");
+}
+ATF_TC_BODY(test01, tc)
+{
+	const char **p;
+	const char *mode[] = {
+	    "r+", "rb+", "r+b",
+	    "w+", "wb+", "w+b",
+	    "a+", "ab+", "a+b",
+	    NULL
+	};
+	FILE *fp;
+
+	for (p = &mode[0]; *p != NULL; ++p) {
+/*
+ * If a null pointer is specified as the buf argument, fmemopen() shall
+ * allocate size bytes of memory as if by a call to malloc().
+ */
+		fp = fmemopen(NULL, BUFSIZ, *p);
+		ATF_CHECK(fp != NULL);
+
+/*
+ * If buf is a null pointer, the initial position shall always be set
+ * to the beginning of the buffer.
+ */
+		ATF_CHECK(ftello(fp) == (off_t)0);
+
+		ATF_CHECK(fclose(fp) == 0);
+	}
+}
+
+ATF_TC(test02);
+ATF_TC_HEAD(test02, tc)
+{
+        atf_tc_set_md_var(tc, "descr", "test02");
+}
+ATF_TC_BODY(test02, tc)
+{
+	const char **p;
+	char buf[BUFSIZ];
+	FILE *fp;
+
+	for (p = &mode_r[0]; *p != NULL; ++p) {
+
+		memset(&buf[0], 0x1, sizeof(buf));
+		fp = fmemopen(&buf[0], sizeof(buf), *p);
+		ATF_CHECK(fp != NULL);
+
+/*
+ * This position is initially set to either the beginning of the buffer
+ * (for r and w modes)
+ */
+		ATF_CHECK((unsigned char)buf[0] == 0x1);
+		ATF_CHECK(ftello(fp) == (off_t)0);
+
+/*
+ * The stream also maintains the size of the current buffer contents.
+ * For modes r and r+ the size is set to the value given by the size argument.
+ */
+#if !defined(__GLIBC__)
+		ATF_CHECK(fseeko(fp, (off_t)0, SEEK_END) == 0);
+		ATF_CHECK(ftello(fp) == (off_t)sizeof(buf));
+#endif
+		ATF_CHECK(fclose(fp) == 0);
+	}
+}
+
+ATF_TC(test03);
+ATF_TC_HEAD(test03, tc)
+{
+        atf_tc_set_md_var(tc, "descr", "test03");
+}
+ATF_TC_BODY(test03, tc)
+{
+	const char **p;
+	char buf[BUFSIZ];
+	FILE *fp;
+ 
+	for (p = &mode_w[0]; *p != NULL; ++p) {
+
+		memset(&buf[0], 0x1, sizeof(buf));
+		fp = fmemopen(&buf[0], sizeof(buf), *p);
+		ATF_CHECK(fp != NULL);
+
+/*
+ * This position is initially set to either the beginning of the buffer
+ * (for r and w modes)
+ */
+		ATF_CHECK(buf[0] == '\0');
+		ATF_CHECK(ftello(fp) == (off_t)0);
+
+/*
+ * For modes w and w+ the initial size is zero
+ */
+		ATF_CHECK(fseeko(fp, (off_t)0, SEEK_END) == 0);
+		ATF_CHECK(ftello(fp) == (off_t)0);
+
+		ATF_CHECK(fclose(fp) == 0);
+	}
+}
+
+ATF_TC(test04);
+ATF_TC_HEAD(test04, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "test04");
+}
+ATF_TC_BODY(test04, tc)
+{
+	const char **p;
+	char buf[BUFSIZ];
+	FILE *fp;
+
+/*
+ * or to the first null byte in the buffer (for a modes)
+ */
+	for (p = &mode_a[0]; *p != NULL; ++p) {
+
+		memset(&buf[0], 0x1, sizeof(buf));
+		fp = fmemopen(&buf[0], sizeof(buf), *p);
+		ATF_CHECK(fp != NULL);
+
+		ATF_CHECK((unsigned char)buf[0] == 0x1);
+
+/* If no null byte is found in append mode,
+ * the initial position is set to one byte after the end of the buffer.
+ */
+#if !defined(__GLIBC__)
+		ATF_CHECK(ftello(fp) == (off_t)sizeof(buf));
+#endif
+
+/*
+ * and for modes a and a+ the initial size is either the position of the
+ * first null byte in the buffer or the value of the size argument
+ * if no null byte is found.
+ */
+#if !defined(__GLIBC__)
+		ATF_CHECK(fseeko(fp, (off_t)0, SEEK_END) == 0);
+		ATF_CHECK(ftello(fp) == (off_t)sizeof(buf));
+#endif
+
+		ATF_CHECK(fclose(fp) == 0);
+	}
+}
+
+ATF_TC(test05);
+ATF_TC_HEAD(test05, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "test05");
+}
+ATF_TC_BODY(test05, tc)
+{
+	const char **p;
+	FILE *fp;
+	char buf[BUFSIZ];
+
+	for (p = &mode_rwa[0]; *p != NULL; ++p) {
+/*
+ * Otherwise, a null pointer shall be returned, and errno shall be set
+ * to indicate the error.
+ */
+		errno = 0;
+		fp = fmemopen(NULL, (size_t)0, *p);
+		ATF_CHECK(fp == NULL);
+		ATF_CHECK(errno == EINVAL);
+
+		errno = 0;
+		fp = fmemopen((void *)&buf[0], 0, *p);
+		ATF_CHECK(fp == NULL);
+		ATF_CHECK(errno == EINVAL);
+	}
+}
+
+ATF_TC(test06);
+ATF_TC_HEAD(test06, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "test06");
+}
+ATF_TC_BODY(test06, tc)
+{
+	const char **p;
+	const char *mode[] = { "", " ", "???", NULL };
+	FILE *fp;
+
+	for (p = &mode[0]; *p != NULL; ++p) {
+/*
+ * The value of the mode argument is not valid.
+ */
+		fp = fmemopen(NULL, 1, *p);
+		ATF_CHECK(fp == NULL);
+		ATF_CHECK(errno == EINVAL);
+	}
+}
+
+ATF_TC(test07);
+ATF_TC_HEAD(test07, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "test07");
+}
+ATF_TC_BODY(test07, tc)
+{
+#if !defined(__GLIBC__)
+	const char **p;
+	const char *mode[] = {
+	    "r", "rb",
+	    "w", "wb",
+	    "a", "ab",
+	    NULL
+	};
+	FILE *fp;
+
+	for (p = &mode[0]; *p != NULL; ++p) {
+/*
+ * Because this feature is only useful when the stream is opened for updating
+ * (because there is no way to get a pointer to the buffer) the fmemopen()
+ * call may fail if the mode argument does not include a '+' . 
+ */
+		errno = 0;
+		fp = fmemopen(NULL, 1, *p);
+		ATF_CHECK(fp == NULL);
+		ATF_CHECK(errno == EINVAL);
+	}
+#endif
+}
+
+ATF_TC(test08);
+ATF_TC_HEAD(test08, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "test08");
+}
+ATF_TC_BODY(test08, tc)
+{
+#if !defined(__GLIBC__)
+	const char **p;
+	const char *mode[] = {
+	    "r+", "rb+", "r+b",
+	    "w+", "wb+", "w+b",
+	    "a+", "ab+", "a+b",
+	    NULL
+	};
+	FILE *fp;
+
+	for (p = &mode[0]; *p != NULL; ++p) {
+/*
+ * The buf argument is a null pointer and the allocation of a buffer of
+ * length size has failed.
+ */
+		fp = fmemopen(NULL, SIZE_MAX, *p);
+		ATF_CHECK(fp == NULL);
+		ATF_CHECK(errno == ENOMEM);
+	}
+#endif
+}
+
+/*
+ * test09 - test14:
+ * An attempt to seek a memory buffer stream to a negative position or to a
+ * position larger than the buffer size given in the size argument shall fail.
+ */
+
+ATF_TC(test09);
+ATF_TC_HEAD(test09, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "test09");
+}
+ATF_TC_BODY(test09, tc)
+{
+	struct testcase *t;
+	const char **p;
+	char buf[BUFSIZ];
+	FILE *fp;
+	off_t i;
+
+	for (t = &testcases[0]; t->s != NULL; ++t) {
+		for (p = &mode_rwa[0]; *p != NULL; ++p) {
+
+			memcpy(&buf[0], t->s, t->n);
+			fp = fmemopen(&buf[0], t->n, *p);
+			ATF_CHECK(fp != NULL);
+
+/*
+ * test fmemopen_seek(SEEK_SET)
+ */
+			/* zero */
+			ATF_CHECK(fseeko(fp, (off_t)0, SEEK_SET) == 0);
+			ATF_CHECK(ftello(fp) == (off_t)0);
+
+			/* positive */
+			for (i = (off_t)1; i <= (off_t)t->n; ++i) {
+				ATF_CHECK(fseeko(fp, i, SEEK_SET) == 0);
+				ATF_CHECK(ftello(fp) == i);
+			}
+			/* positive + OOB */
+			ATF_CHECK(fseeko(fp, t->n + 1, SEEK_SET) == -1);
+			ATF_CHECK(ftello(fp) == t->n);
+
+			/* negative + OOB */
+			ATF_CHECK(fseeko(fp, (off_t)-1, SEEK_SET) == -1);
+			ATF_CHECK(ftello(fp) == t->n);
+
+			ATF_CHECK(fclose(fp) == 0);
+		}
+	}
+}
+
+const char *mode_rw[] = {
+    "r", "rb", "r+", "rb+", "r+b",
+    "w", "wb", "w+", "wb+", "w+b",
+    NULL
+};
+
+ATF_TC(test10);
+ATF_TC_HEAD(test10, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "test10");
+}
+ATF_TC_BODY(test10, tc)
+{
+	struct testcase *t;
+	off_t len, i;
+	const char **p;
+	char buf[BUFSIZ];
+	FILE *fp;
+
+	for (t = &testcases[0]; t->s != NULL; ++t) {
+		len = (off_t)strnlen(t->s, t->n);
+		for (p = &mode_rw[0]; *p != NULL; ++p) {
+
+			memcpy(&buf[0], t->s, t->n);
+			fp = fmemopen(&buf[0], t->n, *p);
+			ATF_CHECK(fp != NULL);
+
+/*
+ * test fmemopen_seek(SEEK_CUR)
+ */
+			ATF_CHECK(ftello(fp) == (off_t)0);
+
+			/* zero */
+			ATF_CHECK(fseeko(fp, (off_t)0, SEEK_CUR) == 0);
+			ATF_CHECK(ftello(fp) == (off_t)0);
+
+			/* negative & OOB */
+			ATF_CHECK(fseeko(fp, (off_t)-1, SEEK_CUR) == -1);
+			ATF_CHECK(ftello(fp) == (off_t)0);
+
+			/* positive */
+			for (i = 0; i < (off_t)t->n; ++i) {
+				ATF_CHECK(fseeko(fp, (off_t)1, SEEK_CUR) == 0);
+				ATF_CHECK(ftello(fp) == i + 1);
+			}
+
+			/* positive & OOB */
+			ATF_CHECK(fseeko(fp, (off_t)1, SEEK_CUR) == -1);
+			ATF_CHECK(ftello(fp) == (off_t)t->n);
+
+			ATF_CHECK(fclose(fp) == 0);
+		}
+	}
+}
+
+ATF_TC(test11);
+ATF_TC_HEAD(test11, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "test11");
+}
+ATF_TC_BODY(test11, tc)
+{
+	struct testcase *t;
+	off_t len, rest, i;
+	const char **p;
+	char buf[BUFSIZ];
+	FILE *fp;
+
+	/* test fmemopen_seek(SEEK_CUR) */
+	for (t = &testcases[0]; t->s != NULL; ++t) {
+		len = (off_t)strnlen(t->s, t->n);
+		rest = (off_t)t->n - len;
+		for (p = &mode_a[0]; *p != NULL; ++p) {
+
+			memcpy(&buf[0], t->s, t->n);
+			fp = fmemopen(&buf[0], t->n, *p);
+			ATF_CHECK(fp != NULL);
+/*
+ * test fmemopen_seek(SEEK_CUR)
+ */
+#if defined(__GLIBC__)
+			if (i < (off_t)t->n) {
+#endif
+			/* zero */
+			ATF_CHECK(fseeko(fp, (off_t)0, SEEK_CUR) == 0);
+			ATF_CHECK(ftello(fp) == len);
+
+			/* posive */
+			for (i = (off_t)1; i <= rest; ++i) {
+				ATF_CHECK(fseeko(fp, (off_t)1, SEEK_CUR) == 0);
+				ATF_CHECK(ftello(fp) == len + i);
+			}
+
+			/* positive + OOB */
+			ATF_CHECK(fseeko(fp, (off_t)1, SEEK_CUR) == -1);
+			ATF_CHECK(ftello(fp) == (off_t)t->n);
+
+			/* negative */
+			for (i = (off_t)1; i <= (off_t)t->n; ++i) {
+				ATF_CHECK(fseeko(fp, (off_t)-1, SEEK_CUR) == 0);
+				ATF_CHECK(ftello(fp) == (off_t)t->n - i);
+			}
+
+			/* negative + OOB */
+			ATF_CHECK(fseeko(fp, (off_t)-1, SEEK_CUR) == -1);
+			ATF_CHECK(ftello(fp) == (off_t)0);
+
+#if defined(__GLIBC__)
+			}
+#endif
+			ATF_CHECK(fclose(fp) == 0);
+		}
+	}
+}
+
+ATF_TC(test12);
+ATF_TC_HEAD(test12, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "test12");
+}
+ATF_TC_BODY(test12, tc)
+{
+	struct testcase *t;
+	off_t len, rest, i;
+	const char **p;
+	char buf[BUFSIZ];
+	FILE *fp;
+
+	/* test fmemopen_seek(SEEK_END) */
+	for (t = &testcases[0]; t->s != NULL; ++t) {
+		len = (off_t)strnlen(t->s, t->n);
+		rest = t->n - len;
+		for (p = &mode_r[0]; *p != NULL; ++p) {
+
+			memcpy(buf, t->s, t->n);
+			fp = fmemopen(&buf[0], t->n, *p);
+			ATF_CHECK(fp != NULL);
+
+/*
+ * test fmemopen_seek(SEEK_END)
+ */
+#if !defined(__GLIBC__)
+			ATF_CHECK(ftello(fp) == (off_t)0);
+
+			/* zero */
+			ATF_CHECK(fseeko(fp, (off_t)0, SEEK_END) == 0);
+			ATF_CHECK(ftello(fp) == len);
+
+			/* positive + OOB */
+			ATF_CHECK(fseeko(fp, rest + 1, SEEK_END) == -1);
+			ATF_CHECK(ftello(fp) == len);
+
+			/* negative + OOB */
+			ATF_CHECK(fseeko(fp, -(len + 1), SEEK_END) == -1);
+			ATF_CHECK(ftello(fp) == len);
+
+			/* positive */
+			for (i = 1; i <= rest; ++i) {
+				ATF_CHECK(fseeko(fp, i, SEEK_END) == 0);
+				ATF_CHECK(ftello(fp) == len + i);
+			}
+
+			/* negative */
+			for (i = 1; i < len; ++i) {
+				ATF_CHECK(fseeko(fp, -i, SEEK_END) == 0);
+				ATF_CHECK(ftello(fp) == len - i);
+			}
+#endif
+			ATF_CHECK(fclose(fp) == 0);
+		}
+	}
+}
+
+ATF_TC(test13);
+ATF_TC_HEAD(test13, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "test13");
+}
+ATF_TC_BODY(test13, tc)
+{
+	struct testcase *t;
+	off_t len, rest, i;
+	const char **p;
+	char buf[BUFSIZ];
+	FILE *fp;
+
+	/* test fmemopen_seek(SEEK_END) */
+	for (t = &testcases[0]; t->s != NULL; ++t) {
+		len = (off_t)strnlen(t->s, t->n);
+		rest = t->n - len;
+		for (p = &mode_w[0]; *p != NULL; ++p) {
+
+			memcpy(buf, t->s, t->n);
+			fp = fmemopen(&buf[0], t->n, *p);
+			ATF_CHECK(fp != NULL);
+/*
+ * test fmemopen_seek(SEEK_END)
+ */
+#if !defined(__GLIBC__)
+			ATF_CHECK(ftello(fp) == (off_t)0);
+			ATF_CHECK(buf[0] == '\0');
+
+			/* zero */
+			ATF_CHECK(fseeko(fp, (off_t)0, SEEK_END) == 0);
+			ATF_CHECK(ftello(fp) == (off_t)0);
+
+			/* positive + OOB */
+			ATF_CHECK(fseeko(fp, (off_t)t->n + 1, SEEK_END) == -1);
+			ATF_CHECK(ftello(fp) == (off_t)0);
+
+			/* negative + OOB */
+			ATF_CHECK(fseeko(fp, -1, SEEK_END) == -1);
+			ATF_CHECK(ftello(fp) == (off_t)0);
+
+			/* positive */
+			for (i = 1; i <= t->n; ++i) {
+				ATF_CHECK(fseeko(fp, i, SEEK_END) == 0);
+				ATF_CHECK(ftello(fp) == i);
+			}
+#endif
+			ATF_CHECK(fclose(fp) == 0);
+		}
+	}
+}
+
+ATF_TC(test14);
+ATF_TC_HEAD(test14, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "test14");
+}
+ATF_TC_BODY(test14, tc)
+{
+	struct testcase *t;
+	off_t len, rest, i;
+	const char **p;
+	char buf[BUFSIZ];
+	FILE *fp;
+
+	/* test fmemopen_seek(SEEK_END) */
+	for (t = &testcases[0]; t->s != NULL; ++t) {
+		len = (off_t)strnlen(t->s, t->n);
+		rest = (off_t)t->n - len;
+		for (p = &mode_a[0]; *p != NULL; ++p) {
+
+			memcpy(buf, t->s, t->n);
+			fp = fmemopen(&buf[0], t->n, *p);
+			ATF_CHECK(fp != NULL);
+/*
+ * test fmemopen_seek(SEEK_END)
+ */
+#if !defined(__GLIBC__)
+			ATF_CHECK(ftello(fp) == len);
+
+			/* zero */
+			ATF_CHECK(fseeko(fp, 0, SEEK_END) == 0);
+			ATF_CHECK(ftello(fp) == len);
+
+			/* positive + OOB */
+			ATF_CHECK(fseeko(fp, rest + 1, SEEK_END) == -1);
+			ATF_CHECK(ftello(fp) == len);
+
+			/* negative + OOB */
+			ATF_CHECK(fseeko(fp, -(len + 1), SEEK_END) == -1);
+			ATF_CHECK(ftello(fp) == len);
+
+			/* positive */
+			for (i = 1; i <= rest; ++i) {
+				ATF_CHECK(fseeko(fp, i, SEEK_END) == 0);
+				ATF_CHECK(ftello(fp) == len + i);
+			}
+
+			/* negative */
+			for (i = 1; i < len; ++i) {
+				ATF_CHECK(fseeko(fp, -i, SEEK_END) == 0);
+				ATF_CHECK(ftello(fp) == len - i);
+			}
+#endif
+			ATF_CHECK(fclose(fp) == 0);
+		}
+	}
+}
+
+const char *mode_rw1[] = {
+    "r", "rb", "r+", "rb+", "r+b",
+    "w+", "wb+",
+    NULL
+};
+
+/* test15 - 18:
+ * When a stream open for writing is flushed or closed, a null byte is written
+ * at the current position or at the end of the buffer, depending on the size
+ * of the contents.
+ */
+
+ATF_TC(test15);
+ATF_TC_HEAD(test15, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "test15");
+}
+ATF_TC_BODY(test15, tc)
+{
+	struct testcase *t;
+	const char **p;
+	char buf0[BUFSIZ], buf1[BUFSIZ];
+	FILE *fp;
+	size_t i;
+
+	for (t = &testcases[0]; t->s != NULL; ++t) {
+		for (p = &mode_rw1[0]; *p != NULL; ++p) {
+
+			memcpy(&buf0[0], t->s, t->n);
+			fp = fmemopen(&buf0[0], t->n, *p);
+			ATF_CHECK(fp != NULL);
+/*
+ * test fmemopen_read + fgetc(3)
+ */
+			for (i = (size_t)0; i < t->n; ++i) {
+				ATF_CHECK(ftello(fp) == (off_t)i);
+				ATF_CHECK(fgetc(fp) == buf0[i]);
+				ATF_CHECK(feof(fp) == 0);
+				ATF_CHECK(ftello(fp) == (off_t)i + 1);
+			}
+			ATF_CHECK(fgetc(fp) == EOF);
+			ATF_CHECK(feof(fp) != 0);
+			ATF_CHECK(ftello(fp) == (off_t)t->n);
+			ATF_CHECK(fclose(fp) == 0);
+		}
+	}
+}
+
+ATF_TC(test16);
+ATF_TC_HEAD(test16, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "test16");
+}
+ATF_TC_BODY(test16, tc)
+{
+	struct testcase *t;
+	const char **p;
+	char buf0[BUFSIZ], buf1[BUFSIZ];
+	FILE *fp;
+
+	for (t = &testcases[0]; t->s != NULL; ++t) {
+		for (p = &mode_rw1[0]; *p != NULL; ++p) {
+
+			memcpy(&buf0[0], t->s, t->n);
+			buf1[t->n] = 0x1;
+			fp = fmemopen(&buf0[0], t->n, *p);
+			ATF_CHECK(fp != NULL);
+/*
+ * test fmemopen_read + fread(4)
+ */
+			ATF_CHECK(ftello(fp) == (off_t)0);
+			ATF_CHECK(fread(&buf1[0], 1, sizeof(buf1), fp) == t->n);
+			ATF_CHECK(feof(fp) != 0);
+			ATF_CHECK(memcmp(&buf0[0], &buf1[0], t->n) == 0);
+			ATF_CHECK((unsigned char)buf1[t->n] == 0x1);
+
+			ATF_CHECK(fclose(fp) == 0);
+		}
+	}
+}
+
+const char *mode_a1[] = { "a+", "ab+", NULL };
+
+ATF_TC(test17);
+ATF_TC_HEAD(test17, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "test17");
+}
+ATF_TC_BODY(test17, tc)
+{
+	struct testcase *t;
+	size_t len, i;
+	const char **p;
+	char buf[BUFSIZ];
+	FILE *fp;
+
+	for (t = &testcases[0]; t->s != NULL; ++t) {
+		len = strnlen(t->s, t->n);
+		for (p = &mode_a1[0]; *p != NULL; ++p) {
+
+			memcpy(&buf[0], t->s, t->n);
+			fp = fmemopen(&buf[0], t->n, *p);
+			ATF_CHECK(fp != NULL);
+/*
+ * test fmemopen_read + fgetc(3)
+ */
+#if defined(__GLIBC__)
+			if (i < t->n) {
+#endif
+			for (i = len; i < t->n; ++i) {
+				ATF_CHECK(ftello(fp) == (off_t)i);
+				ATF_CHECK(fgetc(fp) == buf[i]);
+				ATF_CHECK(feof(fp) == 0);
+				ATF_CHECK(ftello(fp) == (off_t)i + 1);
+			}
+			ATF_CHECK(fgetc(fp) == EOF);
+			ATF_CHECK(feof(fp) != 0);
+			ATF_CHECK(ftello(fp) == (off_t)t->n);
+			rewind(fp);
+			for (i = (size_t)0; i < t->n; ++i) {
+				ATF_CHECK(ftello(fp) == (off_t)i);
+				ATF_CHECK(fgetc(fp) == buf[i]);
+				ATF_CHECK(feof(fp) == 0);
+				ATF_CHECK(ftello(fp) == (off_t)i + 1);
+			}
+			ATF_CHECK(fgetc(fp) == EOF);
+			ATF_CHECK(feof(fp) != 0);
+			ATF_CHECK(ftello(fp) == (off_t)t->n);
+#if defined(__GLIBC__)
+			}
+#endif
+			ATF_CHECK(fclose(fp) == 0);
+		}
+	}
+}
+
+ATF_TC(test18);
+ATF_TC_HEAD(test18, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "test18");
+}
+ATF_TC_BODY(test18, tc)
+{
+	struct testcase *t;
+	size_t len, i;
+	const char **p;
+	char buf0[BUFSIZ], buf1[BUFSIZ];
+	FILE *fp;
+
+	for (t = &testcases[0]; t->s != NULL; ++t) {
+		len = strnlen(t->s, t->n);
+		for (p = &mode_a1[0]; *p != NULL; ++p) {
+
+			memcpy(&buf0[0], t->s, t->n);
+			buf1[t->n - len] = 0x1;
+			fp = fmemopen(&buf0[0], t->n, *p);
+			ATF_CHECK(fp != NULL);
+/*
+ * test fmemopen_read + fread(3)
+ */
+#if defined(__GLIBC__)
+			if (i < t->n) {
+#endif
+			ATF_CHECK(ftello(fp) == (off_t)len);
+			ATF_CHECK(fread(&buf1[0], 1, sizeof(buf1), fp)
+			    == t->n - len);
+			ATF_CHECK(feof(fp) != 0);
+			ATF_CHECK(!memcmp(&buf0[len], &buf1[0], t->n - len));
+			ATF_CHECK((unsigned char)buf1[t->n - len] == 0x1);
+			rewind(fp);
+			buf1[t->n] = 0x1;
+			ATF_CHECK(ftello(fp) == (off_t)0);
+			ATF_CHECK(fread(&buf1[0], 1, sizeof(buf1), fp)
+			    == t->n);
+			ATF_CHECK(feof(fp) != 0);
+			ATF_CHECK(!memcmp(&buf0[0], &buf1[0], t->n));
+			ATF_CHECK((unsigned char)buf1[t->n] == 0x1);
+#if defined(__GLIBC__)
+			}
+#endif
+			ATF_CHECK(fclose(fp) == 0);
+		}
+	}
+}
+
+/*
+ * test19 - test22:
+ * If a stream open for update is flushed or closed and the last write has
+ * advanced the current buffer size, a null byte is written at the end of the
+ * buffer if it fits.
+ */
+
+const char *mode_rw2[] = {
+    "r+", "rb+", "r+b",
+    "w", "wb", "w+", "wb+", "w+b",
+    NULL
+};
+
+ATF_TC(test19);
+ATF_TC_HEAD(test19, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "test19");
+}
+ATF_TC_BODY(test19, tc)
+{
+	struct testcase *t;
+	size_t len, i;
+	const char **p;
+	char buf[BUFSIZ];
+	FILE *fp;
+
+	for (t = &testcases[0]; t->s != NULL; ++t) {
+		len = strnlen(t->s, t->n);
+		for (p = &mode_rw2[0]; *p != NULL; ++p) {
+
+			memcpy(&buf[0], t->s, t->n);
+			buf[t->n] = 0x1;
+			fp = fmemopen(&buf[0], t->n + 1, *p);
+			ATF_CHECK(fp != NULL);
+			setbuf(fp, NULL);
+/*
+ * test fmemopen_write + fputc(3)
+ */
+			for (i = (size_t)0; i < t->n; ++i) {
+				ATF_CHECK(ftello(fp) == (off_t)i);
+				ATF_CHECK(fputc(t->s[i], fp) == t->s[i]);
+				ATF_CHECK(buf[i] == t->s[i]);
+				ATF_CHECK(ftello(fp) == (off_t)i + 1);
+				ATF_CHECK(buf[i] == t->s[i]);
+#if !defined(__GLIBC__)
+				ATF_CHECK(buf[i + 1] == '\0');
+#endif
+			}
+
+/* don't accept non nul character at end of buffer */
+			ATF_CHECK(fputc(0x1, fp) == EOF);
+			ATF_CHECK(ftello(fp) == (off_t)t->n);
+			ATF_CHECK(feof(fp) == 0);
+
+/* accept nul character at end of buffer */
+			ATF_CHECK(fputc('\0', fp) == '\0');
+			ATF_CHECK(ftello(fp) == (off_t)t->n + 1);
+			ATF_CHECK(feof(fp) == 0);
+
+/* reach EOF */
+			ATF_CHECK(fputc('\0', fp) == EOF);
+			ATF_CHECK(ftello(fp) == (off_t)t->n + 1);
+
+			/* compare */
+			ATF_CHECK(memcmp(&buf[0], t->s, t->n) == 0);
+			ATF_CHECK(buf[t->n] == '\0');
+
+			ATF_CHECK(fclose(fp) == 0);
+		}
+	}
+}
+
+ATF_TC(test20);
+ATF_TC_HEAD(test20, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "test20");
+}
+ATF_TC_BODY(test20, tc)
+{
+	struct testcase *t;
+	size_t len, i;
+	const char **p;
+	char buf[BUFSIZ];
+	FILE *fp;
+
+	for (t = &testcases[0]; t->s != NULL; ++t) {
+		len = strnlen(t->s, t->n);
+		for (p = &mode_rw2[0]; *p != NULL; ++p) {
+
+			memcpy(&buf[0], t->s, t->n);
+			buf[t->n] = 0x1;
+			fp = fmemopen(&buf[0], t->n + 1, *p);
+			ATF_CHECK(fp != NULL);
+			setbuf(fp, NULL);
+			ATF_CHECK(fwrite(t->s, 1, t->n, fp) == t->n);
+/*
+ * test fmemopen_write + fwrite(3)
+ */
+#if !defined(__GLIBC__)
+			ATF_CHECK(buf[t->n] == '\0');
+
+/* don't accept non nul character at end of buffer */
+			ATF_CHECK(fwrite("\x1", 1, 1, fp) == 0);
+			ATF_CHECK(ftello(fp) == (off_t)t->n);
+			ATF_CHECK(feof(fp) == 0);
+#endif
+
+/* accept nul character at end of buffer */
+			ATF_CHECK(fwrite("\x0", 1, 1, fp) == 1);
+			ATF_CHECK(ftello(fp) == (off_t)t->n + 1);
+			ATF_CHECK(feof(fp) == 0);
+
+/* reach EOF */
+			ATF_CHECK(fputc('\0', fp) == EOF);
+			ATF_CHECK(ftello(fp) == (off_t)t->n + 1);
+
+/* compare */
+			ATF_CHECK(memcmp(&buf[0], t->s, t->n) == 0);
+			ATF_CHECK(buf[t->n] == '\0');
+
+			ATF_CHECK(fclose(fp) == 0);
+		}
+	}
+}
+
+ATF_TC(test21);
+ATF_TC_HEAD(test21, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "test21");
+}
+ATF_TC_BODY(test21, tc)
+{
+	struct testcase *t;
+	size_t len, i;
+	const char **p;
+	char buf[BUFSIZ];
+	FILE *fp;
+
+	for (t = &testcases[0]; t->s != NULL; ++t) {
+		len = strnlen(t->s, t->n);
+		for (p = &mode_a[0]; *p != NULL; ++p) {
+			memcpy(&buf[0], t->s, t->n);
+			fp = fmemopen(&buf[0], t->n, *p);
+			ATF_CHECK(fp != NULL);
+			setbuf(fp, NULL);
+/*
+ * test fmemopen_write + fputc(3)
+ */
+			if (len < t->n) {
+				for (i = len; i < t->n - 1; ++i) {
+					ATF_CHECK(ftello(fp) == (off_t)i);
+					ATF_CHECK(fputc(t->s[i - len], fp)
+					    == t->s[i - len]);
+					ATF_CHECK(buf[i] == t->s[i - len]);
+					ATF_CHECK(ftello(fp) == (off_t)i + 1);
+#if !defined(__GLIBC__)
+					ATF_CHECK(buf[i + 1] == '\0');
+#endif
+				}
+
+/* don't accept non nul character at end of buffer */
+				ATF_CHECK(ftello(fp) == (off_t)t->n - 1);
+				ATF_CHECK(fputc(0x1, fp) == EOF);
+				ATF_CHECK(ftello(fp) == (off_t)t->n - 1);
+
+/* accept nul character at end of buffer */
+				ATF_CHECK(ftello(fp) == (off_t)t->n - 1);
+				ATF_CHECK(fputc('\0', fp) == '\0');
+				ATF_CHECK(ftello(fp) == (off_t)t->n);
+			}
+
+/* reach EOF */
+			ATF_CHECK(ftello(fp) == (off_t)t->n);
+			ATF_CHECK(fputc('\0', fp) == EOF);
+			ATF_CHECK(ftello(fp) == (off_t)t->n);
+
+			ATF_CHECK(fclose(fp) == 0);
+		}
+	}
+}
+
+ATF_TC(test22);
+ATF_TC_HEAD(test22, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "test22");
+}
+ATF_TC_BODY(test22, tc)
+{
+	struct testcase *t0, *t1;
+	size_t len0, len1, i, nleft;
+	const char **p;
+	char buf[BUFSIZ];
+	FILE *fp;
+
+	for (t0 = &testcases[0]; t0->s != NULL; ++t0) {
+		len0 = strnlen(t0->s, t0->n);
+		for (t1 = &testcases[0]; t1->s != NULL; ++t1) {
+			len1 = strnlen(t1->s, t1->n);
+			for (p = &mode_a[0]; *p != NULL; ++p) {
+
+				memcpy(&buf[0], t0->s, t0->n);
+				fp = fmemopen(&buf[0], t0->n, *p);
+				ATF_CHECK(fp != NULL);
+				setbuf(fp, NULL);
+/*
+ * test fmemopen_write + fwrite(3)
+ */
+				nleft = t0->n - len0;
+#if !defined(__GLIBC__)
+				if (nleft == 0 || len1 == nleft - 1) {
+					ATF_CHECK(fwrite(t1->s, 1, t1->n, fp)
+					    == nleft);
+					ATF_CHECK(ftell(fp) == t1->n);
+				} else {
+					ATF_CHECK(fwrite(t1->s, 1, t1->n, fp)
+					    == nleft - 1);
+					ATF_CHECK(ftell(fp) == t1->n - 1);
+				}
+#endif
+				ATF_CHECK(fclose(fp) == 0);
+			}
+		}
+	}
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+	ATF_TP_ADD_TC(tp, test00);
+	ATF_TP_ADD_TC(tp, test01);
+	ATF_TP_ADD_TC(tp, test02);
+	ATF_TP_ADD_TC(tp, test03);
+	ATF_TP_ADD_TC(tp, test04);
+	ATF_TP_ADD_TC(tp, test05);
+	ATF_TP_ADD_TC(tp, test06);
+	ATF_TP_ADD_TC(tp, test07);
+	ATF_TP_ADD_TC(tp, test08);
+	ATF_TP_ADD_TC(tp, test09);
+	ATF_TP_ADD_TC(tp, test10);
+	ATF_TP_ADD_TC(tp, test11);
+	ATF_TP_ADD_TC(tp, test12);
+	ATF_TP_ADD_TC(tp, test13);
+	ATF_TP_ADD_TC(tp, test14);
+	ATF_TP_ADD_TC(tp, test15);
+	ATF_TP_ADD_TC(tp, test16);
+	ATF_TP_ADD_TC(tp, test17);
+	ATF_TP_ADD_TC(tp, test18);
+	ATF_TP_ADD_TC(tp, test19);
+	ATF_TP_ADD_TC(tp, test20);
+	ATF_TP_ADD_TC(tp, test21);
+	ATF_TP_ADD_TC(tp, test22);
+
+	return atf_no_error();
+}

Reply via email to