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();
+}