svn commit: r252343 - in stable/9: include lib/libc/stdio tools/regression/lib/libc/stdio
John Baldwin
jhb at FreeBSD.org
Fri Jun 28 16:07:23 UTC 2013
Author: jhb
Date: Fri Jun 28 16:07:20 2013
New Revision: 252343
URL: http://svnweb.freebsd.org/changeset/base/252343
Log:
MFC 246120,246148,246206,246587,247411,247415:
Add fmemopen(3), open_memstream(3), and open_wmemstream(3) which provide
stdio FILE objects for memory buffers.
port exprun by: bdrewery
Added:
stable/9/lib/libc/stdio/fmemopen.c
- copied, changed from r246120, head/lib/libc/stdio/fmemopen.c
stable/9/lib/libc/stdio/open_memstream.3
- copied, changed from r247411, head/lib/libc/stdio/open_memstream.3
stable/9/lib/libc/stdio/open_memstream.c
- copied unchanged from r247411, head/lib/libc/stdio/open_memstream.c
stable/9/lib/libc/stdio/open_wmemstream.c
- copied unchanged from r247411, head/lib/libc/stdio/open_wmemstream.c
stable/9/tools/regression/lib/libc/stdio/test-fmemopen.c
- copied, changed from r246120, head/tools/regression/lib/libc/stdio/test-fmemopen.c
stable/9/tools/regression/lib/libc/stdio/test-fmemopen.t
- copied unchanged from r246120, head/tools/regression/lib/libc/stdio/test-fmemopen.t
stable/9/tools/regression/lib/libc/stdio/test-open_memstream.c
- copied unchanged from r247411, head/tools/regression/lib/libc/stdio/test-open_memstream.c
stable/9/tools/regression/lib/libc/stdio/test-open_memstream.t
- copied unchanged from r247411, head/tools/regression/lib/libc/stdio/test-open_memstream.t
stable/9/tools/regression/lib/libc/stdio/test-open_wmemstream.c
- copied unchanged from r247411, head/tools/regression/lib/libc/stdio/test-open_wmemstream.c
stable/9/tools/regression/lib/libc/stdio/test-open_wmemstream.t
- copied unchanged from r247411, head/tools/regression/lib/libc/stdio/test-open_wmemstream.t
Modified:
stable/9/include/stdio.h (contents, props changed)
stable/9/include/wchar.h
stable/9/lib/libc/stdio/Makefile.inc (contents, props changed)
stable/9/lib/libc/stdio/Symbol.map (contents, props changed)
stable/9/lib/libc/stdio/fopen.3 (contents, props changed)
stable/9/tools/regression/lib/libc/stdio/Makefile
Directory Properties:
stable/9/include/ (props changed)
stable/9/lib/libc/ (props changed)
stable/9/tools/regression/lib/libc/ (props changed)
Modified: stable/9/include/stdio.h
==============================================================================
--- stable/9/include/stdio.h Fri Jun 28 15:55:30 2013 (r252342)
+++ stable/9/include/stdio.h Fri Jun 28 16:07:20 2013 (r252343)
@@ -343,8 +343,10 @@ char *tempnam(const char *, const char *
#endif
#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200809
+FILE *fmemopen(void * __restrict, size_t, const char * __restrict);
ssize_t getdelim(char ** __restrict, size_t * __restrict, int,
FILE * __restrict);
+FILE *open_memstream(char **, size_t *);
int renameat(int, const char *, int, const char *);
int vdprintf(int, const char * __restrict, __va_list);
Modified: stable/9/include/wchar.h
==============================================================================
--- stable/9/include/wchar.h Fri Jun 28 15:55:30 2013 (r252342)
+++ stable/9/include/wchar.h Fri Jun 28 16:07:20 2013 (r252343)
@@ -209,6 +209,7 @@ int wcwidth(wchar_t);
#if __POSIX_VISIBLE >= 200809 || __BSD_VISIBLE
size_t mbsnrtowcs(wchar_t * __restrict, const char ** __restrict, size_t,
size_t, mbstate_t * __restrict);
+FILE *open_wmemstream(wchar_t **, size_t *);
wchar_t *wcpcpy(wchar_t * __restrict, const wchar_t * __restrict);
wchar_t *wcpncpy(wchar_t * __restrict, const wchar_t * __restrict, size_t);
wchar_t *wcsdup(const wchar_t *) __malloc_like;
Modified: stable/9/lib/libc/stdio/Makefile.inc
==============================================================================
--- stable/9/lib/libc/stdio/Makefile.inc Fri Jun 28 15:55:30 2013 (r252342)
+++ stable/9/lib/libc/stdio/Makefile.inc Fri Jun 28 16:07:20 2013 (r252343)
@@ -8,11 +8,13 @@ SRCS+= _flock_stub.c asprintf.c clrerr.c
fclose.c fcloseall.c fdopen.c \
feof.c ferror.c fflush.c fgetc.c fgetln.c fgetpos.c fgets.c fgetwc.c \
fgetwln.c fgetws.c \
- fileno.c findfp.c flags.c fopen.c fprintf.c fpurge.c fputc.c fputs.c \
+ fileno.c findfp.c flags.c fmemopen.c fopen.c fprintf.c fpurge.c \
+ fputc.c fputs.c \
fputwc.c fputws.c fread.c freopen.c fscanf.c fseek.c fsetpos.c \
ftell.c funopen.c fvwrite.c fwalk.c fwide.c fwprintf.c fwscanf.c \
fwrite.c getc.c getchar.c getdelim.c getline.c \
gets.c getw.c getwc.c getwchar.c makebuf.c mktemp.c \
+ open_memstream.c open_wmemstream.c \
perror.c printf.c printf-pos.c putc.c putchar.c \
puts.c putw.c putwc.c putwchar.c \
refill.c remove.c rewind.c rget.c scanf.c setbuf.c setbuffer.c \
@@ -35,7 +37,7 @@ MAN+= fclose.3 ferror.3 fflush.3 fgetln.
flockfile.3 \
fopen.3 fputs.3 \
fputws.3 fread.3 fseek.3 funopen.3 fwide.3 getc.3 \
- getline.3 getwc.3 mktemp.3 \
+ getline.3 getwc.3 mktemp.3 open_memstream.3 \
printf.3 printf_l.3 putc.3 putwc.3 remove.3 scanf.3 scanf_l.3 setbuf.3 \
stdio.3 tmpnam.3 \
ungetc.3 ungetwc.3 wprintf.3 wscanf.3
@@ -48,7 +50,7 @@ MLINKS+=ferror.3 ferror_unlocked.3 \
MLINKS+=fflush.3 fpurge.3
MLINKS+=fgets.3 gets.3
MLINKS+=flockfile.3 ftrylockfile.3 flockfile.3 funlockfile.3
-MLINKS+=fopen.3 fdopen.3 fopen.3 freopen.3
+MLINKS+=fopen.3 fdopen.3 fopen.3 freopen.3 fopen.3 fmemopen.3
MLINKS+=fputs.3 puts.3
MLINKS+=fread.3 fwrite.3
MLINKS+=fseek.3 fgetpos.3 fseek.3 fseeko.3 fseek.3 fsetpos.3 fseek.3 ftell.3 \
@@ -59,6 +61,7 @@ MLINKS+=getc.3 fgetc.3 getc.3 getc_unloc
MLINKS+=getline.3 getdelim.3
MLINKS+=getwc.3 fgetwc.3 getwc.3 getwchar.3
MLINKS+=mktemp.3 mkdtemp.3 mktemp.3 mkstemp.3 mktemp.3 mkstemps.3
+MLINKS+=open_memstream.3 open_wmemstream.3
MLINKS+=printf.3 asprintf.3 printf.3 dprintf.3 printf.3 fprintf.3 \
printf.3 snprintf.3 printf.3 sprintf.3 \
printf.3 vasprintf.3 printf.3 vdprintf.3 \
Modified: stable/9/lib/libc/stdio/Symbol.map
==============================================================================
--- stable/9/lib/libc/stdio/Symbol.map Fri Jun 28 15:55:30 2013 (r252342)
+++ stable/9/lib/libc/stdio/Symbol.map Fri Jun 28 16:07:20 2013 (r252343)
@@ -155,6 +155,9 @@ FBSD_1.3 {
getwchar_l;
putwc_l;
putwchar_l;
+ fmemopen;
+ open_memstream;
+ open_wmemstream;
};
FBSDprivate_1.0 {
Copied and modified: stable/9/lib/libc/stdio/fmemopen.c (from r246120, head/lib/libc/stdio/fmemopen.c)
==============================================================================
--- head/lib/libc/stdio/fmemopen.c Wed Jan 30 14:59:26 2013 (r246120, copy source)
+++ stable/9/lib/libc/stdio/fmemopen.c Fri Jun 28 16:07:20 2013 (r252343)
@@ -1,99 +1,166 @@
/*-
-Copyright (C) 2013 Pietro Cerutti <gahr at 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.
-*/
+ * Copyright (C) 2013 Pietro Cerutti <gahr at 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.
+ */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <fcntl.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include "local.h"
-struct __fmemopen_cookie
+struct fmemopen_cookie
{
- char *buf; /* pointer to the memory region */
- char own; /* did we allocate the buffer ourselves? */
- long len; /* buffer length in bytes */
- long off; /* current offset into the buffer */
+ char *buf; /* pointer to the memory region */
+ bool own; /* did we allocate the buffer ourselves? */
+ char bin; /* is this a binary buffer? */
+ size_t size; /* buffer length in bytes */
+ size_t len; /* data length in bytes */
+ size_t off; /* current offset into the buffer */
};
-static int fmemopen_read (void *cookie, char *buf, int nbytes);
-static int fmemopen_write (void *cookie, const char *buf, int nbytes);
-static fpos_t fmemopen_seek (void *cookie, fpos_t offset, int whence);
-static int fmemopen_close (void *cookie);
+static int fmemopen_read(void *cookie, char *buf, int nbytes);
+static int fmemopen_write(void *cookie, const char *buf, int nbytes);
+static fpos_t fmemopen_seek(void *cookie, fpos_t offset, int whence);
+static int fmemopen_close(void *cookie);
FILE *
-fmemopen (void * __restrict buf, size_t size, const char * __restrict mode)
+fmemopen(void * __restrict buf, size_t size, const char * __restrict mode)
{
- /* allocate cookie */
- struct __fmemopen_cookie *ck = malloc (sizeof (struct __fmemopen_cookie));
+ struct fmemopen_cookie *ck;
+ FILE *f;
+ int flags, rc;
+
+ /*
+ * Retrieve the flags as used by open(2) from the mode argument, and
+ * validate them.
+ */
+ rc = __sflags(mode, &flags);
+ if (rc == 0) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /*
+ * There's no point in requiring an automatically allocated buffer
+ * in write-only mode.
+ */
+ if (!(flags & O_RDWR) && buf == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ ck = malloc(sizeof(struct fmemopen_cookie));
if (ck == NULL) {
- errno = ENOMEM;
return (NULL);
}
- ck->off = 0;
- ck->len = size;
+ ck->off = 0;
+ ck->size = size;
- /* do we have to allocate the buffer ourselves? */
+ /* Check whether we have to allocate the buffer ourselves. */
ck->own = ((ck->buf = buf) == NULL);
if (ck->own) {
- ck->buf = malloc (size);
+ ck->buf = malloc(size);
if (ck->buf == NULL) {
- free (ck);
- errno = ENOMEM;
+ free(ck);
return (NULL);
}
+ }
+
+ /*
+ * POSIX distinguishes between w+ and r+, in that w+ is supposed to
+ * truncate the buffer.
+ */
+ if (ck->own || mode[0] == 'w') {
ck->buf[0] = '\0';
}
- if (mode[0] == 'a')
- ck->off = strnlen(ck->buf, ck->len);
+ /* Check for binary mode. */
+ ck->bin = strchr(mode, 'b') != NULL;
- /* actuall wrapper */
- FILE *f = funopen ((void *)ck, fmemopen_read, fmemopen_write,
+ /*
+ * The size of the current buffer contents is set depending on the
+ * mode:
+ *
+ * for append (text-mode), the position of the first NULL byte, or the
+ * size of the buffer if none is found
+ *
+ * for append (binary-mode), the size of the buffer
+ *
+ * for read, the size of the buffer
+ *
+ * for write, 0
+ */
+ switch (mode[0]) {
+ case 'a':
+ if (ck->bin) {
+ /*
+ * This isn't useful, since the buffer isn't allowed
+ * to grow.
+ */
+ ck->off = ck->len = size;
+ } else
+ ck->off = ck->len = strnlen(ck->buf, ck->size);
+ break;
+ case 'r':
+ ck->len = size;
+ break;
+ case 'w':
+ ck->len = 0;
+ break;
+ }
+
+ f = funopen(ck,
+ flags & O_WRONLY ? NULL : fmemopen_read,
+ flags & O_RDONLY ? NULL : fmemopen_write,
fmemopen_seek, fmemopen_close);
if (f == NULL) {
if (ck->own)
- free (ck->buf);
- free (ck);
+ free(ck->buf);
+ free(ck);
return (NULL);
}
- /* turn off buffering, so a write past the end of the buffer
- * correctly returns a short object count */
- setvbuf (f, (char *) NULL, _IONBF, 0);
+ /*
+ * Turn off buffering, so a write past the end of the buffer
+ * correctly returns a short object count.
+ */
+ setvbuf(f, NULL, _IONBF, 0);
return (f);
}
static int
-fmemopen_read (void *cookie, char *buf, int nbytes)
+fmemopen_read(void *cookie, char *buf, int nbytes)
{
- struct __fmemopen_cookie *ck = cookie;
+ struct fmemopen_cookie *ck = cookie;
if (nbytes > ck->len - ck->off)
nbytes = ck->len - ck->off;
@@ -101,7 +168,7 @@ fmemopen_read (void *cookie, char *buf,
if (nbytes == 0)
return (0);
- memcpy (buf, ck->buf + ck->off, nbytes);
+ memcpy(buf, ck->buf + ck->off, nbytes);
ck->off += nbytes;
@@ -109,35 +176,44 @@ fmemopen_read (void *cookie, char *buf,
}
static int
-fmemopen_write (void *cookie, const char *buf, int nbytes)
+fmemopen_write(void *cookie, const char *buf, int nbytes)
{
- struct __fmemopen_cookie *ck = cookie;
+ struct fmemopen_cookie *ck = cookie;
- if (nbytes > ck->len - ck->off)
- nbytes = ck->len - ck->off;
+ if (nbytes > ck->size - ck->off)
+ nbytes = ck->size - ck->off;
if (nbytes == 0)
return (0);
- memcpy (ck->buf + ck->off, buf, nbytes);
+ memcpy(ck->buf + ck->off, buf, nbytes);
ck->off += nbytes;
- if (ck->off < ck->len && ck->buf[ck->off - 1] != '\0')
+ if (ck->off > ck->len)
+ ck->len = ck->off;
+
+ /*
+ * We append a NULL byte if all these conditions are met:
+ * - the buffer is not binary
+ * - the buffer is not full
+ * - the data just written doesn't already end with a NULL byte
+ */
+ if (!ck->bin && ck->off < ck->size && ck->buf[ck->off - 1] != '\0')
ck->buf[ck->off] = '\0';
return (nbytes);
}
static fpos_t
-fmemopen_seek (void *cookie, fpos_t offset, int whence)
+fmemopen_seek(void *cookie, fpos_t offset, int whence)
{
- struct __fmemopen_cookie *ck = cookie;
+ struct fmemopen_cookie *ck = cookie;
switch (whence) {
case SEEK_SET:
- if (offset > ck->len) {
+ if (offset > ck->size) {
errno = EINVAL;
return (-1);
}
@@ -145,7 +221,7 @@ fmemopen_seek (void *cookie, fpos_t offs
break;
case SEEK_CUR:
- if (ck->off + offset > ck->len) {
+ if (ck->off + offset > ck->size) {
errno = EINVAL;
return (-1);
}
@@ -169,14 +245,14 @@ fmemopen_seek (void *cookie, fpos_t offs
}
static int
-fmemopen_close (void *cookie)
+fmemopen_close(void *cookie)
{
- struct __fmemopen_cookie *ck = cookie;
+ struct fmemopen_cookie *ck = cookie;
if (ck->own)
- free (ck->buf);
+ free(ck->buf);
- free (ck);
+ free(ck);
return (0);
}
Modified: stable/9/lib/libc/stdio/fopen.3
==============================================================================
--- stable/9/lib/libc/stdio/fopen.3 Fri Jun 28 15:55:30 2013 (r252342)
+++ stable/9/lib/libc/stdio/fopen.3 Fri Jun 28 16:07:20 2013 (r252343)
@@ -32,13 +32,14 @@
.\" @(#)fopen.3 8.1 (Berkeley) 6/4/93
.\" $FreeBSD$
.\"
-.Dd October 17, 2011
+.Dd January 30, 2013
.Dt FOPEN 3
.Os
.Sh NAME
.Nm fopen ,
.Nm fdopen ,
-.Nm freopen
+.Nm freopen ,
+.Nm fmemopen
.Nd stream open functions
.Sh LIBRARY
.Lb libc
@@ -50,6 +51,8 @@
.Fn fdopen "int fildes" "const char *mode"
.Ft FILE *
.Fn freopen "const char *path" "const char *mode" "FILE *stream"
+.Ft FILE *
+.Fn fmemopen "void *restrict *buf" "size_t size" "const char * restrict mode"
.Sh DESCRIPTION
The
.Fn fopen
@@ -107,7 +110,9 @@ after either the
or the first letter.
This is strictly for compatibility with
.St -isoC
-and has no effect; the ``b'' is ignored.
+and has effect only for
+.Fn fmemopen
+; otherwise the ``b'' is ignored.
.Pp
Any created files will have mode
.Do Dv S_IRUSR
@@ -189,6 +194,34 @@ standard text stream
.Dv ( stderr , stdin ,
or
.Dv stdout ) .
+.Pp
+The
+.Fn fmemopen
+function
+associates the buffer given by the
+.Fa buf
+and
+.Fa size
+arguments with a stream.
+The
+.Fa buf
+argument is either a null pointer or point to a buffer that
+is at least
+.Fa size
+bytes long.
+If a null pointer is specified as the
+.Fa buf
+argument,
+.Fn fmemopen
+allocates
+.Fa size
+bytes of memory. This buffer is automatically freed when the
+stream is closed. Buffers can be opened in text-mode (default) or binary-mode
+(if ``b'' is present in the second or third position of the
+.Fa mode
+argument). Buffers opened in text-mode make sure that writes are terminated with
+a NULL byte, if the last write hasn't filled up the whole buffer. Buffers
+opened in binary-mode never append a NULL byte.
.Sh RETURN VALUES
Upon successful completion
.Fn fopen ,
@@ -212,16 +245,18 @@ argument
to
.Fn fopen ,
.Fn fdopen ,
+.Fn freopen ,
or
-.Fn freopen
+.Fn fmemopen
was invalid.
.El
.Pp
The
.Fn fopen ,
-.Fn fdopen
-and
+.Fn fdopen ,
.Fn freopen
+and
+.Fn fmemopen
functions
may also fail and set
.Va errno
@@ -277,3 +312,10 @@ The
function
conforms to
.St -p1003.1-88 .
+The
+.Fn fmemopen
+function
+conforms to
+.St -p1003.1-2008 .
+The ``b'' mode does not conform to any standard
+but is also supported by glibc.
Copied and modified: stable/9/lib/libc/stdio/open_memstream.3 (from r247411, head/lib/libc/stdio/open_memstream.3)
==============================================================================
--- head/lib/libc/stdio/open_memstream.3 Wed Feb 27 19:50:46 2013 (r247411, copy source)
+++ stable/9/lib/libc/stdio/open_memstream.3 Fri Jun 28 16:07:20 2013 (r252343)
@@ -137,6 +137,7 @@ argument was
.Dv NULL .
.It Bq Er ENOMEM
Memory for the stream or buffer could not be allocated.
+.El
.Sh SEE ALSO
.Xr fclose 3 ,
.Xr fflush 3 ,
Copied: stable/9/lib/libc/stdio/open_memstream.c (from r247411, head/lib/libc/stdio/open_memstream.c)
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ stable/9/lib/libc/stdio/open_memstream.c Fri Jun 28 16:07:20 2013 (r252343, copy of r247411, head/lib/libc/stdio/open_memstream.c)
@@ -0,0 +1,209 @@
+/*-
+ * Copyright (c) 2013 Advanced Computing Technologies LLC
+ * Written by: John H. Baldwin <jhb at 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 "namespace.h"
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "un-namespace.h"
+
+/* XXX: There is no FPOS_MAX. This assumes fpos_t is an off_t. */
+#define FPOS_MAX OFF_MAX
+
+struct memstream {
+ char **bufp;
+ size_t *sizep;
+ ssize_t len;
+ fpos_t offset;
+};
+
+static int
+memstream_grow(struct memstream *ms, fpos_t newoff)
+{
+ char *buf;
+ ssize_t newsize;
+
+ if (newoff < 0 || newoff >= SSIZE_MAX)
+ newsize = SSIZE_MAX - 1;
+ else
+ newsize = newoff;
+ if (newsize > ms->len) {
+ buf = realloc(*ms->bufp, newsize + 1);
+ if (buf != NULL) {
+#ifdef DEBUG
+ fprintf(stderr, "MS: %p growing from %zd to %zd\n",
+ ms, ms->len, newsize);
+#endif
+ memset(buf + ms->len + 1, 0, newsize - ms->len);
+ *ms->bufp = buf;
+ ms->len = newsize;
+ return (1);
+ }
+ return (0);
+ }
+ return (1);
+}
+
+static void
+memstream_update(struct memstream *ms)
+{
+
+ assert(ms->len >= 0 && ms->offset >= 0);
+ *ms->sizep = ms->len < ms->offset ? ms->len : ms->offset;
+}
+
+static int
+memstream_write(void *cookie, const char *buf, int len)
+{
+ struct memstream *ms;
+ ssize_t tocopy;
+
+ ms = cookie;
+ if (!memstream_grow(ms, ms->offset + len))
+ return (-1);
+ tocopy = ms->len - ms->offset;
+ if (len < tocopy)
+ tocopy = len;
+ memcpy(*ms->bufp + ms->offset, buf, tocopy);
+ ms->offset += tocopy;
+ memstream_update(ms);
+#ifdef DEBUG
+ fprintf(stderr, "MS: write(%p, %d) = %zd\n", ms, len, tocopy);
+#endif
+ return (tocopy);
+}
+
+static fpos_t
+memstream_seek(void *cookie, fpos_t pos, int whence)
+{
+ struct memstream *ms;
+#ifdef DEBUG
+ fpos_t old;
+#endif
+
+ ms = cookie;
+#ifdef DEBUG
+ old = ms->offset;
+#endif
+ switch (whence) {
+ case SEEK_SET:
+ /* _fseeko() checks for negative offsets. */
+ assert(pos >= 0);
+ ms->offset = pos;
+ break;
+ case SEEK_CUR:
+ /* This is only called by _ftello(). */
+ assert(pos == 0);
+ break;
+ case SEEK_END:
+ if (pos < 0) {
+ if (pos + ms->len < 0) {
+#ifdef DEBUG
+ fprintf(stderr,
+ "MS: bad SEEK_END: pos %jd, len %zd\n",
+ (intmax_t)pos, ms->len);
+#endif
+ errno = EINVAL;
+ return (-1);
+ }
+ } else {
+ if (FPOS_MAX - ms->len < pos) {
+#ifdef DEBUG
+ fprintf(stderr,
+ "MS: bad SEEK_END: pos %jd, len %zd\n",
+ (intmax_t)pos, ms->len);
+#endif
+ errno = EOVERFLOW;
+ return (-1);
+ }
+ }
+ ms->offset = ms->len + pos;
+ break;
+ }
+ memstream_update(ms);
+#ifdef DEBUG
+ fprintf(stderr, "MS: seek(%p, %jd, %d) %jd -> %jd\n", ms, (intmax_t)pos,
+ whence, (intmax_t)old, (intmax_t)ms->offset);
+#endif
+ return (ms->offset);
+}
+
+static int
+memstream_close(void *cookie)
+{
+
+ free(cookie);
+ return (0);
+}
+
+FILE *
+open_memstream(char **bufp, size_t *sizep)
+{
+ struct memstream *ms;
+ int save_errno;
+ FILE *fp;
+
+ if (bufp == NULL || sizep == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+ *bufp = calloc(1, 1);
+ if (*bufp == NULL)
+ return (NULL);
+ ms = malloc(sizeof(*ms));
+ if (ms == NULL) {
+ save_errno = errno;
+ free(*bufp);
+ *bufp = NULL;
+ errno = save_errno;
+ return (NULL);
+ }
+ ms->bufp = bufp;
+ ms->sizep = sizep;
+ ms->len = 0;
+ ms->offset = 0;
+ memstream_update(ms);
+ fp = funopen(ms, NULL, memstream_write, memstream_seek,
+ memstream_close);
+ if (fp == NULL) {
+ save_errno = errno;
+ free(ms);
+ free(*bufp);
+ *bufp = NULL;
+ errno = save_errno;
+ return (NULL);
+ }
+ fwide(fp, -1);
+ return (fp);
+}
Copied: stable/9/lib/libc/stdio/open_wmemstream.c (from r247411, head/lib/libc/stdio/open_wmemstream.c)
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ stable/9/lib/libc/stdio/open_wmemstream.c Fri Jun 28 16:07:20 2013 (r252343, copy of r247411, head/lib/libc/stdio/open_wmemstream.c)
@@ -0,0 +1,271 @@
+/*-
+ * Copyright (c) 2013 Advanced Computing Technologies LLC
+ * Written by: John H. Baldwin <jhb at 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 "namespace.h"
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "un-namespace.h"
+
+/* XXX: There is no FPOS_MAX. This assumes fpos_t is an off_t. */
+#define FPOS_MAX OFF_MAX
+
+struct wmemstream {
+ wchar_t **bufp;
+ size_t *sizep;
+ ssize_t len;
+ fpos_t offset;
+ mbstate_t mbstate;
+};
+
+static int
+wmemstream_grow(struct wmemstream *ms, fpos_t newoff)
+{
+ wchar_t *buf;
+ ssize_t newsize;
+
+ if (newoff < 0 || newoff >= SSIZE_MAX / sizeof(wchar_t))
+ newsize = SSIZE_MAX / sizeof(wchar_t) - 1;
+ else
+ newsize = newoff;
+ if (newsize > ms->len) {
+ buf = realloc(*ms->bufp, (newsize + 1) * sizeof(wchar_t));
+ if (buf != NULL) {
+#ifdef DEBUG
+ fprintf(stderr, "WMS: %p growing from %zd to %zd\n",
+ ms, ms->len, newsize);
+#endif
+ wmemset(buf + ms->len + 1, 0, newsize - ms->len);
+ *ms->bufp = buf;
+ ms->len = newsize;
+ return (1);
+ }
+ return (0);
+ }
+ return (1);
+}
+
+static void
+wmemstream_update(struct wmemstream *ms)
+{
+
+ assert(ms->len >= 0 && ms->offset >= 0);
+ *ms->sizep = ms->len < ms->offset ? ms->len : ms->offset;
+}
+
+/*
+ * Based on a starting multibyte state and an input buffer, determine
+ * how many wchar_t's would be output. This doesn't use mbsnrtowcs()
+ * so that it can handle embedded null characters.
+ */
+static size_t
+wbuflen(const mbstate_t *state, const char *buf, int len)
+{
+ mbstate_t lenstate;
+ size_t charlen, count;
+
+ count = 0;
+ lenstate = *state;
+ while (len > 0) {
+ charlen = mbrlen(buf, len, &lenstate);
+ if (charlen == (size_t)-1)
+ return (-1);
+ if (charlen == (size_t)-2)
+ break;
+ if (charlen == 0)
+ /* XXX: Not sure how else to handle this. */
+ charlen = 1;
+ len -= charlen;
+ buf += charlen;
+ count++;
+ }
+ return (count);
+}
+
+static int
+wmemstream_write(void *cookie, const char *buf, int len)
+{
+ struct wmemstream *ms;
+ ssize_t consumed, wlen;
+ size_t charlen;
+
+ ms = cookie;
+ wlen = wbuflen(&ms->mbstate, buf, len);
+ if (wlen < 0) {
+ errno = EILSEQ;
+ return (-1);
+ }
+ if (!wmemstream_grow(ms, ms->offset + wlen))
+ return (-1);
+
+ /*
+ * This copies characters one at a time rather than using
+ * mbsnrtowcs() so it can properly handle embedded null
+ * characters.
+ */
+ consumed = 0;
+ while (len > 0 && ms->offset < ms->len) {
+ charlen = mbrtowc(*ms->bufp + ms->offset, buf, len,
+ &ms->mbstate);
+ if (charlen == (size_t)-1) {
+ if (consumed == 0) {
+ errno = EILSEQ;
+ return (-1);
+ }
+ /* Treat it as a successful short write. */
+ break;
+ }
+ if (charlen == 0)
+ /* XXX: Not sure how else to handle this. */
+ charlen = 1;
+ if (charlen == (size_t)-2) {
+ consumed += len;
+ len = 0;
+ } else {
+ consumed += charlen;
+ buf += charlen;
+ len -= charlen;
+ ms->offset++;
+ }
+ }
+ wmemstream_update(ms);
+#ifdef DEBUG
+ fprintf(stderr, "WMS: write(%p, %d) = %zd\n", ms, len, consumed);
+#endif
+ return (consumed);
+}
+
+static fpos_t
+wmemstream_seek(void *cookie, fpos_t pos, int whence)
+{
+ struct wmemstream *ms;
+ fpos_t old;
+
+ ms = cookie;
+ old = ms->offset;
+ switch (whence) {
+ case SEEK_SET:
+ /* _fseeko() checks for negative offsets. */
+ assert(pos >= 0);
+ ms->offset = pos;
+ break;
+ case SEEK_CUR:
+ /* This is only called by _ftello(). */
+ assert(pos == 0);
+ break;
+ case SEEK_END:
+ if (pos < 0) {
+ if (pos + ms->len < 0) {
+#ifdef DEBUG
+ fprintf(stderr,
+ "WMS: bad SEEK_END: pos %jd, len %zd\n",
+ (intmax_t)pos, ms->len);
+#endif
+ errno = EINVAL;
+ return (-1);
+ }
+ } else {
+ if (FPOS_MAX - ms->len < pos) {
+#ifdef DEBUG
+ fprintf(stderr,
+ "WMS: bad SEEK_END: pos %jd, len %zd\n",
+ (intmax_t)pos, ms->len);
+#endif
+ errno = EOVERFLOW;
+ return (-1);
+ }
+ }
+ ms->offset = ms->len + pos;
+ break;
+ }
+ /* Reset the multibyte state if a seek changes the position. */
+ if (ms->offset != old)
+ memset(&ms->mbstate, 0, sizeof(ms->mbstate));
+ wmemstream_update(ms);
+#ifdef DEBUG
+ fprintf(stderr, "WMS: seek(%p, %jd, %d) %jd -> %jd\n", ms,
+ (intmax_t)pos, whence, (intmax_t)old, (intmax_t)ms->offset);
+#endif
+ return (ms->offset);
+}
+
+static int
+wmemstream_close(void *cookie)
+{
+
+ free(cookie);
+ return (0);
+}
+
+FILE *
+open_wmemstream(wchar_t **bufp, size_t *sizep)
+{
+ struct wmemstream *ms;
+ int save_errno;
+ FILE *fp;
+
+ if (bufp == NULL || sizep == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+ *bufp = calloc(1, sizeof(wchar_t));
+ if (*bufp == NULL)
+ return (NULL);
+ ms = malloc(sizeof(*ms));
+ if (ms == NULL) {
+ save_errno = errno;
+ free(*bufp);
+ *bufp = NULL;
+ errno = save_errno;
+ return (NULL);
+ }
+ ms->bufp = bufp;
+ ms->sizep = sizep;
+ ms->len = 0;
+ ms->offset = 0;
+ memset(&ms->mbstate, 0, sizeof(mbstate_t));
+ wmemstream_update(ms);
+ fp = funopen(ms, NULL, wmemstream_write, wmemstream_seek,
+ wmemstream_close);
+ if (fp == NULL) {
+ save_errno = errno;
+ free(ms);
+ free(*bufp);
+ *bufp = NULL;
+ errno = save_errno;
+ return (NULL);
+ }
+ fwide(fp, 1);
+ return (fp);
+}
Modified: stable/9/tools/regression/lib/libc/stdio/Makefile
==============================================================================
--- stable/9/tools/regression/lib/libc/stdio/Makefile Fri Jun 28 15:55:30 2013 (r252342)
+++ stable/9/tools/regression/lib/libc/stdio/Makefile Fri Jun 28 16:07:20 2013 (r252343)
@@ -1,6 +1,8 @@
# $FreeBSD$
-TESTS= test-getdelim test-perror test-print-positional test-printbasic test-printfloat test-scanfloat
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-stable-9
mailing list