summaryrefslogtreecommitdiff
path: root/lib/libc/tests/stdio
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc/tests/stdio')
-rw-r--r--lib/libc/tests/stdio/Makefile44
-rw-r--r--lib/libc/tests/stdio/Makefile.depend20
-rw-r--r--lib/libc/tests/stdio/fdopen_test.c225
-rw-r--r--lib/libc/tests/stdio/fmemopen2_test.c288
-rw-r--r--lib/libc/tests/stdio/fopen_test.c205
-rw-r--r--lib/libc/tests/stdio/freopen_test.c223
-rw-r--r--lib/libc/tests/stdio/getdelim_test.c235
-rw-r--r--lib/libc/tests/stdio/gets_s_test.c145
-rw-r--r--lib/libc/tests/stdio/mkostemp_test.c185
-rw-r--r--lib/libc/tests/stdio/open_memstream2_test.c201
-rw-r--r--lib/libc/tests/stdio/open_wmemstream_test.c201
-rw-r--r--lib/libc/tests/stdio/perror_test.c107
-rw-r--r--lib/libc/tests/stdio/print_positional_test.c157
-rw-r--r--lib/libc/tests/stdio/printbasic_test.c162
-rw-r--r--lib/libc/tests/stdio/printfloat_test.c389
-rw-r--r--lib/libc/tests/stdio/scanfloat_test.c316
16 files changed, 3103 insertions, 0 deletions
diff --git a/lib/libc/tests/stdio/Makefile b/lib/libc/tests/stdio/Makefile
new file mode 100644
index 0000000000000..248a05bc45e78
--- /dev/null
+++ b/lib/libc/tests/stdio/Makefile
@@ -0,0 +1,44 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+ATF_TESTS_C+= fdopen_test
+ATF_TESTS_C+= fmemopen2_test
+ATF_TESTS_C+= fopen2_test
+ATF_TESTS_C+= freopen_test
+ATF_TESTS_C+= getdelim_test
+ATF_TESTS_C+= gets_s_test
+ATF_TESTS_C+= mkostemp_test
+ATF_TESTS_C+= open_memstream2_test
+ATF_TESTS_C+= open_wmemstream_test
+ATF_TESTS_C+= perror_test
+ATF_TESTS_C+= print_positional_test
+ATF_TESTS_C+= printbasic_test
+ATF_TESTS_C+= printfloat_test
+ATF_TESTS_C+= scanfloat_test
+
+SRCS.fopen2_test= fopen_test.c
+
+NETBSD_ATF_TESTS_C= clearerr_test
+NETBSD_ATF_TESTS_C+= fflush_test
+NETBSD_ATF_TESTS_C+= fmemopen_test
+NETBSD_ATF_TESTS_C+= fopen_test
+NETBSD_ATF_TESTS_C+= fputc_test
+NETBSD_ATF_TESTS_C+= mktemp_test
+NETBSD_ATF_TESTS_C+= open_memstream_test
+NETBSD_ATF_TESTS_C+= popen_test
+NETBSD_ATF_TESTS_C+= printf_test
+NETBSD_ATF_TESTS_C+= scanf_test
+
+LIBADD.printfloat_test+= m
+LIBADD.scanfloat_test+= m
+
+.if ${COMPILER_TYPE} == "gcc"
+# 90: use of assignment suppression and length modifier together in scanf format
+PROG_OVERRIDE_VARS+= NO_WFORMAT
+NO_WFORMAT.scanfloat_test=
+.endif
+
+.include "../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/stdio/Makefile.depend b/lib/libc/tests/stdio/Makefile.depend
new file mode 100644
index 0000000000000..45823695c1bb5
--- /dev/null
+++ b/lib/libc/tests/stdio/Makefile.depend
@@ -0,0 +1,20 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/atf/libatf-c \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libnetbsd \
+ lib/msun \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/stdio/fdopen_test.c b/lib/libc/tests/stdio/fdopen_test.c
new file mode 100644
index 0000000000000..060635af498b6
--- /dev/null
+++ b/lib/libc/tests/stdio/fdopen_test.c
@@ -0,0 +1,225 @@
+/*-
+ * Copyright (c) 2014 Jilles Tjoelker
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+static void
+runtest(const char *fname, int intmode, const char *strmode, bool success)
+{
+ FILE *fp;
+ int fd;
+
+ fd = open(fname, intmode);
+ ATF_REQUIRE_MSG(fd != -1,
+ "open(\"%s\", %#x) failed; errno=%d", fname, intmode, errno);
+
+ fp = fdopen(fd, strmode);
+ if (fp == NULL) {
+ close(fd);
+ ATF_REQUIRE_MSG(success == false,
+ "fdopen(open(\"%s\", %#x), \"%s\") succeeded unexpectedly",
+ fname, intmode, strmode);
+ return;
+ }
+ ATF_REQUIRE_MSG(success == true,
+ "fdopen(open(\"%s\", %#x), \"%s\") failed; errno=%d",
+ fname, intmode, strmode, errno);
+ fclose(fp);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_RDONLY__r_test);
+ATF_TC_BODY(null__O_RDONLY__r_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_RDONLY, "r", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_WRONLY__r_test);
+ATF_TC_BODY(null__O_WRONLY__r_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_WRONLY, "r", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_RDWR__r_test);
+ATF_TC_BODY(null__O_RDWR__r_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_RDWR, "r", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_RDONLY__w_test);
+ATF_TC_BODY(null__O_RDONLY__w_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_RDONLY, "w", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_WRONLY__w_test);
+ATF_TC_BODY(null__O_WRONLY__w_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_WRONLY, "w", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_RDWR__w_test);
+ATF_TC_BODY(null__O_RDWR__w_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_RDWR, "w", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_RDONLY__a_test);
+ATF_TC_BODY(null__O_RDONLY__a_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_RDONLY, "a", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_WRONLY__a_test);
+ATF_TC_BODY(null__O_WRONLY__a_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_WRONLY, "a", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_RDWR__test);
+ATF_TC_BODY(null__O_RDWR__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_RDWR, "a", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_RDONLY__r_append);
+ATF_TC_BODY(null__O_RDONLY__r_append, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_RDONLY, "r+", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_WRONLY__r_append);
+ATF_TC_BODY(null__O_WRONLY__r_append, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_WRONLY, "r+", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_RDWR__r_append);
+ATF_TC_BODY(null__O_RDWR__r_append, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_RDWR, "r+", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_RDONLY__w_append);
+ATF_TC_BODY(null__O_RDONLY__w_append, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_RDONLY, "w+", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_WRONLY__w_append);
+ATF_TC_BODY(null__O_WRONLY__w_append, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_WRONLY, "w+", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_RDWR__w_append);
+ATF_TC_BODY(null__O_RDWR__w_append, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_RDWR, "w+", true);
+}
+
+ATF_TC_WITHOUT_HEAD(sh__O_EXEC__r);
+ATF_TC_BODY(sh__O_EXEC__r, tc)
+{
+
+ runtest("/bin/sh", O_EXEC, "r", false);
+}
+
+ATF_TC_WITHOUT_HEAD(sh__O_EXEC__w);
+ATF_TC_BODY(sh__O_EXEC__w, tc)
+{
+
+ runtest("/bin/sh", O_EXEC, "w", false);
+}
+
+ATF_TC_WITHOUT_HEAD(sh__O_EXEC__r_append);
+ATF_TC_BODY(sh__O_EXEC__r_append, tc)
+{
+
+ runtest("/bin/sh", O_EXEC, "r+", false);
+}
+
+ATF_TC_WITHOUT_HEAD(sh__O_EXEC__w_append);
+ATF_TC_BODY(sh__O_EXEC__w_append, tc)
+{
+
+ runtest("/bin/sh", O_EXEC, "w+", false);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, null__O_RDONLY__r_test);
+ ATF_TP_ADD_TC(tp, null__O_WRONLY__r_test);
+ ATF_TP_ADD_TC(tp, null__O_RDWR__r_test);
+ ATF_TP_ADD_TC(tp, null__O_RDONLY__w_test);
+ ATF_TP_ADD_TC(tp, null__O_WRONLY__w_test);
+ ATF_TP_ADD_TC(tp, null__O_RDWR__w_test);
+ ATF_TP_ADD_TC(tp, null__O_RDONLY__a_test);
+ ATF_TP_ADD_TC(tp, null__O_WRONLY__a_test);
+ ATF_TP_ADD_TC(tp, null__O_RDWR__test);
+ ATF_TP_ADD_TC(tp, null__O_RDONLY__r_append);
+ ATF_TP_ADD_TC(tp, null__O_WRONLY__r_append);
+ ATF_TP_ADD_TC(tp, null__O_RDWR__r_append);
+ ATF_TP_ADD_TC(tp, null__O_RDONLY__w_append);
+ ATF_TP_ADD_TC(tp, null__O_WRONLY__w_append);
+ ATF_TP_ADD_TC(tp, null__O_RDWR__w_append);
+ ATF_TP_ADD_TC(tp, sh__O_EXEC__r);
+ ATF_TP_ADD_TC(tp, sh__O_EXEC__w);
+ ATF_TP_ADD_TC(tp, sh__O_EXEC__r_append);
+ ATF_TP_ADD_TC(tp, sh__O_EXEC__w_append);
+
+ return (atf_no_error());
+}
+
+/*
+ vim:ts=8:cin:sw=8
+ */
diff --git a/lib/libc/tests/stdio/fmemopen2_test.c b/lib/libc/tests/stdio/fmemopen2_test.c
new file mode 100644
index 0000000000000..a2ca3257fe4e7
--- /dev/null
+++ b/lib/libc/tests/stdio/fmemopen2_test.c
@@ -0,0 +1,288 @@
+/*-
+Copyright (C) 2013 Pietro Cerutti <gahr@FreeBSD.org>
+
+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 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 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.
+*/
+
+/*
+ * Test basic FILE * functions (fread, fwrite, fseek, fclose) against
+ * a FILE * retrieved using fmemopen()
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+
+#include <atf-c.h>
+
+ATF_TC_WITHOUT_HEAD(test_preexisting);
+ATF_TC_BODY(test_preexisting, tc)
+{
+ /* Use a pre-existing buffer. */
+ char buf[512];
+ char buf2[512];
+ char str[] = "Test writing some stuff";
+ char str2[] = "AAAAAAAAA";
+ char str3[] = "AAAA writing some stuff";
+ FILE *fp;
+ size_t nofw, nofr;
+ int rc;
+
+ /* Open a FILE * using fmemopen. */
+ fp = fmemopen(buf, sizeof(buf), "w");
+ ATF_REQUIRE(fp != NULL);
+
+ /* Write to the buffer. */
+ nofw = fwrite(str, 1, sizeof(str), fp);
+ ATF_REQUIRE(nofw == sizeof(str));
+
+ /* Close the FILE *. */
+ rc = fclose(fp);
+ ATF_REQUIRE(rc == 0);
+
+ /* Re-open the FILE * to read back the data. */
+ fp = fmemopen(buf, sizeof(buf), "r");
+ ATF_REQUIRE(fp != NULL);
+
+ /* Read from the buffer. */
+ bzero(buf2, sizeof(buf2));
+ nofr = fread(buf2, 1, sizeof(buf2), fp);
+ ATF_REQUIRE(nofr == sizeof(buf2));
+
+ /*
+ * Since a write on a FILE * retrieved by fmemopen
+ * will add a '\0' (if there's space), we can check
+ * the strings for equality.
+ */
+ ATF_REQUIRE(strcmp(str, buf2) == 0);
+
+ /* Close the FILE *. */
+ rc = fclose(fp);
+ ATF_REQUIRE(rc == 0);
+
+ /* Now open a FILE * on the first 4 bytes of the string. */
+ fp = fmemopen(str, 4, "w");
+ ATF_REQUIRE(fp != NULL);
+
+ /*
+ * Try to write more bytes than we shoud, we'll get a short count (4).
+ */
+ nofw = fwrite(str2, 1, sizeof(str2), fp);
+ ATF_REQUIRE(nofw == 4);
+
+ /* Close the FILE *. */
+ rc = fclose(fp);
+ ATF_REQUIRE(rc == 0);
+
+ /* Check that the string was not modified after the first 4 bytes. */
+ ATF_REQUIRE(strcmp(str, str3) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(test_autoalloc);
+ATF_TC_BODY(test_autoalloc, tc)
+{
+ /* Let fmemopen allocate the buffer. */
+ FILE *fp;
+ long pos;
+ size_t nofw, i;
+ int rc;
+
+ /* Open a FILE * using fmemopen. */
+ fp = fmemopen(NULL, 512, "w+");
+ ATF_REQUIRE(fp != NULL);
+
+ /* fill the buffer */
+ for (i = 0; i < 512; i++) {
+ nofw = fwrite("a", 1, 1, fp);
+ ATF_REQUIRE(nofw == 1);
+ }
+
+ /* Get the current position into the stream. */
+ pos = ftell(fp);
+ ATF_REQUIRE(pos == 512);
+
+ /* Try to write past the end, we should get a short object count (0) */
+ nofw = fwrite("a", 1, 1, fp);
+ ATF_REQUIRE(nofw == 0);
+
+ /* Close the FILE *. */
+ rc = fclose(fp);
+ ATF_REQUIRE(rc == 0);
+
+ /* Open a FILE * using a wrong mode */
+ fp = fmemopen(NULL, 512, "r");
+ ATF_REQUIRE(fp == NULL);
+
+ fp = fmemopen(NULL, 512, "w");
+ ATF_REQUIRE(fp == NULL);
+}
+
+ATF_TC_WITHOUT_HEAD(test_data_length);
+ATF_TC_BODY(test_data_length, tc)
+{
+ /*
+ * Here we test that a read operation doesn't go past the end of the
+ * data actually written, and that a SEEK_END seeks from the end of the
+ * data, not of the whole buffer.
+ */
+ FILE *fp;
+ char buf[512] = {'\0'};
+ char str[] = "Test data length. ";
+ char str2[] = "Do we have two sentences?";
+ char str3[sizeof(str) + sizeof(str2) -1];
+ long pos;
+ size_t nofw, nofr;
+ int rc;
+
+ /* Open a FILE * for updating our buffer. */
+ fp = fmemopen(buf, sizeof(buf), "w+");
+ ATF_REQUIRE(fp != NULL);
+
+ /* Write our string into the buffer. */
+ nofw = fwrite(str, 1, sizeof(str), fp);
+ ATF_REQUIRE(nofw == sizeof(str));
+
+ /* Now seek to the end and check that ftell gives us sizeof(str). */
+ rc = fseek(fp, 0, SEEK_END);
+ ATF_REQUIRE(rc == 0);
+ pos = ftell(fp);
+ ATF_REQUIRE(pos == sizeof(str));
+
+ /* Close the FILE *. */
+ rc = fclose(fp);
+ ATF_REQUIRE(rc == 0);
+
+ /* Reopen the buffer for appending. */
+ fp = fmemopen(buf, sizeof(buf), "a+");
+ ATF_REQUIRE(fp != NULL);
+
+ /* We should now be writing after the first string. */
+ nofw = fwrite(str2, 1, sizeof(str2), fp);
+ ATF_REQUIRE(nofw == sizeof(str2));
+
+ /* Rewind the FILE *. */
+ rc = fseek(fp, 0, SEEK_SET);
+ ATF_REQUIRE(rc == 0);
+
+ /* Make sure we're at the beginning. */
+ pos = ftell(fp);
+ ATF_REQUIRE(pos == 0);
+
+ /* Read the whole buffer. */
+ nofr = fread(str3, 1, sizeof(buf), fp);
+ ATF_REQUIRE(nofr == sizeof(str3));
+
+ /* Make sure the two strings are there. */
+ ATF_REQUIRE(strncmp(str3, str, sizeof(str) - 1) == 0);
+ ATF_REQUIRE(strncmp(str3 + sizeof(str) - 1, str2, sizeof(str2)) == 0);
+
+ /* Close the FILE *. */
+ rc = fclose(fp);
+ ATF_REQUIRE(rc == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(test_binary);
+ATF_TC_BODY(test_binary, tc)
+{
+ /*
+ * Make sure that NULL bytes are never appended when opening a buffer
+ * in binary mode.
+ */
+
+ FILE *fp;
+ char buf[20];
+ char str[] = "Test";
+ size_t nofw;
+ int rc, i;
+
+ /* Pre-fill the buffer. */
+ memset(buf, 'A', sizeof(buf));
+
+ /* Open a FILE * in binary mode. */
+ fp = fmemopen(buf, sizeof(buf), "w+b");
+ ATF_REQUIRE(fp != NULL);
+
+ /* Write some data into it. */
+ nofw = fwrite(str, 1, strlen(str), fp);
+ ATF_REQUIRE(nofw == strlen(str));
+
+ /* Make sure that the buffer doesn't contain any NULL bytes. */
+ for (i = 0; i < sizeof(buf); i++)
+ ATF_REQUIRE(buf[i] != '\0');
+
+ /* Close the FILE *. */
+ rc = fclose(fp);
+ ATF_REQUIRE(rc == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(test_append_binary_pos);
+ATF_TC_BODY(test_append_binary_pos, tc)
+{
+ /*
+ * For compatibility with other implementations (glibc), we set the
+ * position to 0 when opening an automatically allocated binary stream
+ * for appending.
+ */
+
+ FILE *fp;
+
+ fp = fmemopen(NULL, 16, "ab+");
+ ATF_REQUIRE(fp != NULL);
+ ATF_REQUIRE(ftell(fp) == 0L);
+ fclose(fp);
+
+ /* Make sure that a pre-allocated buffer behaves correctly. */
+ char buf[] = "Hello";
+ fp = fmemopen(buf, sizeof(buf), "ab+");
+ ATF_REQUIRE(fp != NULL);
+ ATF_REQUIRE(ftell(fp) == strlen(buf));
+ fclose(fp);
+}
+
+ATF_TC_WITHOUT_HEAD(test_size_0);
+ATF_TC_BODY(test_size_0, tc)
+{
+ /* POSIX mandates that we return EINVAL if size is 0. */
+
+ FILE *fp;
+
+ fp = fmemopen(NULL, 0, "r+");
+ ATF_REQUIRE(fp == NULL);
+ ATF_REQUIRE(errno == EINVAL);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, test_autoalloc);
+ ATF_TP_ADD_TC(tp, test_preexisting);
+ ATF_TP_ADD_TC(tp, test_data_length);
+ ATF_TP_ADD_TC(tp, test_binary);
+ ATF_TP_ADD_TC(tp, test_append_binary_pos);
+ ATF_TP_ADD_TC(tp, test_size_0);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdio/fopen_test.c b/lib/libc/tests/stdio/fopen_test.c
new file mode 100644
index 0000000000000..962e7fdb1a34a
--- /dev/null
+++ b/lib/libc/tests/stdio/fopen_test.c
@@ -0,0 +1,205 @@
+/*-
+ * Copyright (c) 2013 Jilles Tjoelker
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#include <fcntl.h>
+#include <paths.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+/*
+ * O_ACCMODE is currently defined incorrectly. This is what it should be.
+ * Various code depends on the incorrect value.
+ */
+#define CORRECT_O_ACCMODE (O_ACCMODE | O_EXEC)
+
+static void
+runtest(const char *fname, const char *mode)
+{
+ FILE *fp;
+ int exp_fget_ret, fget_ret, fd, flags, wantedflags;
+
+ fp = fopen(fname, mode);
+ ATF_REQUIRE_MSG(fp != NULL,
+ "fopen(\"%s\", \"%s\") failed", fname, mode);
+ fd = fileno(fp);
+ ATF_REQUIRE_MSG(fd >= 0, "fileno() failed for fopen");
+ exp_fget_ret = strchr(mode, 'e') != NULL ? FD_CLOEXEC : 0;
+ ATF_REQUIRE_MSG((fget_ret = fcntl(fd, F_GETFD)) == exp_fget_ret,
+ "fcntl(.., F_GETFD) didn't FD_CLOEXEC as expected %d != %d",
+ exp_fget_ret, fget_ret);
+ flags = fcntl(fd, F_GETFL);
+ if (strchr(mode, '+'))
+ wantedflags = O_RDWR | (*mode == 'a' ? O_APPEND : 0);
+ else if (*mode == 'r')
+ wantedflags = O_RDONLY;
+ else if (*mode == 'w')
+ wantedflags = O_WRONLY;
+ else if (*mode == 'a')
+ wantedflags = O_WRONLY | O_APPEND;
+ else
+ wantedflags = -1;
+ fclose(fp);
+ if (wantedflags == -1)
+ atf_tc_fail("unrecognized mode: %s", mode);
+ else if ((flags & (CORRECT_O_ACCMODE | O_APPEND)) != wantedflags)
+ atf_tc_fail("incorrect access mode: %s", mode);
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_r_test);
+ATF_TC_BODY(fopen_r_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_r_append_test);
+ATF_TC_BODY(fopen_r_append_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r+");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_w_test);
+ATF_TC_BODY(fopen_w_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "w");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_w_append_test);
+ATF_TC_BODY(fopen_w_append_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "w+");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_a_test);
+ATF_TC_BODY(fopen_a_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "a");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_a_append_test);
+ATF_TC_BODY(fopen_a_append_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "a+");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_re_test);
+ATF_TC_BODY(fopen_re_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "re");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_r_append_e_test);
+ATF_TC_BODY(fopen_r_append_e_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r+e");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_we_test);
+ATF_TC_BODY(fopen_we_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "we");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_w_append_e_test);
+ATF_TC_BODY(fopen_w_append_e_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "w+e");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_ae_test);
+ATF_TC_BODY(fopen_ae_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "ae");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_a_append_e_test);
+ATF_TC_BODY(fopen_a_append_e_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "a+e");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_re_append_test);
+ATF_TC_BODY(fopen_re_append_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "re+");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_we_append_test);
+ATF_TC_BODY(fopen_we_append_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "we+");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_ae_append_test);
+ATF_TC_BODY(fopen_ae_append_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "ae+");
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, fopen_r_test);
+ ATF_TP_ADD_TC(tp, fopen_r_append_test);
+ ATF_TP_ADD_TC(tp, fopen_w_test);
+ ATF_TP_ADD_TC(tp, fopen_w_append_test);
+ ATF_TP_ADD_TC(tp, fopen_a_test);
+ ATF_TP_ADD_TC(tp, fopen_a_append_test);
+ ATF_TP_ADD_TC(tp, fopen_re_test);
+ ATF_TP_ADD_TC(tp, fopen_r_append_e_test);
+ ATF_TP_ADD_TC(tp, fopen_we_test);
+ ATF_TP_ADD_TC(tp, fopen_w_append_e_test);
+ ATF_TP_ADD_TC(tp, fopen_ae_test);
+ ATF_TP_ADD_TC(tp, fopen_a_append_e_test);
+ ATF_TP_ADD_TC(tp, fopen_re_append_test);
+ ATF_TP_ADD_TC(tp, fopen_we_append_test);
+ ATF_TP_ADD_TC(tp, fopen_ae_append_test);
+
+ return (atf_no_error());
+}
+
+/*
+ vim:ts=8:cin:sw=8
+ */
diff --git a/lib/libc/tests/stdio/freopen_test.c b/lib/libc/tests/stdio/freopen_test.c
new file mode 100644
index 0000000000000..8ca4719e86034
--- /dev/null
+++ b/lib/libc/tests/stdio/freopen_test.c
@@ -0,0 +1,223 @@
+/*-
+ * Copyright (c) 2014 Jilles Tjoelker
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <paths.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+static void
+runtest(const char *fname1, const char *mode1, const char *fname2,
+ const char *mode2, bool success)
+{
+ FILE *fp1, *fp2;
+ const char *fname2_print;
+
+ fname2_print = fname2 != NULL ? fname2 : "<NULL>";
+ fp1 = fopen(fname1, mode1);
+ ATF_REQUIRE_MSG(fp1 != NULL,
+ "fopen(\"%s\", \"%s\") failed; errno=%d", fname1, mode1, errno);
+ fp2 = freopen(fname2, mode2, fp1);
+ if (fp2 == NULL) {
+ ATF_REQUIRE_MSG(success == false,
+ "freopen(\"%s\", \"%s\", fopen(\"%s\", \"%s\")) succeeded "
+ "unexpectedly", fname2_print, mode2, fname1, mode1);
+ return;
+ }
+ ATF_REQUIRE_MSG(success == true,
+ "freopen(\"%s\", \"%s\", fopen(\"%s\", \"%s\")) failed: %d",
+ fname2_print, mode2, fname1, mode1, errno);
+ fclose(fp2);
+}
+
+ATF_TC_WITHOUT_HEAD(null__r__r__test);
+ATF_TC_BODY(null__r__r__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r", NULL, "r", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__w__r__test);
+ATF_TC_BODY(null__w__r__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "w", NULL, "r", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__r_append__r__test);
+ATF_TC_BODY(null__r_append__r__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r+", NULL, "r", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__r__w__test);
+ATF_TC_BODY(null__r__w__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r", NULL, "w", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__w__w__test);
+ATF_TC_BODY(null__w__w__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "w", NULL, "w", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__r_append__w__test);
+ATF_TC_BODY(null__r_append__w__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r+", NULL, "w", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__r__a__test);
+ATF_TC_BODY(null__r__a__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r", NULL, "a", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__w__a__test);
+ATF_TC_BODY(null__w__a__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "w", NULL, "a", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__r_append__a__test);
+ATF_TC_BODY(null__r_append__a__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r+", NULL, "a", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__r__r_append__test);
+ATF_TC_BODY(null__r__r_append__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r", NULL, "r+", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__w__r_append__test);
+ATF_TC_BODY(null__w__r_append__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "w", NULL, "r+", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__r_append__r_append__test);
+ATF_TC_BODY(null__r_append__r_append__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r+", NULL, "r+", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__r__w_append__test);
+ATF_TC_BODY(null__r__w_append__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r", NULL, "w+", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__w__w_append__test);
+ATF_TC_BODY(null__w__w_append__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "w", NULL, "w+", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__r_append__w_append__test);
+ATF_TC_BODY(null__r_append__w_append__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r+", NULL, "w+", true);
+}
+
+ATF_TC_WITHOUT_HEAD(sh__r__r__test);
+ATF_TC_BODY(sh__r__r__test, tc)
+{
+
+ runtest("/bin/sh", "r", NULL, "r", true);
+}
+
+ATF_TC_WITHOUT_HEAD(sh__sh__r__r__test);
+ATF_TC_BODY(sh__sh__r__r__test, tc)
+{
+
+ runtest("/bin/sh", "r", "/bin/sh", "r", true);
+}
+
+ATF_TC_WITHOUT_HEAD(sh__null__r__r__test);
+ATF_TC_BODY(sh__null__r__r__test, tc)
+{
+
+ runtest("/bin/sh", "r", _PATH_DEVNULL, "r", true);
+}
+
+ATF_TC_WITHOUT_HEAD(sh__null__r__w__test);
+ATF_TC_BODY(sh__null__r__w__test, tc)
+{
+
+ runtest("/bin/sh", "r", _PATH_DEVNULL, "w", true);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, null__r__r__test);
+ ATF_TP_ADD_TC(tp, null__w__r__test);
+ ATF_TP_ADD_TC(tp, null__r_append__r__test);
+ ATF_TP_ADD_TC(tp, null__r__w__test);
+ ATF_TP_ADD_TC(tp, null__w__w__test);
+ ATF_TP_ADD_TC(tp, null__r_append__w__test);
+ ATF_TP_ADD_TC(tp, null__r__a__test);
+ ATF_TP_ADD_TC(tp, null__w__a__test);
+ ATF_TP_ADD_TC(tp, null__r_append__a__test);
+ ATF_TP_ADD_TC(tp, null__r__r_append__test);
+ ATF_TP_ADD_TC(tp, null__w__r_append__test);
+ ATF_TP_ADD_TC(tp, null__r_append__r_append__test);
+ ATF_TP_ADD_TC(tp, null__r__w_append__test);
+ ATF_TP_ADD_TC(tp, null__w__w_append__test);
+ ATF_TP_ADD_TC(tp, null__r_append__w_append__test);
+ ATF_TP_ADD_TC(tp, sh__r__r__test);
+ ATF_TP_ADD_TC(tp, sh__sh__r__r__test);
+ ATF_TP_ADD_TC(tp, sh__null__r__r__test);
+ ATF_TP_ADD_TC(tp, sh__null__r__w__test);
+
+ return (atf_no_error());
+}
+
+/*
+ vim:ts=8:cin:sw=8
+ */
diff --git a/lib/libc/tests/stdio/getdelim_test.c b/lib/libc/tests/stdio/getdelim_test.c
new file mode 100644
index 0000000000000..8dc662fcab8f2
--- /dev/null
+++ b/lib/libc/tests/stdio/getdelim_test.c
@@ -0,0 +1,235 @@
+/*-
+ * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+#define CHUNK_MAX 10
+
+/* The assertions depend on this string. */
+char apothegm[] = "All work and no play\0 makes Jack a dull boy.\n";
+
+/*
+ * This is a neurotic reader function designed to give getdelim() a
+ * hard time. It reads through the string `apothegm' and returns a
+ * random number of bytes up to the requested length.
+ */
+static int
+_reader(void *cookie, char *buf, int len)
+{
+ size_t *offp = cookie;
+ size_t r;
+
+ r = random() % CHUNK_MAX + 1;
+ if (len > r)
+ len = r;
+ if (len > sizeof(apothegm) - *offp)
+ len = sizeof(apothegm) - *offp;
+ memcpy(buf, apothegm + *offp, len);
+ *offp += len;
+ return (len);
+}
+
+static FILE *
+mkfilebuf(void)
+{
+ size_t *offp;
+
+ offp = malloc(sizeof(*offp)); /* XXX leak */
+ *offp = 0;
+ return (fropen(offp, _reader));
+}
+
+ATF_TC_WITHOUT_HEAD(getline_basic);
+ATF_TC_BODY(getline_basic, tc)
+{
+ FILE *fp;
+ char *line;
+ size_t linecap;
+ int i;
+
+ srandom(0);
+
+ /*
+ * Test multiple times with different buffer sizes
+ * and different _reader() return values.
+ */
+ errno = 0;
+ for (i = 0; i < 8; i++) {
+ fp = mkfilebuf();
+ linecap = i;
+ line = malloc(i);
+ /* First line: the full apothegm */
+ ATF_REQUIRE(getline(&line, &linecap, fp) == sizeof(apothegm) - 1);
+ ATF_REQUIRE(memcmp(line, apothegm, sizeof(apothegm)) == 0);
+ ATF_REQUIRE(linecap >= sizeof(apothegm));
+ /* Second line: the NUL terminator following the newline */
+ ATF_REQUIRE(getline(&line, &linecap, fp) == 1);
+ ATF_REQUIRE(line[0] == '\0' && line[1] == '\0');
+ /* Third line: EOF */
+ line[0] = 'X';
+ ATF_REQUIRE(getline(&line, &linecap, fp) == -1);
+ ATF_REQUIRE(line[0] == '\0');
+ free(line);
+ line = NULL;
+ ATF_REQUIRE(feof(fp));
+ ATF_REQUIRE(!ferror(fp));
+ fclose(fp);
+ }
+ ATF_REQUIRE(errno == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(stream_error);
+ATF_TC_BODY(stream_error, tc)
+{
+ char *line;
+ size_t linecap;
+
+ /* Make sure read errors are handled properly. */
+ line = NULL;
+ linecap = 0;
+ errno = 0;
+ ATF_REQUIRE(getline(&line, &linecap, stdout) == -1);
+ ATF_REQUIRE(errno == EBADF);
+ errno = 0;
+ ATF_REQUIRE(getdelim(&line, &linecap, 'X', stdout) == -1);
+ ATF_REQUIRE(errno == EBADF);
+ ATF_REQUIRE(ferror(stdout));
+}
+
+ATF_TC_WITHOUT_HEAD(invalid_params);
+ATF_TC_BODY(invalid_params, tc)
+{
+ FILE *fp;
+ char *line;
+ size_t linecap;
+
+ /* Make sure NULL linep or linecapp pointers are handled. */
+ fp = mkfilebuf();
+ ATF_REQUIRE(getline(NULL, &linecap, fp) == -1);
+ ATF_REQUIRE(errno == EINVAL);
+ ATF_REQUIRE(getline(&line, NULL, fp) == -1);
+ ATF_REQUIRE(errno == EINVAL);
+ ATF_REQUIRE(ferror(fp));
+ fclose(fp);
+}
+
+ATF_TC_WITHOUT_HEAD(eof);
+ATF_TC_BODY(eof, tc)
+{
+ FILE *fp;
+ char *line;
+ size_t linecap;
+
+ /* Make sure getline() allocates memory as needed if fp is at EOF. */
+ errno = 0;
+ fp = mkfilebuf();
+ while (!feof(fp)) /* advance to EOF; can't fseek this stream */
+ getc(fp);
+ line = NULL;
+ linecap = 0;
+ printf("getline\n");
+ ATF_REQUIRE(getline(&line, &linecap, fp) == -1);
+ ATF_REQUIRE(line[0] == '\0');
+ ATF_REQUIRE(linecap > 0);
+ ATF_REQUIRE(errno == 0);
+ printf("feof\n");
+ ATF_REQUIRE(feof(fp));
+ ATF_REQUIRE(!ferror(fp));
+ fclose(fp);
+}
+
+ATF_TC_WITHOUT_HEAD(nul);
+ATF_TC_BODY(nul, tc)
+{
+ FILE *fp;
+ char *line;
+ size_t linecap, n;
+
+ errno = 0;
+ line = NULL;
+ linecap = 0;
+ /* Make sure a NUL delimiter works. */
+ fp = mkfilebuf();
+ n = strlen(apothegm);
+ printf("getdelim\n");
+ ATF_REQUIRE(getdelim(&line, &linecap, '\0', fp) == n + 1);
+ ATF_REQUIRE(strcmp(line, apothegm) == 0);
+ ATF_REQUIRE(line[n + 1] == '\0');
+ ATF_REQUIRE(linecap > n + 1);
+ n = strlen(apothegm + n + 1);
+ printf("getdelim 2\n");
+ ATF_REQUIRE(getdelim(&line, &linecap, '\0', fp) == n + 1);
+ ATF_REQUIRE(line[n + 1] == '\0');
+ ATF_REQUIRE(linecap > n + 1);
+ ATF_REQUIRE(errno == 0);
+ ATF_REQUIRE(!ferror(fp));
+ fclose(fp);
+}
+
+ATF_TC_WITHOUT_HEAD(empty_NULL_buffer);
+ATF_TC_BODY(empty_NULL_buffer, tc)
+{
+ FILE *fp;
+ char *line;
+ size_t linecap;
+
+ /* Make sure NULL *linep and zero *linecapp are handled. */
+ fp = mkfilebuf();
+ line = NULL;
+ linecap = 42;
+ ATF_REQUIRE(getline(&line, &linecap, fp) == sizeof(apothegm) - 1);
+ ATF_REQUIRE(memcmp(line, apothegm, sizeof(apothegm)) == 0);
+ fp = mkfilebuf();
+ free(line);
+ line = malloc(100);
+ linecap = 0;
+ ATF_REQUIRE(getline(&line, &linecap, fp) == sizeof(apothegm) - 1);
+ ATF_REQUIRE(memcmp(line, apothegm, sizeof(apothegm)) == 0);
+ free(line);
+ ATF_REQUIRE(!ferror(fp));
+ fclose(fp);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, getline_basic);
+ ATF_TP_ADD_TC(tp, stream_error);
+ ATF_TP_ADD_TC(tp, eof);
+ ATF_TP_ADD_TC(tp, invalid_params);
+ ATF_TP_ADD_TC(tp, nul);
+ ATF_TP_ADD_TC(tp, empty_NULL_buffer);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdio/gets_s_test.c b/lib/libc/tests/stdio/gets_s_test.c
new file mode 100644
index 0000000000000..7d02990f82d44
--- /dev/null
+++ b/lib/libc/tests/stdio/gets_s_test.c
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 2017 Cyril S. E. Schubert
+ *
+ * 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 REGENTS 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 REGENTS 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>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include <atf-c.h>
+
+static errno_t error_code;
+static const char * message;
+
+void
+h(const char * msg, void * ptr __unused, errno_t error)
+{
+ error_code = error;
+ message = msg;
+}
+
+/* null ptr */
+ATF_TC_WITHOUT_HEAD(null_ptr);
+ATF_TC_BODY(null_ptr, tc)
+{
+ ATF_CHECK_MSG(gets_s(NULL, 1) == NULL,
+ "gets_s() failed to handle NULL pointer");
+}
+
+/* normal */
+ATF_TC_WITHOUT_HEAD(normal);
+ATF_TC_BODY(normal, tc)
+{
+ pid_t kidpid;
+ int fd[2];
+ int nfd;
+
+ // close(STDIN_FILENO);
+ // close(STDOUT_FILENO);
+ pipe(fd);
+
+ if ((kidpid = fork()) == 0) {
+ char b[10];
+
+ close(fd[1]);
+ nfd = dup2(fd[0], 0);
+ close(fd[0]);
+ stdin = fdopen(nfd, "r");
+ ATF_CHECK_MSG(gets_s(b, sizeof(b)) == 0, "gets_s() normal failed");
+ fclose(stdin);
+ } else {
+ int stat;
+
+ close(fd[0]);
+ stdout = fdopen(fd[1], "w");
+ puts("a sting");
+ fclose(stdout);
+ (void) waitpid(kidpid, &stat, WEXITED);
+ }
+}
+
+/* n > rmax */
+ATF_TC_WITHOUT_HEAD(n_gt_rmax);
+ATF_TC_BODY(n_gt_rmax, tc)
+{
+ char b;
+
+ ATF_CHECK_MSG(gets_s(&b, RSIZE_MAX + 1) == NULL,
+ "gets_s() n > RSIZE_MAX");
+}
+
+/* n == 0 */
+ATF_TC_WITHOUT_HEAD(n_eq_zero);
+ATF_TC_BODY(n_eq_zero, tc)
+{
+ char b;
+
+ ATF_CHECK_MSG(gets_s(&b, 0) == NULL, "gets_s() n is zero");
+}
+
+/* n > rmax, handler */
+ATF_TC_WITHOUT_HEAD(n_gt_rmax_handler);
+ATF_TC_BODY(n_gt_rmax_handler, tc)
+{
+ char b;
+
+ error_code = 0;
+ message = NULL;
+ set_constraint_handler_s(h);
+ ATF_CHECK_MSG(gets_s(&b, RSIZE_MAX + 1) == NULL, "gets_s() n > RSIZE_MAX");
+ ATF_CHECK_MSG(error_code > 0, "gets_s() error code is %d", error_code);
+ ATF_CHECK_MSG(strcmp(message, "gets_s : n > RSIZE_MAX") == 0, "gets_s(): incorrect error message");
+}
+
+/* n == 0, handler */
+ATF_TC_WITHOUT_HEAD(n_eq_zero_handler);
+ATF_TC_BODY(n_eq_zero_handler, tc)
+{
+ char b;
+
+ error_code = 0;
+ message = NULL;
+ set_constraint_handler_s(h);
+ ATF_CHECK(gets_s(&b, 0) == NULL);
+ ATF_CHECK_MSG(error_code > 0, "gets_s() error code is %d", error_code);
+ ATF_CHECK_MSG(strcmp(message, "gets_s : n == 0") == 0, "gets_s(): incorrect error message");
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, null_ptr);
+ ATF_TP_ADD_TC(tp, normal);
+ ATF_TP_ADD_TC(tp, n_gt_rmax);
+ ATF_TP_ADD_TC(tp, n_eq_zero);
+ ATF_TP_ADD_TC(tp, n_gt_rmax_handler);
+ ATF_TP_ADD_TC(tp, n_eq_zero_handler);
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdio/mkostemp_test.c b/lib/libc/tests/stdio/mkostemp_test.c
new file mode 100644
index 0000000000000..0dd475b4ec61b
--- /dev/null
+++ b/lib/libc/tests/stdio/mkostemp_test.c
@@ -0,0 +1,185 @@
+/*-
+ * Copyright (c) 2013 Jilles Tjoelker
+ * 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.
+ */
+
+/*
+ * Test program for mkostemp().
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+static const char template[] = "mkostemp.XXXXXXXX";
+static int testnum;
+
+#define MISCFLAGS (O_APPEND | O_DIRECT | O_SHLOCK | O_EXLOCK | O_SYNC)
+
+static void
+test_one(int oflags)
+{
+ char tmpf[sizeof(template)];
+ struct stat st1, st2;
+ int fd;
+
+ memcpy(tmpf, template, sizeof(tmpf));
+ fd = mkostemp(tmpf, oflags);
+ if (fd < 0) {
+ printf("not ok %d - oflags=%#x "
+ "mkostemp() reported failure: %s\n",
+ testnum++, oflags, strerror(errno));
+ return;
+ }
+ if (memcmp(tmpf, template, sizeof(tmpf) - 8 - 1) != 0) {
+ printf("not ok %d - oflags=%#x "
+ "returned pathname does not match template: %s\n",
+ testnum++, oflags, tmpf);
+ return;
+ }
+ do {
+ if (fcntl(fd, F_GETFD) !=
+ (oflags & O_CLOEXEC ? FD_CLOEXEC : 0)) {
+ printf("not ok %d - oflags=%#x "
+ "close-on-exec flag incorrect\n",
+ testnum++, oflags);
+ break;
+ }
+ if ((fcntl(fd, F_GETFL) & MISCFLAGS) != (oflags & MISCFLAGS)) {
+ printf("not ok %d - oflags=%#x "
+ "open flags incorrect\n",
+ testnum++, oflags);
+ break;
+ }
+ if (stat(tmpf, &st1) == -1) {
+ printf("not ok %d - oflags=%#x "
+ "cannot stat returned pathname %s: %s\n",
+ testnum++, oflags, tmpf, strerror(errno));
+ break;
+ }
+ if (fstat(fd, &st2) == -1) {
+ printf("not ok %d - oflags=%#x "
+ "cannot fstat returned fd %d: %s\n",
+ testnum++, oflags, fd, strerror(errno));
+ break;
+ }
+ if (!S_ISREG(st1.st_mode) || (st1.st_mode & 0777) != 0600 ||
+ st1.st_nlink != 1 || st1.st_size != 0) {
+ printf("not ok %d - oflags=%#x "
+ "named file attributes incorrect\n",
+ testnum++, oflags);
+ break;
+ }
+ if (!S_ISREG(st2.st_mode) || (st2.st_mode & 0777) != 0600 ||
+ st2.st_nlink != 1 || st2.st_size != 0) {
+ printf("not ok %d - oflags=%#x "
+ "opened file attributes incorrect\n",
+ testnum++, oflags);
+ break;
+ }
+ if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) {
+ printf("not ok %d - oflags=%#x "
+ "named and opened file do not match\n",
+ testnum++, oflags);
+ break;
+ }
+ (void)unlink(tmpf);
+ if (fstat(fd, &st2) == -1)
+ printf("not ok %d - oflags=%#x "
+ "cannot fstat returned fd %d again: %s\n",
+ testnum++, oflags, fd, strerror(errno));
+ else if (st2.st_nlink != 0)
+ printf("not ok %d - oflags=%#x "
+ "st_nlink is not 0 after unlink\n",
+ testnum++, oflags);
+ else
+ printf("ok %d - oflags=%#x\n", testnum++, oflags);
+ (void)close(fd);
+ return;
+ } while (0);
+ (void)close(fd);
+ (void)unlink(tmpf);
+}
+
+ATF_TC_WITHOUT_HEAD(zero);
+ATF_TC_BODY(zero, tc)
+{
+
+ test_one(0);
+}
+
+ATF_TC_WITHOUT_HEAD(O_CLOEXEC);
+ATF_TC_BODY(O_CLOEXEC, tc)
+{
+
+ test_one(O_CLOEXEC);
+}
+
+ATF_TC_WITHOUT_HEAD(O_APPEND);
+ATF_TC_BODY(O_APPEND, tc)
+{
+
+ test_one(O_APPEND);
+}
+
+ATF_TC_WITHOUT_HEAD(O_APPEND__O_CLOEXEC);
+ATF_TC_BODY(O_APPEND__O_CLOEXEC, tc)
+{
+
+ test_one(O_APPEND|O_CLOEXEC);
+}
+
+ATF_TC_WITHOUT_HEAD(bad_flags);
+ATF_TC_BODY(bad_flags, tc)
+{
+
+ char tmpf[sizeof(template)];
+
+ memcpy(tmpf, template, sizeof(tmpf));
+ ATF_REQUIRE_MSG(mkostemp(tmpf, O_CREAT) == -1,
+ "mkostemp(O_CREAT) succeeded unexpectedly");
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, zero);
+ ATF_TP_ADD_TC(tp, O_CLOEXEC);
+ ATF_TP_ADD_TC(tp, O_APPEND);
+ ATF_TP_ADD_TC(tp, O_APPEND__O_CLOEXEC);
+ ATF_TP_ADD_TC(tp, bad_flags);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdio/open_memstream2_test.c b/lib/libc/tests/stdio/open_memstream2_test.c
new file mode 100644
index 0000000000000..21ea64c7c6695
--- /dev/null
+++ b/lib/libc/tests/stdio/open_memstream2_test.c
@@ -0,0 +1,201 @@
+/*-
+ * Copyright (c) 2013 Hudson River Trading LLC
+ * Written by: John H. Baldwin <jhb@FreeBSD.org>
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <atf-c.h>
+
+static char *buf;
+static size_t len;
+
+static void
+assert_stream(const char *contents)
+{
+ if (strlen(contents) != len)
+ printf("bad length %zd for \"%s\"\n", len, contents);
+ else if (strncmp(buf, contents, strlen(contents)) != 0)
+ printf("bad buffer \"%s\" for \"%s\"\n", buf, contents);
+}
+
+ATF_TC_WITHOUT_HEAD(open_group_test);
+ATF_TC_BODY(open_group_test, tc)
+{
+ FILE *fp;
+ off_t eob;
+
+ fp = open_memstream(&buf, &len);
+ ATF_REQUIRE_MSG(fp != NULL, "open_memstream failed");
+
+ fprintf(fp, "hello my world");
+ fflush(fp);
+ assert_stream("hello my world");
+ eob = ftello(fp);
+ rewind(fp);
+ fprintf(fp, "good-bye");
+ fseeko(fp, eob, SEEK_SET);
+ fclose(fp);
+ assert_stream("good-bye world");
+ free(buf);
+}
+
+ATF_TC_WITHOUT_HEAD(simple_tests);
+ATF_TC_BODY(simple_tests, tc)
+{
+ static const char zerobuf[] =
+ { 'f', 'o', 'o', 0, 0, 0, 0, 'b', 'a', 'r', 0 };
+ char c;
+ FILE *fp;
+
+ fp = open_memstream(&buf, NULL);
+ ATF_REQUIRE_MSG(fp == NULL, "open_memstream did not fail");
+ ATF_REQUIRE_MSG(errno == EINVAL,
+ "open_memstream didn't fail with EINVAL");
+ fp = open_memstream(NULL, &len);
+ ATF_REQUIRE_MSG(fp == NULL, "open_memstream did not fail");
+ ATF_REQUIRE_MSG(errno == EINVAL,
+ "open_memstream didn't fail with EINVAL");
+ fp = open_memstream(&buf, &len);
+ ATF_REQUIRE_MSG(fp != NULL, "open_memstream failed; errno=%d", errno);
+ fflush(fp);
+ assert_stream("");
+ if (fwide(fp, 0) >= 0)
+ printf("stream is not byte-oriented\n");
+
+ fprintf(fp, "fo");
+ fflush(fp);
+ assert_stream("fo");
+ fputc('o', fp);
+ fflush(fp);
+ assert_stream("foo");
+ rewind(fp);
+ fflush(fp);
+ assert_stream("");
+ fseek(fp, 0, SEEK_END);
+ fflush(fp);
+ assert_stream("foo");
+
+ /*
+ * Test seeking out past the current end. Should zero-fill the
+ * intermediate area.
+ */
+ fseek(fp, 4, SEEK_END);
+ fprintf(fp, "bar");
+ fflush(fp);
+
+ /*
+ * Can't use assert_stream() here since this should contain
+ * embedded null characters.
+ */
+ if (len != 10)
+ printf("bad length %zd for zero-fill test\n", len);
+ else if (memcmp(buf, zerobuf, sizeof(zerobuf)) != 0)
+ printf("bad buffer for zero-fill test\n");
+
+ fseek(fp, 3, SEEK_SET);
+ fprintf(fp, " in ");
+ fflush(fp);
+ assert_stream("foo in ");
+ fseek(fp, 0, SEEK_END);
+ fflush(fp);
+ assert_stream("foo in bar");
+
+ rewind(fp);
+ if (fread(&c, sizeof(c), 1, fp) != 0)
+ printf("fread did not fail\n");
+ else if (!ferror(fp))
+ printf("error indicator not set after fread\n");
+ else
+ clearerr(fp);
+
+ fseek(fp, 4, SEEK_SET);
+ fprintf(fp, "bar baz");
+ fclose(fp);
+ assert_stream("foo bar baz");
+ free(buf);
+}
+
+ATF_TC_WITHOUT_HEAD(seek_tests);
+ATF_TC_BODY(seek_tests, tc)
+{
+ FILE *fp;
+
+ fp = open_memstream(&buf, &len);
+ ATF_REQUIRE_MSG(fp != NULL, "open_memstream failed: %d", errno);
+
+#define SEEK_FAIL(offset, whence, error) do { \
+ errno = 0; \
+ ATF_REQUIRE_MSG(fseeko(fp, (offset), (whence)) != 0, \
+ "fseeko(%s, %s) did not fail, set pos to %jd", \
+ __STRING(offset), __STRING(whence), \
+ (intmax_t)ftello(fp)); \
+ ATF_REQUIRE_MSG(errno == (error), \
+ "fseeko(%s, %s) failed with %d rather than %s", \
+ __STRING(offset), __STRING(whence), errno, \
+ __STRING(error)); \
+} while (0)
+
+#define SEEK_OK(offset, whence, result) do { \
+ ATF_REQUIRE_MSG(fseeko(fp, (offset), (whence)) == 0, \
+ "fseeko(%s, %s) failed: %s", \
+ __STRING(offset), __STRING(whence), strerror(errno)); \
+ ATF_REQUIRE_MSG(ftello(fp) == (result), \
+ "fseeko(%s, %s) seeked to %jd rather than %s", \
+ __STRING(offset), __STRING(whence), \
+ (intmax_t)ftello(fp), __STRING(result)); \
+} while (0)
+
+ SEEK_FAIL(-1, SEEK_SET, EINVAL);
+ SEEK_FAIL(-1, SEEK_CUR, EINVAL);
+ SEEK_FAIL(-1, SEEK_END, EINVAL);
+ fprintf(fp, "foo");
+ SEEK_OK(-1, SEEK_CUR, 2);
+ SEEK_OK(0, SEEK_SET, 0);
+ SEEK_OK(-1, SEEK_END, 2);
+ SEEK_OK(OFF_MAX - 1, SEEK_SET, OFF_MAX - 1);
+ SEEK_FAIL(2, SEEK_CUR, EOVERFLOW);
+ fclose(fp);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, open_group_test);
+ ATF_TP_ADD_TC(tp, simple_tests);
+ ATF_TP_ADD_TC(tp, seek_tests);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdio/open_wmemstream_test.c b/lib/libc/tests/stdio/open_wmemstream_test.c
new file mode 100644
index 0000000000000..324bcf3d3482a
--- /dev/null
+++ b/lib/libc/tests/stdio/open_wmemstream_test.c
@@ -0,0 +1,201 @@
+/*-
+ * Copyright (c) 2013 Hudson River Trading LLC
+ * Written by: John H. Baldwin <jhb@FreeBSD.org>
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <atf-c.h>
+
+static wchar_t *buf;
+static size_t len;
+
+static void
+assert_stream(const wchar_t *contents)
+{
+ if (wcslen(contents) != len)
+ printf("bad length %zd for \"%ls\"\n", len, contents);
+ else if (wcsncmp(buf, contents, wcslen(contents)) != 0)
+ printf("bad buffer \"%ls\" for \"%ls\"\n", buf, contents);
+}
+
+ATF_TC_WITHOUT_HEAD(open_group_test);
+ATF_TC_BODY(open_group_test, tc)
+{
+ FILE *fp;
+ off_t eob;
+
+ fp = open_wmemstream(&buf, &len);
+ ATF_REQUIRE_MSG(fp != NULL, "open_wmemstream failed");
+
+ fwprintf(fp, L"hello my world");
+ fflush(fp);
+ assert_stream(L"hello my world");
+ eob = ftello(fp);
+ rewind(fp);
+ fwprintf(fp, L"good-bye");
+ fseeko(fp, eob, SEEK_SET);
+ fclose(fp);
+ assert_stream(L"good-bye world");
+ free(buf);
+}
+
+ATF_TC_WITHOUT_HEAD(simple_tests);
+ATF_TC_BODY(simple_tests, tc)
+{
+ static const wchar_t zerobuf[] =
+ { L'f', L'o', L'o', 0, 0, 0, 0, L'b', L'a', L'r', 0 };
+ wchar_t c;
+ FILE *fp;
+
+ fp = open_wmemstream(&buf, NULL);
+ ATF_REQUIRE_MSG(fp == NULL, "open_wmemstream did not fail");
+ ATF_REQUIRE_MSG(errno == EINVAL,
+ "open_wmemstream didn't fail with EINVAL");
+ fp = open_wmemstream(NULL, &len);
+ ATF_REQUIRE_MSG(fp == NULL, "open_wmemstream did not fail");
+ ATF_REQUIRE_MSG(errno == EINVAL,
+ "open_wmemstream didn't fail with EINVAL");
+ fp = open_wmemstream(&buf, &len);
+ ATF_REQUIRE_MSG(fp != NULL, "open_memstream failed; errno=%d", errno);
+ fflush(fp);
+ assert_stream(L"");
+ if (fwide(fp, 0) <= 0)
+ printf("stream is not wide-oriented\n");
+
+ fwprintf(fp, L"fo");
+ fflush(fp);
+ assert_stream(L"fo");
+ fputwc(L'o', fp);
+ fflush(fp);
+ assert_stream(L"foo");
+ rewind(fp);
+ fflush(fp);
+ assert_stream(L"");
+ fseek(fp, 0, SEEK_END);
+ fflush(fp);
+ assert_stream(L"foo");
+
+ /*
+ * Test seeking out past the current end. Should zero-fill the
+ * intermediate area.
+ */
+ fseek(fp, 4, SEEK_END);
+ fwprintf(fp, L"bar");
+ fflush(fp);
+
+ /*
+ * Can't use assert_stream() here since this should contain
+ * embedded null characters.
+ */
+ if (len != 10)
+ printf("bad length %zd for zero-fill test\n", len);
+ else if (memcmp(buf, zerobuf, sizeof(zerobuf)) != 0)
+ printf("bad buffer for zero-fill test\n");
+
+ fseek(fp, 3, SEEK_SET);
+ fwprintf(fp, L" in ");
+ fflush(fp);
+ assert_stream(L"foo in ");
+ fseek(fp, 0, SEEK_END);
+ fflush(fp);
+ assert_stream(L"foo in bar");
+
+ rewind(fp);
+ if (fread(&c, sizeof(c), 1, fp) != 0)
+ printf("fread did not fail\n");
+ else if (!ferror(fp))
+ printf("error indicator not set after fread\n");
+ else
+ clearerr(fp);
+
+ fseek(fp, 4, SEEK_SET);
+ fwprintf(fp, L"bar baz");
+ fclose(fp);
+ assert_stream(L"foo bar baz");
+ free(buf);
+}
+
+ATF_TC_WITHOUT_HEAD(seek_tests);
+ATF_TC_BODY(seek_tests, tc)
+{
+ FILE *fp;
+
+ fp = open_wmemstream(&buf, &len);
+ ATF_REQUIRE_MSG(fp != NULL, "open_wmemstream failed; errno=%d", errno);
+
+#define SEEK_FAIL(offset, whence, error) do { \
+ errno = 0; \
+ ATF_REQUIRE_MSG(fseeko(fp, (offset), (whence)) != 0, \
+ "fseeko(%s, %s) did not fail, set pos to %jd", \
+ __STRING(offset), __STRING(whence), \
+ (intmax_t)ftello(fp)); \
+ ATF_REQUIRE_MSG(errno == (error), \
+ "fseeko(%s, %s) failed with %d rather than %s", \
+ __STRING(offset), __STRING(whence), errno, \
+ __STRING(error)); \
+} while (0)
+
+#define SEEK_OK(offset, whence, result) do { \
+ ATF_REQUIRE_MSG(fseeko(fp, (offset), (whence)) == 0, \
+ "fseeko(%s, %s) failed: %s", \
+ __STRING(offset), __STRING(whence), strerror(errno)); \
+ ATF_REQUIRE_MSG(ftello(fp) == (result), \
+ "fseeko(%s, %s) seeked to %jd rather than %s", \
+ __STRING(offset), __STRING(whence), \
+ (intmax_t)ftello(fp), __STRING(result)); \
+} while (0)
+
+ SEEK_FAIL(-1, SEEK_SET, EINVAL);
+ SEEK_FAIL(-1, SEEK_CUR, EINVAL);
+ SEEK_FAIL(-1, SEEK_END, EINVAL);
+ fwprintf(fp, L"foo");
+ SEEK_OK(-1, SEEK_CUR, 2);
+ SEEK_OK(0, SEEK_SET, 0);
+ SEEK_OK(-1, SEEK_END, 2);
+ SEEK_OK(OFF_MAX - 1, SEEK_SET, OFF_MAX - 1);
+ SEEK_FAIL(2, SEEK_CUR, EOVERFLOW);
+ fclose(fp);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, open_group_test);
+ ATF_TP_ADD_TC(tp, simple_tests);
+ ATF_TP_ADD_TC(tp, seek_tests);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdio/perror_test.c b/lib/libc/tests/stdio/perror_test.c
new file mode 100644
index 0000000000000..989f1ff6ea595
--- /dev/null
+++ b/lib/libc/tests/stdio/perror_test.c
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * 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.
+ */
+
+/*
+ * Test program for perror() as specified by IEEE Std. 1003.1-2001 and
+ * ISO/IEC 9899:1999.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+static char tmpfil[PATH_MAX];
+
+ATF_TC_WITHOUT_HEAD(perror_test);
+ATF_TC_BODY(perror_test, tc)
+{
+ char lbuf[512];
+ int i;
+ char *s;
+
+ strcpy(tmpfil, "perror.XXXXXXXX");
+ ATF_REQUIRE(mkstemp(tmpfil) >= 0);
+ /* Reopen stderr on a file descriptor other than 2. */
+ fclose(stderr);
+ for (i = 0; i < 3; i++)
+ dup(0);
+ ATF_REQUIRE(freopen(tmpfil, "r+", stderr) != NULL);
+
+ /*
+ * Test that perror() doesn't call strerror() (4.4BSD bug),
+ * the two ways of omitting a program name, and the formatting when
+ * a program name is specified.
+ */
+ s = strerror(ENOENT);
+ ATF_REQUIRE_MSG(strcmp(s, "No such file or directory") == 0,
+ "message obtained was: %s", s);
+ errno = EPERM;
+ perror(NULL);
+ perror("");
+ perror("perror_test");
+ ATF_REQUIRE_MSG(strcmp(s, "No such file or directory") == 0,
+ "message obtained was: %s", s);
+
+ /*
+ * Read it back to check...
+ */
+ rewind(stderr);
+ s = fgets(lbuf, sizeof(lbuf), stderr);
+ ATF_REQUIRE(s != NULL);
+ ATF_REQUIRE_MSG(strcmp(s, "Operation not permitted\n") == 0,
+ "message obtained was: %s", s);
+ s = fgets(lbuf, sizeof(lbuf), stderr);
+ ATF_REQUIRE(s != NULL);
+ ATF_REQUIRE_MSG(strcmp(s, "Operation not permitted\n") == 0,
+ "message obtained was: %s", s);
+ s = fgets(lbuf, sizeof(lbuf), stderr);
+ ATF_REQUIRE(s != NULL);
+ ATF_REQUIRE_MSG(
+ strcmp(s, "perror_test: Operation not permitted\n") == 0,
+ "message obtained was: %s", s);
+ s = fgets(lbuf, sizeof(lbuf), stderr);
+ ATF_REQUIRE(s == NULL);
+ fclose(stderr);
+
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, perror_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdio/print_positional_test.c b/lib/libc/tests/stdio/print_positional_test.c
new file mode 100644
index 0000000000000..9c9ec314d62dd
--- /dev/null
+++ b/lib/libc/tests/stdio/print_positional_test.c
@@ -0,0 +1,157 @@
+/* $OpenBSD: sprintf_test.c,v 1.3 2004/09/16 20:22:26 otto Exp $ */
+
+/*
+ * Copyright (c) 2003 Theo de Raadt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <atf-c.h>
+
+const char correct[] =
+ "|xx 01 02 03 04\n"
+ "|xx 05 06 07 08\n"
+ "|xx 09 10 11 12\n"
+ "|xx 13 14 15 16\n"
+ "|xx 17 18 19 20\n"
+ "|xx 21 22 23 24\n"
+ "|xx 25 26 27 28\n"
+ "|xx 29 30 31 32\n"
+ "|xx 33 34 35 36\n"
+ "|xx 37 38 39 40\n"
+ "|xx 41 42 43 44\n"
+ "|xx 45 -1 1 -1 1\n";
+
+const char correct2[] =
+ "b bs BSD";
+static char buf[1024];
+static wchar_t wbuf1[1024], wbuf2[1024];
+static const char *temp;
+
+ATF_TC_WITHOUT_HEAD(positional_normal);
+ATF_TC_BODY(positional_normal, tc)
+{
+
+ /* Test positional arguments */
+ snprintf(buf, sizeof buf,
+ "|xx %1$s %2$s %3$s %4$s\n"
+ "|xx %5$s %6$s %7$s %8$s\n"
+ "|xx %9$s %10$s %11$s %12$s\n"
+ "|xx %13$s %14$s %15$s %16$s\n"
+ "|xx %17$s %18$s %19$s %20$s\n"
+ "|xx %21$s %22$s %23$s %24$s\n"
+ "|xx %25$s %26$s %27$s %28$s\n"
+ "|xx %29$s %30$s %31$s %32$s\n"
+ "|xx %33$s %34$s %35$s %36$s\n"
+ "|xx %37$s %38$s %39$s %40$s\n"
+ "|xx %41$s %42$s %43$s %44$s\n"
+ "|xx %45$d %46$ld %47$lld %48$d %49$lld\n",
+ "01", "02", "03", "04", "05", "06",
+ "07", "08", "09", "10", "11", "12",
+ "13", "14", "15", "16", "17", "18",
+ "19", "20", "21", "22", "23", "24",
+ "25", "26", "27", "28", "29", "30",
+ "31", "32", "33", "34", "35", "36",
+ "37", "38", "39", "40", "41", "42",
+ "43", "44", 45, -1L, 1LL, -1, 1LL
+ );
+ ATF_REQUIRE_MSG(wcscmp(wbuf1, wbuf2) == 0,
+ "buffers didn't match");
+}
+
+ATF_TC_WITHOUT_HEAD(positional_wide);
+ATF_TC_BODY(positional_wide, tc)
+{
+
+ swprintf(wbuf1, nitems(wbuf1),
+ L"|xx %1$s %2$s %3$s %4$s\n"
+ "|xx %5$s %6$s %7$s %8$s\n"
+ "|xx %9$s %10$s %11$s %12$s\n"
+ "|xx %13$s %14$s %15$s %16$s\n"
+ "|xx %17$s %18$s %19$s %20$s\n"
+ "|xx %21$s %22$s %23$s %24$s\n"
+ "|xx %25$s %26$s %27$s %28$s\n"
+ "|xx %29$s %30$s %31$s %32$s\n"
+ "|xx %33$s %34$s %35$s %36$s\n"
+ "|xx %37$s %38$s %39$s %40$s\n"
+ "|xx %41$s %42$s %43$s %44$s\n"
+ "|xx %45$d %46$ld %47$lld %48$d %49$lld\n",
+ "01", "02", "03", "04", "05", "06",
+ "07", "08", "09", "10", "11", "12",
+ "13", "14", "15", "16", "17", "18",
+ "19", "20", "21", "22", "23", "24",
+ "25", "26", "27", "28", "29", "30",
+ "31", "32", "33", "34", "35", "36",
+ "37", "38", "39", "40", "41", "42",
+ "43", "44", 45, -1L, 1LL, -1, 1LL
+ );
+ temp = correct;
+ mbsrtowcs(wbuf2, &temp, nitems(wbuf2), NULL);
+ ATF_REQUIRE_MSG(wcscmp(wbuf1, wbuf2) == 0,
+ "buffers didn't match");
+}
+
+ATF_TC_WITHOUT_HEAD(positional_precision);
+ATF_TC_BODY(positional_precision, tc)
+{
+
+ snprintf(buf, sizeof buf, "%2$.*4$s %2$.*3$s %1$s",
+ "BSD", "bsd", 2, 1);
+ ATF_REQUIRE_MSG(strcmp(buf, correct2) == 0,
+ "buffers didn't match");
+}
+
+ATF_TC_WITHOUT_HEAD(positional_precision_wide);
+ATF_TC_BODY(positional_precision_wide, tc)
+{
+
+ swprintf(wbuf1, sizeof buf, L"%2$.*4$s %2$.*3$s %1$s",
+ "BSD", "bsd", 2, 1);
+ temp = correct2;
+ mbsrtowcs(wbuf2, &temp, nitems(wbuf2), NULL);
+ ATF_REQUIRE_MSG(wcscmp(wbuf1, wbuf2) == 0,
+ "buffers didn't match");
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, positional_normal);
+ ATF_TP_ADD_TC(tp, positional_wide);
+ ATF_TP_ADD_TC(tp, positional_precision);
+ ATF_TP_ADD_TC(tp, positional_precision_wide);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdio/printbasic_test.c b/lib/libc/tests/stdio/printbasic_test.c
new file mode 100644
index 0000000000000..322e7477da25d
--- /dev/null
+++ b/lib/libc/tests/stdio/printbasic_test.c
@@ -0,0 +1,162 @@
+/*-
+ * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * 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.
+ */
+
+/*
+ * Tests for basic and miscellaneous printf() formats.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <atf-c.h>
+
+#define S_UINT64MAX "18446744073709551615"
+#define S_UINT32MAX "4294967295"
+#define S_INT64MIN "-9223372036854775808"
+#define S_INT32MIN "-2147483648"
+
+#define S_SIZEMAX (SIZE_MAX == UINT64_MAX ? S_UINT64MAX : S_UINT32MAX)
+#define S_ULONGMAX (ULONG_MAX == UINT64_MAX ? S_UINT64MAX : S_UINT32MAX)
+#define S_ULLONGMAX (ULLONG_MAX == UINT64_MAX ? S_UINT64MAX : S_UINT32MAX)
+
+static void
+smash_stack(void)
+{
+ static uint32_t junk = 0xdeadbeef;
+ uint32_t buf[512];
+ int i;
+
+ for (i = 0; i < sizeof(buf) / sizeof(buf[0]); i++)
+ buf[i] = junk;
+}
+
+#define testfmt(result, fmt, ...) \
+ _testfmt((result), #__VA_ARGS__, fmt, __VA_ARGS__)
+static void
+_testfmt(const char *result, const char *argstr, const char *fmt,...)
+{
+#define BUF 100
+ wchar_t ws[BUF], wfmt[BUF], wresult[BUF];
+ char s[BUF];
+ va_list ap, ap2;
+
+ va_start(ap, fmt);
+ va_copy(ap2, ap);
+ smash_stack();
+ vsnprintf(s, sizeof(s), fmt, ap);
+ ATF_CHECK_MSG(strcmp(result, s) == 0,
+ "printf(\"%s\", %s) ==> [%s], expected [%s]",
+ fmt, argstr, s, result);
+
+ smash_stack();
+ mbstowcs(ws, s, BUF - 1);
+ mbstowcs(wfmt, fmt, BUF - 1);
+ mbstowcs(wresult, result, BUF - 1);
+ vswprintf(ws, sizeof(ws) / sizeof(ws[0]), wfmt, ap2);
+ ATF_CHECK_MSG(wcscmp(wresult, ws) == 0,
+ "wprintf(\"%ls\", %s) ==> [%ls], expected [%ls]",
+ wfmt, argstr, ws, wresult);
+
+ va_end(ap);
+ va_end(ap2);
+}
+
+ATF_TC_WITHOUT_HEAD(int_within_limits);
+ATF_TC_BODY(int_within_limits, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ /* The test requires these to be true. */
+ ATF_REQUIRE(UINTMAX_MAX == UINT64_MAX);
+ ATF_REQUIRE(UINT_MAX == UINT32_MAX);
+ ATF_REQUIRE(USHRT_MAX == 0xffff);
+ ATF_REQUIRE(UCHAR_MAX == 0xff);
+
+ /* Make sure we handle signed vs. unsigned args correctly. */
+ testfmt("-1", "%jd", (intmax_t)-1);
+ testfmt(S_UINT64MAX, "%ju", UINT64_MAX);
+
+ if (sizeof(ptrdiff_t) != sizeof(uintmax_t))
+ atf_tc_expect_fail("the %%t qualifier is broken on 32-bit "
+ "platforms where there's a mismatch between ptrdiff_t and "
+ "uintmax_t's type width; bug # 191674");
+
+ testfmt("-1", "%td", (ptrdiff_t)-1);
+ testfmt(S_SIZEMAX, "%tu", (size_t)-1);
+
+ testfmt("-1", "%zd", (ssize_t)-1);
+ testfmt(S_SIZEMAX, "%zu", (ssize_t)-1);
+
+ testfmt("-1", "%ld", (long)-1);
+ testfmt(S_ULONGMAX, "%lu", ULONG_MAX);
+
+ testfmt("-1", "%lld", (long long)-1);
+ testfmt(S_ULLONGMAX, "%llu", ULLONG_MAX);
+
+ testfmt("-1", "%d", -1);
+ testfmt(S_UINT32MAX, "%u", UINT32_MAX);
+
+ testfmt("-1", "%hd", -1);
+ testfmt("65535", "%hu", USHRT_MAX);
+
+ testfmt("-1", "%hhd", -1);
+ testfmt("255", "%hhu", UCHAR_MAX);
+}
+
+ATF_TC_WITHOUT_HEAD(int_limits);
+ATF_TC_BODY(int_limits, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ /*
+ * Check that printing the largest negative number does not cause
+ * overflow when it is negated.
+ */
+ testfmt(S_INT32MIN, "%d", INT_MIN);
+ testfmt(S_INT64MIN, "%jd", INTMAX_MIN);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, int_within_limits);
+ ATF_TP_ADD_TC(tp, int_limits);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdio/printfloat_test.c b/lib/libc/tests/stdio/printfloat_test.c
new file mode 100644
index 0000000000000..97629fb0d2b15
--- /dev/null
+++ b/lib/libc/tests/stdio/printfloat_test.c
@@ -0,0 +1,389 @@
+/*-
+ * Copyright (c) 2002-2009 David Schultz <das@FreeBSD.org>
+ * 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.
+ */
+
+/*
+ * Test for printf() floating point formats.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <fenv.h>
+#include <float.h>
+#include <locale.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <atf-c.h>
+
+static void
+smash_stack(void)
+{
+ static uint32_t junk = 0xdeadbeef;
+ uint32_t buf[512];
+ int i;
+
+ for (i = 0; i < sizeof(buf) / sizeof(buf[0]); i++)
+ buf[i] = junk;
+}
+
+#define testfmt(result, fmt, ...) \
+ _testfmt((result), #__VA_ARGS__, fmt, __VA_ARGS__)
+static void
+_testfmt(const char *result, const char *argstr, const char *fmt,...)
+{
+#define BUF 100
+ wchar_t ws[BUF], wfmt[BUF], wresult[BUF];
+ char s[BUF];
+ va_list ap, ap2;
+
+ va_start(ap, fmt);
+ va_copy(ap2, ap);
+ smash_stack();
+ vsnprintf(s, sizeof(s), fmt, ap);
+ ATF_CHECK_MSG(strcmp(result, s) == 0,
+ "printf(\"%s\", %s) ==> [%s], expected [%s]",
+ fmt, argstr, s, result);
+
+ smash_stack();
+ mbstowcs(ws, s, BUF - 1);
+ mbstowcs(wfmt, fmt, BUF - 1);
+ mbstowcs(wresult, result, BUF - 1);
+ vswprintf(ws, sizeof(ws) / sizeof(ws[0]), wfmt, ap2);
+ ATF_CHECK_MSG(wcscmp(wresult, ws) == 0,
+ "wprintf(\"%ls\", %s) ==> [%ls], expected [%ls]",
+ wfmt, argstr, ws, wresult);
+
+ va_end(ap);
+ va_end(ap2);
+}
+
+ATF_TC_WITHOUT_HEAD(float_within_limits);
+ATF_TC_BODY(float_within_limits, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ /* Basic tests of decimal output functionality. */
+ testfmt(" 1.000000E+00", "%13E", 1.0);
+ testfmt(" 1.000000", "%13f", 1.0);
+ testfmt(" 1", "%13G", 1.0);
+ testfmt(" 1.000000E+00", "%13LE", 1.0L);
+ testfmt(" 1.000000", "%13Lf", 1.0L);
+ testfmt(" 1", "%13LG", 1.0L);
+
+ testfmt("2.718282", "%.*f", -2, 2.7182818);
+
+ testfmt("1.234568e+06", "%e", 1234567.8);
+ testfmt("1234567.800000", "%f", 1234567.8);
+ testfmt("1.23457E+06", "%G", 1234567.8);
+ testfmt("1.234568e+06", "%Le", 1234567.8L);
+ testfmt("1234567.800000", "%Lf", 1234567.8L);
+ testfmt("1.23457E+06", "%LG", 1234567.8L);
+
+#if (LDBL_MANT_DIG > DBL_MANT_DIG) && !defined(__i386__)
+ testfmt("123456789.864210", "%Lf", 123456789.8642097531L);
+ testfmt("-1.23457E+08", "%LG", -123456789.8642097531L);
+ testfmt("123456789.8642097531", "%.10Lf", 123456789.8642097531L);
+ testfmt(" 3.141592653589793238e-4000", "%L27.18Le",
+ 3.14159265358979323846e-4000L);
+#endif
+}
+
+ATF_TC_WITHOUT_HEAD(infinities_and_nans);
+ATF_TC_BODY(infinities_and_nans, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ testfmt("nan", "%e", NAN);
+ testfmt("NAN", "%F", NAN);
+ testfmt("nan", "%g", NAN);
+ testfmt("NAN", "%LE", (long double)NAN);
+ testfmt(" nan", "%05e", NAN);
+
+ testfmt("INF", "%E", HUGE_VAL);
+ testfmt("-inf", "%f", -HUGE_VAL);
+ testfmt("+inf", "%+g", HUGE_VAL);
+ testfmt(" inf", "%4.2Le", HUGE_VALL);
+ testfmt("-inf", "%Lf", -HUGE_VALL);
+ testfmt(" inf", "%05e", HUGE_VAL);
+ testfmt(" -inf", "%05e", -HUGE_VAL);
+}
+
+ATF_TC_WITHOUT_HEAD(padding);
+ATF_TC_BODY(padding, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ testfmt("0.000000e+00", "%e", 0.0);
+ testfmt("0.000000", "%F", (double)0.0);
+ testfmt("0", "%G", 0.0);
+ testfmt(" 0", "%3.0Lg", 0.0L);
+ testfmt(" 0", "%5.0f", 0.001);
+}
+
+ATF_TC_WITHOUT_HEAD(precision_specifiers);
+ATF_TC_BODY(precision_specifiers, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ testfmt("1.0123e+00", "%.4e", 1.0123456789);
+ testfmt("1.0123", "%.4f", 1.0123456789);
+ testfmt("1.012", "%.4g", 1.0123456789);
+ testfmt("1.2346e-02", "%.4e", 0.0123456789);
+ testfmt("0.0123", "%.4f", 0.0123456789);
+ testfmt("0.01235", "%.4g", 0.0123456789);
+}
+
+ATF_TC_WITHOUT_HEAD(thousands_separator_and_other_locale_tests);
+ATF_TC_BODY(thousands_separator_and_other_locale_tests, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ testfmt("12345678.0625", "%'.04f", 12345678.0625);
+ testfmt("0012345678.0625", "%'015.4F", 12345678.0625);
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "hi_IN.ISCII-DEV")); /* grouping == 2;3 */
+ testfmt("1,23,45,678.0625", "%'.4f", 12345678.0625);
+ testfmt("01,23,45,678.0625", "%'017.4F", 12345678.0625);
+ testfmt(" 9,000", "%'6.0f", 9000.0);
+ testfmt("9,000.0", "%'.1f", 9000.0);
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "ru_RU.ISO8859-5")); /* decimalpoint==, */
+ testfmt("3,1415", "%g", 3.1415);
+
+ /* thousands=. decimalpoint=, grouping=3;3 */
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "el_GR.ISO8859-7")); /* decimalpoint==, */
+ testfmt("1.234,00", "%'.2f", 1234.00);
+ testfmt("123.456,789", "%'.3f", 123456.789);
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+ testfmt("12345678.062500", "%'f", 12345678.0625);
+ testfmt("9000.000000", "%'f", 9000.0);
+}
+
+ATF_TC_WITHOUT_HEAD(signed_conversions);
+ATF_TC_BODY(signed_conversions, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ testfmt("+2.500000e-01", "%+e", 0.25);
+ testfmt("+0.000000", "%+F", 0.0);
+ testfmt("-1", "%+g", -1.0);
+
+ testfmt("-1.000000e+00", "% e", -1.0);
+ testfmt("+1.000000", "% +f", 1.0);
+ testfmt(" 1", "% g", 1.0);
+ testfmt(" 0", "% g", 0.0);
+}
+
+ATF_TC_WITHOUT_HEAD(alternate_form);
+ATF_TC_BODY(alternate_form, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ testfmt("1.250e+00", "%#.3e", 1.25);
+ testfmt("123.000000", "%#f", 123.0);
+ testfmt(" 12345.", "%#7.5g", 12345.0);
+ testfmt(" 1.00000", "%#8g", 1.0);
+ testfmt("0.0", "%#.2g", 0.0);
+}
+
+ATF_TC_WITHOUT_HEAD(padding_and_decimal_point_placement);
+ATF_TC_BODY(padding_and_decimal_point_placement, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ testfmt("03.2E+00", "%08.1E", 3.25);
+ testfmt("003.25", "%06.2F", 3.25);
+ testfmt("0003.25", "%07.4G", 3.25);
+
+ testfmt("3.14159e-05", "%g", 3.14159e-5);
+ testfmt("0.000314159", "%g", 3.14159e-4);
+ testfmt("3.14159e+06", "%g", 3.14159e6);
+ testfmt("314159", "%g", 3.14159e5);
+ testfmt("314159.", "%#g", 3.14159e5);
+
+ testfmt(" 9.000000e+03", "%13e", 9000.0);
+ testfmt(" 9000.000000", "%12f", 9000.0);
+ testfmt(" 9000", "%5g", 9000.0);
+ testfmt(" 900000.", "%#8g", 900000.0);
+ testfmt(" 9e+06", "%6g", 9000000.0);
+ testfmt(" 9.000000e-04", "%13e", 0.0009);
+ testfmt(" 0.000900", "%9f", 0.0009);
+ testfmt(" 0.0009", "%7g", 0.0009);
+ testfmt(" 9e-05", "%6g", 0.00009);
+ testfmt(" 9.00000e-05", "%#12g", 0.00009);
+ testfmt(" 9.e-05", "%#7.1g", 0.00009);
+
+ testfmt(" 0.0", "%4.1f", 0.0);
+ testfmt("90.0", "%4.1f", 90.0);
+ testfmt(" 100", "%4.0f", 100.0);
+ testfmt("9.0e+01", "%4.1e", 90.0);
+ testfmt("1e+02", "%4.0e", 100.0);
+}
+
+ATF_TC_WITHOUT_HEAD(decimal_rounding);
+ATF_TC_BODY(decimal_rounding, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ fesetround(FE_DOWNWARD);
+ testfmt("4.437", "%.3f", 4.4375);
+ testfmt("-4.438", "%.3f", -4.4375);
+ testfmt("4.437", "%.3Lf", 4.4375L);
+ testfmt("-4.438", "%.3Lf", -4.4375L);
+
+ fesetround(FE_UPWARD);
+ testfmt("4.438", "%.3f", 4.4375);
+ testfmt("-4.437", "%.3f", -4.4375);
+ testfmt("4.438", "%.3Lf", 4.4375L);
+ testfmt("-4.437", "%.3Lf", -4.4375L);
+
+ fesetround(FE_TOWARDZERO);
+ testfmt("4.437", "%.3f", 4.4375);
+ testfmt("-4.437", "%.3f", -4.4375);
+ testfmt("4.437", "%.3Lf", 4.4375L);
+ testfmt("-4.437", "%.3Lf", -4.4375L);
+
+ fesetround(FE_TONEAREST);
+ testfmt("4.438", "%.3f", 4.4375);
+ testfmt("-4.438", "%.3f", -4.4375);
+ testfmt("4.438", "%.3Lf", 4.4375L);
+ testfmt("-4.438", "%.3Lf", -4.4375L);
+}
+
+ATF_TC_WITHOUT_HEAD(hexadecimal_floating_point);
+ATF_TC_BODY(hexadecimal_floating_point, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ /*
+ * Hexadecimal floating point (%a, %A) tests. Some of these
+ * are only valid if the implementation converts to hex digits
+ * on nibble boundaries.
+ */
+ testfmt("0x0p+0", "%a", 0x0.0p0);
+ testfmt("0X0.P+0", "%#LA", 0x0.0p0L);
+ testfmt("inf", "%La", (long double)INFINITY);
+ testfmt("+INF", "%+A", INFINITY);
+ testfmt("nan", "%La", (long double)NAN);
+ testfmt("NAN", "%A", NAN);
+
+ testfmt(" 0x1.23p+0", "%10a", 0x1.23p0);
+ testfmt(" 0x1.23p-500", "%12a", 0x1.23p-500);
+ testfmt(" 0x1.2p+40", "%10.1a", 0x1.23p40);
+ testfmt(" 0X1.230000000000000000000000P-4", "%32.24A", 0x1.23p-4);
+ testfmt("0x1p-1074", "%a", 0x1p-1074);
+ testfmt("0x1.2345p-1024", "%a", 0x1.2345p-1024);
+
+#if (LDBL_MANT_DIG == 64)
+ testfmt("0x1.921fb54442d18468p+1", "%La", 0x3.243f6a8885a308dp0L);
+ testfmt("0x1p-16445", "%La", 0x1p-16445L);
+ testfmt("0x1.30ecap-16381", "%La", 0x9.8765p-16384L);
+#elif (LDBL_MANT_DIG == 113)
+ testfmt("0x1.921fb54442d18469898cc51701b8p+1", "%La",
+ 0x3.243f6a8885a308d313198a2e037p0L);
+ testfmt("0x1p-16494", "%La", 0x1p-16494L);
+ testfmt("0x1.2345p-16384", "%La", 0x1.2345p-16384L);
+#else
+ testfmt("0x1.921fb54442d18p+1", "%La", 0x3.243f6a8885a31p0L);
+ testfmt("0x1p-1074", "%La", 0x1p-1074L);
+ testfmt("0x1.30ecap-1021", "%La", 0x9.8765p-1024L);
+#endif
+}
+
+ATF_TC_WITHOUT_HEAD(hexadecimal_rounding);
+ATF_TC_BODY(hexadecimal_rounding, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ fesetround(FE_TOWARDZERO);
+ testfmt("0X1.23456789ABCP+0", "%.11A", 0x1.23456789abcdep0);
+ testfmt("-0x1.23456p+0", "%.5a", -0x1.23456789abcdep0);
+ testfmt("0x1.23456p+0", "%.5a", 0x1.23456789abcdep0);
+ testfmt("0x1.234567p+0", "%.6a", 0x1.23456789abcdep0);
+ testfmt("-0x1.234566p+0", "%.6a", -0x1.23456689abcdep0);
+
+ fesetround(FE_DOWNWARD);
+ testfmt("0X1.23456789ABCP+0", "%.11A", 0x1.23456789abcdep0);
+ testfmt("-0x1.23457p+0", "%.5a", -0x1.23456789abcdep0);
+ testfmt("0x1.23456p+0", "%.5a", 0x1.23456789abcdep0);
+ testfmt("0x1.234567p+0", "%.6a", 0x1.23456789abcdep0);
+ testfmt("-0x1.234567p+0", "%.6a", -0x1.23456689abcdep0);
+
+ fesetround(FE_UPWARD);
+ testfmt("0X1.23456789ABDP+0", "%.11A", 0x1.23456789abcdep0);
+ testfmt("-0x1.23456p+0", "%.5a", -0x1.23456789abcdep0);
+ testfmt("0x1.23457p+0", "%.5a", 0x1.23456789abcdep0);
+ testfmt("0x1.234568p+0", "%.6a", 0x1.23456789abcdep0);
+ testfmt("-0x1.234566p+0", "%.6a", -0x1.23456689abcdep0);
+
+ fesetround(FE_TONEAREST);
+ testfmt("0x1.23456789abcdep+4", "%a", 0x1.23456789abcdep4);
+ testfmt("0X1.23456789ABDP+0", "%.11A", 0x1.23456789abcdep0);
+ testfmt("-0x1.23456p+0", "%.5a", -0x1.23456789abcdep0);
+ testfmt("0x1.23456p+0", "%.5a", 0x1.23456789abcdep0);
+ testfmt("0x1.234568p+0", "%.6a", 0x1.23456789abcdep0);
+ testfmt("-0x1.234567p+0", "%.6a", -0x1.23456689abcdep0);
+ testfmt("0x1.00p-1029", "%.2a", 0x1.fffp-1030);
+ testfmt("0x1.00p-1026", "%.2a", 0xf.fffp-1030);
+ testfmt("0x1.83p+0", "%.2a", 1.51);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, float_within_limits);
+ ATF_TP_ADD_TC(tp, infinities_and_nans);
+ ATF_TP_ADD_TC(tp, padding);
+ ATF_TP_ADD_TC(tp, precision_specifiers);
+ ATF_TP_ADD_TC(tp, thousands_separator_and_other_locale_tests);
+ ATF_TP_ADD_TC(tp, signed_conversions);
+ ATF_TP_ADD_TC(tp, alternate_form);
+ ATF_TP_ADD_TC(tp, padding_and_decimal_point_placement);
+ ATF_TP_ADD_TC(tp, decimal_rounding);
+ ATF_TP_ADD_TC(tp, hexadecimal_floating_point);
+ ATF_TP_ADD_TC(tp, hexadecimal_rounding);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdio/scanfloat_test.c b/lib/libc/tests/stdio/scanfloat_test.c
new file mode 100644
index 0000000000000..7e27e69542e73
--- /dev/null
+++ b/lib/libc/tests/stdio/scanfloat_test.c
@@ -0,0 +1,316 @@
+/*-
+ * Copyright (C) 2003, 2005 David Schultz <das@FreeBSD.org>
+ * 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.
+ */
+
+/*
+ * Test for scanf() floating point formats.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <fenv.h>
+#include <float.h>
+#include <locale.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+#define eq(type, a, b) _eq(type##_EPSILON, (a), (b))
+static int
+_eq(long double epsilon, long double a, long double b)
+{
+ long double delta;
+
+ delta = fabsl(a - b);
+ return (delta <= epsilon);
+}
+
+ATF_TC_WITHOUT_HEAD(normalized_numbers);
+ATF_TC_BODY(normalized_numbers, tc)
+{
+ char buf[128];
+ long double ld = 0.0;
+ double d = 0.0;
+ float f = 0.0;
+
+ buf[0] = '\0';
+ ATF_REQUIRE(setlocale(LC_NUMERIC, ""));
+
+ sscanf("3.141592", "%e", &f);
+ ATF_REQUIRE(eq(FLT, f, 3.141592));
+
+ sscanf("3.141592653589793", "%lf", &d);
+ ATF_REQUIRE(eq(DBL, d, 3.141592653589793));
+
+ sscanf("1.234568e+06", "%E", &f);
+ ATF_REQUIRE(eq(FLT, f, 1.234568e+06));
+
+ sscanf("-1.234568e6", "%lF", &d);
+ ATF_REQUIRE(eq(DBL, d, -1.234568e6));
+
+ sscanf("+1.234568e-52", "%LG", &ld);
+ ATF_REQUIRE(eq(LDBL, ld, 1.234568e-52L));
+
+ sscanf("0.1", "%la", &d);
+ ATF_REQUIRE(eq(DBL, d, 0.1));
+
+ sscanf("00.2", "%lA", &d);
+ ATF_REQUIRE(eq(DBL, d, 0.2));
+
+ sscanf("123456", "%5le%s", &d, buf);
+ ATF_REQUIRE(eq(DBL, d, 12345.));
+ ATF_REQUIRE(strcmp(buf, "6") == 0);
+
+ sscanf("1.0Q", "%*5le%s", buf);
+ ATF_REQUIRE(strcmp(buf, "Q") == 0);
+
+ sscanf("-1.23e", "%e%s", &f, buf);
+ ATF_REQUIRE(eq(FLT, f, -1.23));
+ ATF_REQUIRE(strcmp(buf, "e") == 0);
+
+ sscanf("1.25e+", "%le%s", &d, buf);
+ ATF_REQUIRE(eq(DBL, d, 1.25));
+ ATF_REQUIRE(strcmp(buf, "e+") == 0);
+
+ sscanf("1.23E4E5", "%le%s", &d, buf);
+ ATF_REQUIRE(eq(DBL, d, 1.23e4));
+ ATF_REQUIRE(strcmp(buf, "E5") == 0);
+
+ sscanf("12e6", "%le", &d);
+ ATF_REQUIRE(eq(DBL, d, 12e6));
+
+ sscanf("1.a", "%le%s", &d, buf);
+ ATF_REQUIRE(eq(DBL, d, 1.0));
+ ATF_REQUIRE(strcmp(buf, "a") == 0);
+
+ sscanf(".0p4", "%le%s", &d, buf);
+ ATF_REQUIRE(eq(DBL, d, 0.0));
+ ATF_REQUIRE(strcmp(buf, "p4") == 0);
+
+ d = 0.25;
+ ATF_REQUIRE(sscanf(".", "%le", &d) == 0);
+ ATF_REQUIRE(d == 0.25);
+
+ sscanf("0x08", "%le", &d);
+ ATF_REQUIRE(d == 0x8p0);
+
+ sscanf("0x90a.bcdefP+09a", "%le%s", &d, buf);
+ ATF_REQUIRE(d == 0x90a.bcdefp+09);
+ ATF_REQUIRE(strcmp(buf, "a") == 0);
+
+#if (LDBL_MANT_DIG > DBL_MANT_DIG) && !defined(__i386__)
+ sscanf("3.14159265358979323846", "%Lg", &ld);
+ ATF_REQUIRE(eq(LDBL, ld, 3.14159265358979323846L));
+
+ sscanf(" 0X.0123456789abcdefffp-3g", "%Le%s", &ld, buf);
+ ATF_REQUIRE(ld == 0x0.0123456789abcdefffp-3L);
+ ATF_REQUIRE(strcmp(buf, "g") == 0);
+#endif
+
+ sscanf("0xg", "%le%s", &d, buf);
+ ATF_REQUIRE(d == 0.0);
+ ATF_REQUIRE(strcmp(buf, "xg") == 0);
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "ru_RU.ISO8859-5")); /* decimalpoint==, */
+
+ sscanf("1.23", "%le%s", &d, buf);
+ ATF_REQUIRE(d == 1.0);
+ ATF_REQUIRE(strcmp(buf, ".23") == 0);
+
+ sscanf("1,23", "%le", &d);
+ ATF_REQUIRE(d == 1.23);
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, ""));
+}
+
+ATF_TC_WITHOUT_HEAD(infinities_and_nans);
+ATF_TC_BODY(infinities_and_nans, tc)
+{
+ char buf[128];
+ long double ld = 0.0;
+ double d = 0.0;
+ float f = 0.0;
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ sscanf("-Inf", "%le", &d);
+ ATF_REQUIRE(d < 0.0 && isinf(d));
+
+ sscanf("iNfInItY and beyond", "%le%s", &d, buf);
+ ATF_REQUIRE(d > 0.0 && isinf(d));
+ ATF_REQUIRE(strcmp(buf, " and beyond"));
+
+ sscanf("NaN", "%le", &d);
+ ATF_REQUIRE(isnan(d));
+
+ sscanf("NAN(123Y", "%le%s", &d, buf);
+ ATF_REQUIRE(isnan(d));
+ ATF_REQUIRE(strcmp(buf, "(123Y") == 0);
+
+ sscanf("nan(f00f)plugh", "%le%s", &d, buf);
+ ATF_REQUIRE(isnan(d));
+ ATF_REQUIRE(strcmp(buf, "plugh") == 0);
+
+ sscanf("-nan", "%le", &d);
+ ATF_REQUIRE(isnan(d));
+
+ /* Only quiet NaNs should be returned. */
+ sscanf("NaN", "%e", &f);
+ sscanf("nan", "%le", &d);
+ sscanf("nan", "%Le", &ld);
+ feclearexcept(FE_ALL_EXCEPT);
+ ATF_REQUIRE(f != f);
+ ATF_REQUIRE(d != d);
+ ATF_REQUIRE(ld != ld);
+ ATF_REQUIRE(fetestexcept(FE_INVALID) == 0);
+ sscanf("nan(1234)", "%e", &f);
+ sscanf("nan(1234)", "%le", &d);
+ sscanf("nan(1234)", "%Le", &ld);
+ feclearexcept(FE_ALL_EXCEPT);
+ ATF_REQUIRE(f != f);
+ ATF_REQUIRE(d != d);
+ ATF_REQUIRE(ld != ld);
+ /* POSIX says we should only generate quiet NaNs. */
+ ATF_REQUIRE(fetestexcept(FE_INVALID) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(rounding_tests);
+ATF_TC_BODY(rounding_tests, tc)
+{
+ long double ld = 0.0;
+ double d = 0.0;
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ fesetround(FE_DOWNWARD);
+
+ sscanf("1.999999999999999999999999999999999", "%le", &d);
+ ATF_REQUIRE(d < 2.0);
+ sscanf("0x1.ffffffffffffffp0", "%le", &d);
+ ATF_REQUIRE(d < 2.0);
+ sscanf("1.999999999999999999999999999999999", "%Le", &ld);
+ ATF_REQUIRE(ld < 2.0);
+
+ sscanf("1.0571892669084007", "%le", &d);
+ ATF_REQUIRE(d == 0x1.0ea3f4af0dc59p0);
+ sscanf("-1.0571892669084007", "%le", &d);
+ ATF_REQUIRE(d == -0x1.0ea3f4af0dc5ap0);
+ sscanf("1.0571892669084010", "%le", &d);
+ ATF_REQUIRE(d == 0x1.0ea3f4af0dc5ap0);
+
+ sscanf("0x1.23p-5000", "%le", &d);
+ ATF_REQUIRE(d == 0.0);
+
+ sscanf("0x1.2345678p-1050", "%le", &d);
+ ATF_REQUIRE(d == 0x1.234567p-1050);
+
+ fesetround(FE_UPWARD);
+
+ sscanf("1.0571892669084007", "%le", &d);
+ ATF_REQUIRE(d == 0x1.0ea3f4af0dc5ap0);
+ sscanf("-1.0571892669084007", "%le", &d);
+ ATF_REQUIRE(d == -0x1.0ea3f4af0dc59p0);
+ sscanf("1.0571892669084010", "%le", &d);
+ ATF_REQUIRE(d == 0x1.0ea3f4af0dc5bp0);
+
+ sscanf("0x1.23p-5000", "%le", &d);
+ ATF_REQUIRE(d == 0x1p-1074);
+
+ sscanf("0x1.2345678p-1050", "%le", &d);
+ ATF_REQUIRE(d == 0x1.234568p-1050);
+
+ fesetround(FE_TOWARDZERO);
+
+ sscanf("1.0571892669084007", "%le", &d);
+ ATF_REQUIRE(d == 0x1.0ea3f4af0dc59p0);
+ sscanf("-1.0571892669084007", "%le", &d);
+ ATF_REQUIRE(d == -0x1.0ea3f4af0dc59p0);
+ sscanf("1.0571892669084010", "%le", &d);
+ ATF_REQUIRE(d == 0x1.0ea3f4af0dc5ap0);
+
+ sscanf("0x1.23p-5000", "%le", &d);
+ ATF_REQUIRE(d == 0.0);
+
+ sscanf("0x1.2345678p-1050", "%le", &d);
+ ATF_REQUIRE(d == 0x1.234567p-1050);
+
+ fesetround(FE_TONEAREST);
+
+ /* 1.0571892669084007 is slightly closer to 0x1.0ea3f4af0dc59p0 */
+ sscanf("1.0571892669084007", "%le", &d);
+ ATF_REQUIRE(d == 0x1.0ea3f4af0dc59p0);
+ sscanf("-1.0571892669084007", "%le", &d);
+ ATF_REQUIRE(d == -0x1.0ea3f4af0dc59p0);
+ sscanf("1.0571892669084010", "%le", &d);
+ ATF_REQUIRE(d == 0x1.0ea3f4af0dc5bp0);
+
+ /* strtod() should round small numbers to 0. */
+ sscanf("0x1.23p-5000", "%le", &d);
+ ATF_REQUIRE(d == 0.0);
+
+ /* Extra digits in a denormal shouldn't break anything. */
+ sscanf("0x1.2345678p-1050", "%le", &d);
+ ATF_REQUIRE(d == 0x1.234568p-1050);
+}
+
+ATF_TC_WITHOUT_HEAD(strtod);
+ATF_TC_BODY(strtod, tc)
+{
+ char *endp;
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ ATF_REQUIRE(strtod("0xy", &endp) == 0);
+ ATF_REQUIRE(strcmp("xy", endp) == 0);
+
+ /* This used to cause an infinite loop and round the wrong way. */
+ fesetround(FE_DOWNWARD);
+ ATF_REQUIRE(strtof("3.5e38", &endp) == FLT_MAX);
+ ATF_REQUIRE(strtod("2e308", &endp) == DBL_MAX);
+ fesetround(FE_UPWARD);
+ ATF_REQUIRE(strtof("3.5e38", &endp) == INFINITY);
+ ATF_REQUIRE(strtod("2e308", &endp) == INFINITY);
+ fesetround(FE_TOWARDZERO);
+ ATF_REQUIRE(strtof("3.5e38", &endp) == FLT_MAX);
+ ATF_REQUIRE(strtod("2e308", &endp) == DBL_MAX);
+ fesetround(FE_TONEAREST);
+ ATF_REQUIRE(strtof("3.5e38", &endp) == INFINITY);
+ ATF_REQUIRE(strtod("2e308", &endp) == INFINITY);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, normalized_numbers);
+ ATF_TP_ADD_TC(tp, infinities_and_nans);
+ ATF_TP_ADD_TC(tp, rounding_tests);
+ ATF_TP_ADD_TC(tp, strtod);
+
+ return (atf_no_error());
+}