diff options
author | jhb <jhb@FreeBSD.org> | 2013-02-27 19:50:46 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2013-02-27 19:50:46 +0000 |
commit | 2b2e6341820f4bf973e758ae57713a8e6d356a3a (patch) | |
tree | 816ebb18fe50626639453ff4d9e8077daa1693e2 /tools/regression/lib/libc/stdio | |
parent | 743bccf1ecd630e8a4bc5f9e27f286fc4567e98d (diff) | |
download | FreeBSD-src-2b2e6341820f4bf973e758ae57713a8e6d356a3a.zip FreeBSD-src-2b2e6341820f4bf973e758ae57713a8e6d356a3a.tar.gz |
Add an implementation of open_memstream() and open_wmemstream(). These
routines provide write-only stdio FILE objects that store their data in a
dynamically allocated buffer. They are a string builder interface somewhat
akin to a completely dynamic sbuf.
Reviewed by: bde, jilles (earlier versions)
MFC after: 1 month
Diffstat (limited to 'tools/regression/lib/libc/stdio')
-rw-r--r-- | tools/regression/lib/libc/stdio/Makefile | 4 | ||||
-rw-r--r-- | tools/regression/lib/libc/stdio/test-open_memstream.c | 203 | ||||
-rw-r--r-- | tools/regression/lib/libc/stdio/test-open_memstream.t | 10 | ||||
-rw-r--r-- | tools/regression/lib/libc/stdio/test-open_wmemstream.c | 203 | ||||
-rw-r--r-- | tools/regression/lib/libc/stdio/test-open_wmemstream.t | 10 |
5 files changed, 429 insertions, 1 deletions
diff --git a/tools/regression/lib/libc/stdio/Makefile b/tools/regression/lib/libc/stdio/Makefile index d62ac84..f496f73 100644 --- a/tools/regression/lib/libc/stdio/Makefile +++ b/tools/regression/lib/libc/stdio/Makefile @@ -1,6 +1,8 @@ # $FreeBSD$ -TESTS= test-getdelim test-perror test-print-positional test-printbasic test-printfloat test-scanfloat +TESTS= test-fmemopen test-getdelim test-open_memstream test-open_wmemstream \ + test-perror test-print-positional test-printbasic test-printfloat \ + test-scanfloat CFLAGS+= -lm .PHONY: tests diff --git a/tools/regression/lib/libc/stdio/test-open_memstream.c b/tools/regression/lib/libc/stdio/test-open_memstream.c new file mode 100644 index 0000000..1a168c6 --- /dev/null +++ b/tools/regression/lib/libc/stdio/test-open_memstream.c @@ -0,0 +1,203 @@ +/*- + * Copyright (c) 2013 Advanced Computing Technologies 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> + +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); +} + +static void +open_group_test(void) +{ + FILE *fp; + off_t eob; + + fp = open_memstream(&buf, &len); + if (fp == NULL) + err(1, "failed to open stream"); + + 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); +} + +static void +simple_tests(void) +{ + static const char zerobuf[] = + { 'f', 'o', 'o', 0, 0, 0, 0, 'b', 'a', 'r', 0 }; + char c; + FILE *fp; + + fp = open_memstream(&buf, NULL); + if (fp != NULL) + errx(1, "did not fail to open stream"); + else if (errno != EINVAL) + err(1, "incorrect error for bad length pointer"); + fp = open_memstream(NULL, &len); + if (fp != NULL) + errx(1, "did not fail to open stream"); + else if (errno != EINVAL) + err(1, "incorrect error for bad buffer pointer"); + fp = open_memstream(&buf, &len); + if (fp == NULL) + err(1, "failed to open stream"); + 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); +} + +static void +seek_tests(void) +{ + FILE *fp; + + fp = open_memstream(&buf, &len); + if (fp == NULL) + err(1, "failed to open stream"); +#define SEEK_FAIL(offset, whence, error) do { \ + errno = 0; \ + if (fseeko(fp, (offset), (whence)) == 0) \ + printf("fseeko(%s, %s) did not fail, set pos to %jd\n", \ + __STRING(offset), __STRING(whence), \ + (intmax_t)ftello(fp)); \ + else if (errno != (error)) \ + printf("fseeko(%s, %s) failed with %d rather than %s\n",\ + __STRING(offset), __STRING(whence), errno, \ + __STRING(error)); \ +} while (0) + +#define SEEK_OK(offset, whence, result) do { \ + if (fseeko(fp, (offset), (whence)) != 0) \ + printf("fseeko(%s, %s) failed: %s\n", \ + __STRING(offset), __STRING(whence), strerror(errno)); \ + else if (ftello(fp) != (result)) \ + printf("fseeko(%s, %s) seeked to %jd rather than %s\n", \ + __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); +} + +int +main(int ac, char **av) +{ + + open_group_test(); + simple_tests(); + seek_tests(); + return (0); +} diff --git a/tools/regression/lib/libc/stdio/test-open_memstream.t b/tools/regression/lib/libc/stdio/test-open_memstream.t new file mode 100644 index 0000000..8bdfd03 --- /dev/null +++ b/tools/regression/lib/libc/stdio/test-open_memstream.t @@ -0,0 +1,10 @@ +#!/bin/sh +# $FreeBSD$ + +cd `dirname $0` + +executable=`basename $0 .t` + +make $executable 2>&1 > /dev/null + +exec ./$executable diff --git a/tools/regression/lib/libc/stdio/test-open_wmemstream.c b/tools/regression/lib/libc/stdio/test-open_wmemstream.c new file mode 100644 index 0000000..4cd0ab9 --- /dev/null +++ b/tools/regression/lib/libc/stdio/test-open_wmemstream.c @@ -0,0 +1,203 @@ +/*- + * Copyright (c) 2013 Advanced Computing Technologies 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> + +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); +} + +static void +open_group_test(void) +{ + FILE *fp; + off_t eob; + + fp = open_wmemstream(&buf, &len); + if (fp == NULL) + err(1, "failed to open stream"); + + 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); +} + +static void +simple_tests(void) +{ + 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); + if (fp != NULL) + errx(1, "did not fail to open stream"); + else if (errno != EINVAL) + err(1, "incorrect error for bad length pointer"); + fp = open_wmemstream(NULL, &len); + if (fp != NULL) + errx(1, "did not fail to open stream"); + else if (errno != EINVAL) + err(1, "incorrect error for bad buffer pointer"); + fp = open_wmemstream(&buf, &len); + if (fp == NULL) + err(1, "failed to open stream"); + 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); +} + +static void +seek_tests(void) +{ + FILE *fp; + + fp = open_wmemstream(&buf, &len); + if (fp == NULL) + err(1, "failed to open stream"); +#define SEEK_FAIL(offset, whence, error) do { \ + errno = 0; \ + if (fseeko(fp, (offset), (whence)) == 0) \ + printf("fseeko(%s, %s) did not fail, set pos to %jd\n", \ + __STRING(offset), __STRING(whence), \ + (intmax_t)ftello(fp)); \ + else if (errno != (error)) \ + printf("fseeko(%s, %s) failed with %d rather than %s\n",\ + __STRING(offset), __STRING(whence), errno, \ + __STRING(error)); \ +} while (0) + +#define SEEK_OK(offset, whence, result) do { \ + if (fseeko(fp, (offset), (whence)) != 0) \ + printf("fseeko(%s, %s) failed: %s\n", \ + __STRING(offset), __STRING(whence), strerror(errno)); \ + else if (ftello(fp) != (result)) \ + printf("fseeko(%s, %s) seeked to %jd rather than %s\n", \ + __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); +} + +int +main(int ac, char **av) +{ + + open_group_test(); + simple_tests(); + seek_tests(); + return (0); +} diff --git a/tools/regression/lib/libc/stdio/test-open_wmemstream.t b/tools/regression/lib/libc/stdio/test-open_wmemstream.t new file mode 100644 index 0000000..8bdfd03 --- /dev/null +++ b/tools/regression/lib/libc/stdio/test-open_wmemstream.t @@ -0,0 +1,10 @@ +#!/bin/sh +# $FreeBSD$ + +cd `dirname $0` + +executable=`basename $0 .t` + +make $executable 2>&1 > /dev/null + +exec ./$executable |