Implement fmemopen and open_memstream.
* libc/stdio/fmemopen.c (_fmemopen_r, fmemopen): New file. * libc/stdio/open_memstream.c (_open_memstream_r, open_memstream): New file. * libc/stdio/fopencookie.c (fcwriter): Minor optimization. * libc/include/stdio.h (dprintf, vdprintf): Group all POSIX 200x functions together. (fmemopen, open_memstream): Declare new functions. * libc/stdio/stdio.tex: Document them. * libc/stdio/Makefile.am (ELIX_4_SOURCES, CHEWOUT_FILES): Add fmemopen and open_memstream. * libc/stdio/Makefile.in: Regenerate.
This commit is contained in:
parent
191814588a
commit
6ddcdb9da5
|
@ -1,3 +1,18 @@
|
|||
2007-08-02 Eric Blake <ebb9@byu.net>
|
||||
|
||||
Implement fmemopen and open_memstream.
|
||||
* libc/stdio/fmemopen.c (_fmemopen_r, fmemopen): New file.
|
||||
* libc/stdio/open_memstream.c (_open_memstream_r, open_memstream):
|
||||
New file.
|
||||
* libc/stdio/fopencookie.c (fcwriter): Minor optimization.
|
||||
* libc/include/stdio.h (dprintf, vdprintf): Group all POSIX 200x
|
||||
functions together.
|
||||
(fmemopen, open_memstream): Declare new functions.
|
||||
* libc/stdio/stdio.tex: Document them.
|
||||
* libc/stdio/Makefile.am (ELIX_4_SOURCES, CHEWOUT_FILES): Add
|
||||
fmemopen and open_memstream.
|
||||
* libc/stdio/Makefile.in: Regenerate.
|
||||
|
||||
2007-07-31 Eric Blake <ebb9@byu.net>
|
||||
|
||||
More POSIX stream corner cases.
|
||||
|
|
|
@ -244,11 +244,9 @@ char * _EXFUN(asnprintf, (char *, size_t *, const char *, ...)
|
|||
_ATTRIBUTE ((__format__ (__printf__, 3, 4))));
|
||||
int _EXFUN(asprintf, (char **, const char *, ...)
|
||||
_ATTRIBUTE ((__format__ (__printf__, 2, 3))));
|
||||
#ifndef dprintf
|
||||
#ifndef diprintf
|
||||
int _EXFUN(diprintf, (int, const char *, ...)
|
||||
_ATTRIBUTE ((__format__ (__printf__, 2, 3))));
|
||||
int _EXFUN(dprintf, (int, const char *, ...)
|
||||
_ATTRIBUTE ((__format__ (__printf__, 2, 3))));
|
||||
#endif
|
||||
int _EXFUN(fcloseall, (_VOID));
|
||||
int _EXFUN(fiprintf, (FILE *, const char *, ...)
|
||||
|
@ -278,8 +276,6 @@ int _EXFUN(vasprintf, (char **, const char *, __VALIST)
|
|||
_ATTRIBUTE ((__format__ (__printf__, 2, 0))));
|
||||
int _EXFUN(vdiprintf, (int, const char *, __VALIST)
|
||||
_ATTRIBUTE ((__format__ (__printf__, 2, 0))));
|
||||
int _EXFUN(vdprintf, (int, const char *, __VALIST)
|
||||
_ATTRIBUTE ((__format__ (__printf__, 2, 0))));
|
||||
int _EXFUN(vfiprintf, (FILE *, const char *, __VALIST)
|
||||
_ATTRIBUTE ((__format__ (__printf__, 2, 0))));
|
||||
int _EXFUN(vfiscanf, (FILE *, const char *, __VALIST)
|
||||
|
@ -306,7 +302,7 @@ int _EXFUN(vsscanf, (const char *, const char *, __VALIST)
|
|||
#endif /* !__STRICT_ANSI__ */
|
||||
|
||||
/*
|
||||
* Routines in POSIX 1003.1.
|
||||
* Routines in POSIX 1003.1:2001.
|
||||
*/
|
||||
|
||||
#ifndef __STRICT_ANSI__
|
||||
|
@ -329,6 +325,26 @@ int _EXFUN(putc_unlocked, (int, FILE *));
|
|||
int _EXFUN(putchar_unlocked, (int));
|
||||
#endif /* ! __STRICT_ANSI__ */
|
||||
|
||||
/*
|
||||
* Routines in POSIX 1003.1:200x.
|
||||
*/
|
||||
|
||||
#ifndef __STRICT_ANSI__
|
||||
# ifndef _REENT_ONLY
|
||||
# ifndef dprintf
|
||||
int _EXFUN(dprintf, (int, const char *, ...)
|
||||
_ATTRIBUTE ((__format__ (__printf__, 2, 3))));
|
||||
# endif
|
||||
FILE * _EXFUN(fmemopen, (void *, size_t, const char *));
|
||||
/* getdelim - see __getdelim for now */
|
||||
/* getline - see __getline for now */
|
||||
FILE * _EXFUN(open_memstream, (char **, size_t *));
|
||||
/* renameat - unimplemented for now */
|
||||
int _EXFUN(vdprintf, (int, const char *, __VALIST)
|
||||
_ATTRIBUTE ((__format__ (__printf__, 2, 0))));
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Recursive versions of the above.
|
||||
*/
|
||||
|
@ -354,6 +370,7 @@ int _EXFUN(_fiprintf_r, (struct _reent *, FILE *, const char *, ...)
|
|||
_ATTRIBUTE ((__format__ (__printf__, 3, 4))));
|
||||
int _EXFUN(_fiscanf_r, (struct _reent *, FILE *, const char *, ...)
|
||||
_ATTRIBUTE ((__format__ (__scanf__, 3, 4))));
|
||||
FILE * _EXFUN(_fmemopen_r, (struct _reent *, void *, size_t, const char *));
|
||||
FILE * _EXFUN(_fopen_r, (struct _reent *, const char *, const char *));
|
||||
int _EXFUN(_fprintf_r, (struct _reent *, FILE *, const char *, ...)
|
||||
_ATTRIBUTE ((__format__ (__printf__, 3, 4))));
|
||||
|
@ -376,6 +393,7 @@ int _EXFUN(_iscanf_r, (struct _reent *, const char *, ...)
|
|||
_ATTRIBUTE ((__format__ (__scanf__, 2, 3))));
|
||||
int _EXFUN(_mkstemp_r, (struct _reent *, char *));
|
||||
char * _EXFUN(_mktemp_r, (struct _reent *, char *));
|
||||
FILE * _EXFUN(_open_memstream_r, (struct _reent *, char **, size_t *));
|
||||
void _EXFUN(_perror_r, (struct _reent *, const char *));
|
||||
int _EXFUN(_printf_r, (struct _reent *, const char *, ...)
|
||||
_ATTRIBUTE ((__format__ (__printf__, 2, 3))));
|
||||
|
|
|
@ -117,8 +117,10 @@ ELIX_4_SOURCES = \
|
|||
asnprintf.c \
|
||||
diprintf.c \
|
||||
dprintf.c \
|
||||
fmemopen.c \
|
||||
fopencookie.c \
|
||||
funopen.c \
|
||||
open_memstream.c \
|
||||
vasniprintf.c \
|
||||
vasnprintf.c
|
||||
endif !ELIX_LEVEL_3
|
||||
|
@ -179,6 +181,7 @@ CHEWOUT_FILES = \
|
|||
fgetpos.def \
|
||||
fgets.def \
|
||||
fileno.def \
|
||||
fmemopen.def \
|
||||
fopen.def \
|
||||
fopencookie.def \
|
||||
fputc.def \
|
||||
|
@ -199,6 +202,7 @@ CHEWOUT_FILES = \
|
|||
gets.def \
|
||||
getw.def \
|
||||
mktemp.def \
|
||||
open_memstream.def \
|
||||
perror.def \
|
||||
putc.def \
|
||||
putc_u.def \
|
||||
|
@ -244,6 +248,7 @@ $(lpfx)fclose.$(oext): local.h
|
|||
$(lpfx)fdopen.$(oext): local.h
|
||||
$(lpfx)fflush.$(oext): local.h
|
||||
$(lpfx)findfp.$(oext): local.h
|
||||
$(lpfx)fmemopen.$(oext): local.h
|
||||
$(lpfx)fopen.$(oext): local.h
|
||||
$(lpfx)fopencookie.$(oext): local.h
|
||||
$(lpfx)fputs.$(oext): fvwrite.h
|
||||
|
@ -257,6 +262,7 @@ $(lpfx)fwalk.$(oext): local.h
|
|||
$(lpfx)fwrite.$(oext): local.h fvwrite.h
|
||||
$(lpfx)iscanf.$(oext): local.h
|
||||
$(lpfx)makebuf.$(oext): local.h
|
||||
$(lpfx)open_memstream.$(oext): local.h
|
||||
$(lpfx)puts.$(oext): fvwrite.h
|
||||
$(lpfx)refill.$(oext): local.h
|
||||
$(lpfx)scanf.$(oext): local.h
|
||||
|
|
|
@ -110,8 +110,10 @@ am__objects_1 = lib_a-clearerr.$(OBJEXT) lib_a-fclose.$(OBJEXT) \
|
|||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-asnprintf.$(OBJEXT) \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-diprintf.$(OBJEXT) \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-dprintf.$(OBJEXT) \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-fmemopen.$(OBJEXT) \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-fopencookie.$(OBJEXT) \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-funopen.$(OBJEXT) \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-open_memstream.$(OBJEXT) \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-vasniprintf.$(OBJEXT) \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ lib_a-vasnprintf.$(OBJEXT)
|
||||
@USE_LIBTOOL_FALSE@am_lib_a_OBJECTS = $(am__objects_1) \
|
||||
|
@ -141,8 +143,10 @@ am__objects_4 = clearerr.lo fclose.lo fdopen.lo feof.lo ferror.lo \
|
|||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ asnprintf.lo \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ diprintf.lo \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ dprintf.lo \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ fmemopen.lo \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ fopencookie.lo \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ funopen.lo \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ open_memstream.lo \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ vasniprintf.lo \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ vasnprintf.lo
|
||||
@USE_LIBTOOL_TRUE@am_libstdio_la_OBJECTS = $(am__objects_4) \
|
||||
|
@ -423,8 +427,10 @@ GENERAL_SOURCES = \
|
|||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ asnprintf.c \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ diprintf.c \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ dprintf.c \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ fmemopen.c \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ fopencookie.c \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ funopen.c \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ open_memstream.c \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ vasniprintf.c \
|
||||
@ELIX_LEVEL_1_FALSE@@ELIX_LEVEL_2_FALSE@@ELIX_LEVEL_3_FALSE@ vasnprintf.c
|
||||
|
||||
|
@ -463,6 +469,7 @@ CHEWOUT_FILES = \
|
|||
fgetpos.def \
|
||||
fgets.def \
|
||||
fileno.def \
|
||||
fmemopen.def \
|
||||
fopen.def \
|
||||
fopencookie.def \
|
||||
fputc.def \
|
||||
|
@ -483,6 +490,7 @@ CHEWOUT_FILES = \
|
|||
gets.def \
|
||||
getw.def \
|
||||
mktemp.def \
|
||||
open_memstream.def \
|
||||
perror.def \
|
||||
putc.def \
|
||||
putc_u.def \
|
||||
|
@ -1138,6 +1146,12 @@ lib_a-dprintf.o: dprintf.c
|
|||
lib_a-dprintf.obj: dprintf.c
|
||||
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-dprintf.obj `if test -f 'dprintf.c'; then $(CYGPATH_W) 'dprintf.c'; else $(CYGPATH_W) '$(srcdir)/dprintf.c'; fi`
|
||||
|
||||
lib_a-fmemopen.o: fmemopen.c
|
||||
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-fmemopen.o `test -f 'fmemopen.c' || echo '$(srcdir)/'`fmemopen.c
|
||||
|
||||
lib_a-fmemopen.obj: fmemopen.c
|
||||
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-fmemopen.obj `if test -f 'fmemopen.c'; then $(CYGPATH_W) 'fmemopen.c'; else $(CYGPATH_W) '$(srcdir)/fmemopen.c'; fi`
|
||||
|
||||
lib_a-fopencookie.o: fopencookie.c
|
||||
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-fopencookie.o `test -f 'fopencookie.c' || echo '$(srcdir)/'`fopencookie.c
|
||||
|
||||
|
@ -1150,6 +1164,12 @@ lib_a-funopen.o: funopen.c
|
|||
lib_a-funopen.obj: funopen.c
|
||||
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-funopen.obj `if test -f 'funopen.c'; then $(CYGPATH_W) 'funopen.c'; else $(CYGPATH_W) '$(srcdir)/funopen.c'; fi`
|
||||
|
||||
lib_a-open_memstream.o: open_memstream.c
|
||||
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-open_memstream.o `test -f 'open_memstream.c' || echo '$(srcdir)/'`open_memstream.c
|
||||
|
||||
lib_a-open_memstream.obj: open_memstream.c
|
||||
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-open_memstream.obj `if test -f 'open_memstream.c'; then $(CYGPATH_W) 'open_memstream.c'; else $(CYGPATH_W) '$(srcdir)/open_memstream.c'; fi`
|
||||
|
||||
lib_a-vasniprintf.o: vasniprintf.c
|
||||
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-vasniprintf.o `test -f 'vasniprintf.c' || echo '$(srcdir)/'`vasniprintf.c
|
||||
|
||||
|
@ -1342,6 +1362,7 @@ $(lpfx)fclose.$(oext): local.h
|
|||
$(lpfx)fdopen.$(oext): local.h
|
||||
$(lpfx)fflush.$(oext): local.h
|
||||
$(lpfx)findfp.$(oext): local.h
|
||||
$(lpfx)fmemopen.$(oext): local.h
|
||||
$(lpfx)fopen.$(oext): local.h
|
||||
$(lpfx)fopencookie.$(oext): local.h
|
||||
$(lpfx)fputs.$(oext): fvwrite.h
|
||||
|
@ -1355,6 +1376,7 @@ $(lpfx)fwalk.$(oext): local.h
|
|||
$(lpfx)fwrite.$(oext): local.h fvwrite.h
|
||||
$(lpfx)iscanf.$(oext): local.h
|
||||
$(lpfx)makebuf.$(oext): local.h
|
||||
$(lpfx)open_memstream.$(oext): local.h
|
||||
$(lpfx)puts.$(oext): fvwrite.h
|
||||
$(lpfx)refill.$(oext): local.h
|
||||
$(lpfx)scanf.$(oext): local.h
|
||||
|
|
|
@ -0,0 +1,371 @@
|
|||
/* Copyright (C) 2007 Eric Blake
|
||||
* Permission to use, copy, modify, and distribute this software
|
||||
* is freely granted, provided that this notice is preserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
FUNCTION
|
||||
<<fmemopen>>---open a stream around a fixed-length string
|
||||
|
||||
INDEX
|
||||
fmemopen
|
||||
|
||||
ANSI_SYNOPSIS
|
||||
#include <stdio.h>
|
||||
FILE *fmemopen(void *restrict <[buf]>, size_t <[size]>,
|
||||
const char *restrict <[mode]>);
|
||||
|
||||
DESCRIPTION
|
||||
<<fmemopen>> creates a seekable <<FILE>> stream that wraps a
|
||||
fixed-length buffer of <[size]> bytes starting at <[buf]>. The stream
|
||||
is opened with <[mode]> treated as in <<fopen>>, where append mode
|
||||
starts writing at the first NUL byte. If <[buf]> is NULL, then
|
||||
<[size]> bytes are automatically provided as if by <<malloc>>, with
|
||||
the initial size of 0, and <[mode]> must contain <<+>> so that data
|
||||
can be read after it is written.
|
||||
|
||||
The stream maintains a current position, which moves according to
|
||||
bytes read or written, and which can be one past the end of the array.
|
||||
The stream also maintains a current file size, which is never greater
|
||||
than <[size]>. If <[mode]> starts with <<r>>, the position starts at
|
||||
<<0>>, and file size starts at <[size]> if <[buf]> was provided. If
|
||||
<[mode]> starts with <<w>>, the position and file size start at <<0>>,
|
||||
and if <[buf]> was provided, the first byte is set to NUL. If
|
||||
<[mode]> starts with <<a>>, the position and file size start at the
|
||||
location of the first NUL byte, or else <[size]> if <[buf]> was
|
||||
provided.
|
||||
|
||||
When reading, NUL bytes have no significance, and reads cannot exceed
|
||||
the current file size. When writing, the file size can increase up to
|
||||
<[size]> as needed, and NUL bytes may be embedded in the stream (see
|
||||
<<open_memstream>> for an alternative that automatically enlarges the
|
||||
buffer). When the stream is flushed or closed after a write that
|
||||
changed the file size, a NUL byte is written at the current position
|
||||
if there is still room; if the stream is not also open for reading, a
|
||||
NUL byte is additionally written at the last byte of <[buf]> when the
|
||||
stream has exceeded <[size]>, so that a write-only <[buf]> is always
|
||||
NUL-terminated when the stream is flushed or closed (and the initial
|
||||
<[size]> should take this into account). It is not possible to seek
|
||||
outside the bounds of <[size]>. A NUL byte written during a flush is
|
||||
restored to its previous value when seeking elsewhere in the string.
|
||||
|
||||
RETURNS
|
||||
The return value is an open FILE pointer on success. On error,
|
||||
<<NULL>> is returned, and <<errno>> will be set to EINVAL if <[size]>
|
||||
is zero or <[mode]> is invalid, ENOMEM if <[buf]> was NULL and memory
|
||||
could not be allocated, or EMFILE if too many streams are already
|
||||
open.
|
||||
|
||||
PORTABILITY
|
||||
This function is being added to POSIX 200x, but is not in POSIX 2001.
|
||||
|
||||
Supporting OS subroutines required: <<sbrk>>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/lock.h>
|
||||
#include "local.h"
|
||||
|
||||
/* Describe details of an open memstream. */
|
||||
typedef struct fmemcookie {
|
||||
void *storage; /* storage to free on close */
|
||||
char *buf; /* buffer start */
|
||||
size_t pos; /* current position */
|
||||
size_t eof; /* current file size */
|
||||
size_t max; /* maximum file size */
|
||||
char append; /* nonzero if appending */
|
||||
char writeonly; /* 1 if write-only */
|
||||
char saved; /* saved character that lived at pos before write-only NUL */
|
||||
} fmemcookie;
|
||||
|
||||
/* Read up to non-zero N bytes into BUF from stream described by
|
||||
COOKIE; return number of bytes read (0 on EOF). */
|
||||
static _READ_WRITE_RETURN_TYPE
|
||||
_DEFUN(fmemreader, (ptr, cookie, buf, n),
|
||||
struct _reent *ptr _AND
|
||||
void *cookie _AND
|
||||
char *buf _AND
|
||||
int n)
|
||||
{
|
||||
fmemcookie *c = (fmemcookie *) cookie;
|
||||
/* Can't read beyond current size, but EOF condition is not an error. */
|
||||
if (c->pos > c->eof)
|
||||
return 0;
|
||||
if (n >= c->eof - c->pos)
|
||||
n = c->eof - c->pos;
|
||||
memcpy (buf, c->buf + c->pos, n);
|
||||
c->pos += n;
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Write up to non-zero N bytes of BUF into the stream described by COOKIE,
|
||||
returning the number of bytes written or EOF on failure. */
|
||||
static _READ_WRITE_RETURN_TYPE
|
||||
_DEFUN(fmemwriter, (ptr, cookie, buf, n),
|
||||
struct _reent *ptr _AND
|
||||
void *cookie _AND
|
||||
const char *buf _AND
|
||||
int n)
|
||||
{
|
||||
fmemcookie *c = (fmemcookie *) cookie;
|
||||
int adjust = 0; /* true if at EOF, but still need to write NUL. */
|
||||
|
||||
/* Append always seeks to eof; otherwise, if we have previously done
|
||||
a seek beyond eof, ensure all intermediate bytes are NUL. */
|
||||
if (c->append)
|
||||
c->pos = c->eof;
|
||||
else if (c->pos > c->eof)
|
||||
memset (c->buf + c->eof, '\0', c->pos - c->eof);
|
||||
/* Do not write beyond EOF; saving room for NUL on write-only stream. */
|
||||
if (c->pos + n > c->max - c->writeonly)
|
||||
{
|
||||
adjust = c->writeonly;
|
||||
n = c->max - c->pos;
|
||||
}
|
||||
/* Now n is the number of bytes being modified, and adjust is 1 if
|
||||
the last byte is NUL instead of from buf. Write a NUL if
|
||||
write-only; or if read-write, eof changed, and there is still
|
||||
room. When we are within the file contents, remember what we
|
||||
overwrite so we can restore it if we seek elsewhere later. */
|
||||
if (c->pos + n > c->eof)
|
||||
{
|
||||
c->eof = c->pos + n;
|
||||
if (c->eof - adjust < c->max)
|
||||
c->saved = c->buf[c->eof - adjust] = '\0';
|
||||
}
|
||||
else if (c->writeonly)
|
||||
{
|
||||
if (n)
|
||||
{
|
||||
c->saved = c->buf[c->pos + n - adjust];
|
||||
c->buf[c->pos + n - adjust] = '\0';
|
||||
}
|
||||
else
|
||||
adjust = 0;
|
||||
}
|
||||
c->pos += n;
|
||||
if (n - adjust)
|
||||
memcpy (c->buf + c->pos - n, buf, n - adjust);
|
||||
else
|
||||
{
|
||||
ptr->_errno = ENOSPC;
|
||||
return EOF;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Seek to position POS relative to WHENCE within stream described by
|
||||
COOKIE; return resulting position or fail with EOF. */
|
||||
static _fpos_t
|
||||
_DEFUN(fmemseeker, (ptr, cookie, pos, whence),
|
||||
struct _reent *ptr _AND
|
||||
void *cookie _AND
|
||||
_fpos_t pos _AND
|
||||
int whence)
|
||||
{
|
||||
fmemcookie *c = (fmemcookie *) cookie;
|
||||
#ifndef __LARGE64_FILES
|
||||
off_t offset = (off_t) pos;
|
||||
#else /* __LARGE64_FILES */
|
||||
_off64_t offset = (_off64_t) pos;
|
||||
#endif /* __LARGE64_FILES */
|
||||
|
||||
if (whence == SEEK_CUR)
|
||||
offset += c->pos;
|
||||
else if (whence == SEEK_END)
|
||||
offset += c->eof;
|
||||
if (offset < 0)
|
||||
{
|
||||
ptr->_errno = EINVAL;
|
||||
offset = -1;
|
||||
}
|
||||
else if (offset > c->max)
|
||||
{
|
||||
ptr->_errno = ENOSPC;
|
||||
offset = -1;
|
||||
}
|
||||
#ifdef __LARGE64_FILES
|
||||
else if ((_fpos_t) offset != offset)
|
||||
{
|
||||
ptr->_errno = EOVERFLOW;
|
||||
offset = -1;
|
||||
}
|
||||
#endif /* __LARGE64_FILES */
|
||||
else
|
||||
{
|
||||
if (c->writeonly && c->pos < c->eof)
|
||||
{
|
||||
c->buf[c->pos] = c->saved;
|
||||
c->saved = '\0';
|
||||
}
|
||||
c->pos = offset;
|
||||
if (c->writeonly && c->pos < c->eof)
|
||||
{
|
||||
c->saved = c->buf[c->pos];
|
||||
c->buf[c->pos] = '\0';
|
||||
}
|
||||
}
|
||||
return (_fpos_t) offset;
|
||||
}
|
||||
|
||||
/* Seek to position POS relative to WHENCE within stream described by
|
||||
COOKIE; return resulting position or fail with EOF. */
|
||||
#ifdef __LARGE64_FILES
|
||||
static _fpos64_t
|
||||
_DEFUN(fmemseeker64, (ptr, cookie, pos, whence),
|
||||
struct _reent *ptr _AND
|
||||
void *cookie _AND
|
||||
_fpos64_t pos _AND
|
||||
int whence)
|
||||
{
|
||||
_off64_t offset = (_off64_t) pos;
|
||||
fmemcookie *c = (fmemcookie *) cookie;
|
||||
if (whence == SEEK_CUR)
|
||||
offset += c->pos;
|
||||
else if (whence == SEEK_END)
|
||||
offset += c->eof;
|
||||
if (offset < 0)
|
||||
{
|
||||
ptr->_errno = EINVAL;
|
||||
offset = -1;
|
||||
}
|
||||
else if (offset > c->max)
|
||||
{
|
||||
ptr->_errno = ENOSPC;
|
||||
offset = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c->writeonly && c->pos < c->eof)
|
||||
{
|
||||
c->buf[c->pos] = c->saved;
|
||||
c->saved = '\0';
|
||||
}
|
||||
c->pos = offset;
|
||||
if (c->writeonly && c->pos < c->eof)
|
||||
{
|
||||
c->saved = c->buf[c->pos];
|
||||
c->buf[c->pos] = '\0';
|
||||
}
|
||||
}
|
||||
return (_fpos64_t) offset;
|
||||
}
|
||||
#endif /* __LARGE64_FILES */
|
||||
|
||||
/* Reclaim resources used by stream described by COOKIE. */
|
||||
static int
|
||||
_DEFUN(fmemcloser, (ptr, cookie),
|
||||
struct _reent *ptr _AND
|
||||
void *cookie)
|
||||
{
|
||||
fmemcookie *c = (fmemcookie *) cookie;
|
||||
_free_r (ptr, c->storage);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Open a memstream around buffer BUF of SIZE bytes, using MODE.
|
||||
Return the new stream, or fail with NULL. */
|
||||
FILE *
|
||||
_DEFUN(_fmemopen_r, (ptr, buf, size, mode),
|
||||
struct _reent *ptr _AND
|
||||
void *buf _AND
|
||||
size_t size _AND
|
||||
const char *mode)
|
||||
{
|
||||
FILE *fp;
|
||||
fmemcookie *c;
|
||||
int flags;
|
||||
int dummy;
|
||||
|
||||
if ((flags = __sflags (ptr, mode, &dummy)) == 0)
|
||||
return NULL;
|
||||
if (!size || !(buf || flags & __SAPP))
|
||||
{
|
||||
ptr->_errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if ((fp = __sfp (ptr)) == NULL)
|
||||
return NULL;
|
||||
if ((c = (fmemcookie *) _malloc_r (ptr, sizeof *c + (buf ? 0 : size)))
|
||||
== NULL)
|
||||
{
|
||||
__sfp_lock_acquire ();
|
||||
fp->_flags = 0; /* release */
|
||||
#ifndef __SINGLE_THREAD__
|
||||
__lock_close_recursive (fp->_lock);
|
||||
#endif
|
||||
__sfp_lock_release ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
c->storage = c;
|
||||
c->max = size;
|
||||
/* 9 modes to worry about. */
|
||||
/* w/a, buf or no buf: Guarantee a NUL after any file writes. */
|
||||
c->writeonly = (flags & __SWR) != 0;
|
||||
c->saved = '\0';
|
||||
if (!buf)
|
||||
{
|
||||
/* r+/w+/a+, and no buf: file starts empty. */
|
||||
c->buf = (char *) (c + 1);
|
||||
*(char *) buf = '\0';
|
||||
c->pos = c->eof = 0;
|
||||
c->append = (flags & __SAPP) != 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
c->buf = (char *) buf;
|
||||
switch (*mode)
|
||||
{
|
||||
case 'a':
|
||||
/* a/a+ and buf: position and size at first NUL. */
|
||||
buf = memchr (c->buf, '\0', size);
|
||||
c->eof = c->pos = buf ? (char *) buf - c->buf : size;
|
||||
if (!buf && c->writeonly)
|
||||
/* a: guarantee a NUL within size even if no writes. */
|
||||
c->buf[size - 1] = '\0';
|
||||
c->append = 1;
|
||||
break;
|
||||
case 'r':
|
||||
/* r/r+ and buf: read at beginning, full size available. */
|
||||
c->pos = c->append = 0;
|
||||
c->eof = size;
|
||||
break;
|
||||
case 'w':
|
||||
/* w/w+ and buf: write at beginning, truncate to empty. */
|
||||
c->pos = c->append = c->eof = 0;
|
||||
*c->buf = '\0';
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
_flockfile (fp);
|
||||
fp->_file = -1;
|
||||
fp->_flags = flags;
|
||||
fp->_cookie = c;
|
||||
fp->_read = flags & (__SRD | __SRW) ? fmemreader : NULL;
|
||||
fp->_write = flags & (__SWR | __SRW) ? fmemwriter : NULL;
|
||||
fp->_seek = fmemseeker;
|
||||
#ifdef __LARGE64_FILES
|
||||
fp->_seek64 = fmemseeker64;
|
||||
fp->_flags |= __SL64;
|
||||
#endif
|
||||
fp->_close = fmemcloser;
|
||||
_funlockfile (fp);
|
||||
return fp;
|
||||
}
|
||||
|
||||
#ifndef _REENT_ONLY
|
||||
FILE *
|
||||
_DEFUN(fmemopen, (buf, size, mode),
|
||||
void *buf _AND
|
||||
size_t size _AND
|
||||
const char *mode)
|
||||
{
|
||||
return _fmemopen_r (_REENT, buf, size, mode);
|
||||
}
|
||||
#endif /* !_REENT_ONLY */
|
|
@ -122,9 +122,9 @@ _DEFUN(fcwriter, (ptr, cookie, buf, n),
|
|||
if (c->fp->_flags & __SAPP && c->fp->_seek)
|
||||
{
|
||||
#ifdef __LARGE64_FILES
|
||||
c->fp->_seek64 (ptr, c->fp->_cookie, 0, SEEK_END);
|
||||
c->fp->_seek64 (ptr, cookie, 0, SEEK_END);
|
||||
#else
|
||||
c->fp->_seek (ptr, c->fp->_cookie, 0, SEEK_END);
|
||||
c->fp->_seek (ptr, cookie, 0, SEEK_END);
|
||||
#endif
|
||||
}
|
||||
errno = 0;
|
||||
|
@ -134,7 +134,7 @@ _DEFUN(fcwriter, (ptr, cookie, buf, n),
|
|||
}
|
||||
|
||||
static _fpos_t
|
||||
_DEFUN(fcseeker, (ptr, cookie, off, whence),
|
||||
_DEFUN(fcseeker, (ptr, cookie, pos, whence),
|
||||
struct _reent *ptr _AND
|
||||
void *cookie _AND
|
||||
_fpos_t pos _AND
|
||||
|
@ -162,7 +162,7 @@ _DEFUN(fcseeker, (ptr, cookie, off, whence),
|
|||
|
||||
#ifdef __LARGE64_FILES
|
||||
static _fpos64_t
|
||||
_DEFUN(fcseeker64, (ptr, cookie, off, whence),
|
||||
_DEFUN(fcseeker64, (ptr, cookie, pos, whence),
|
||||
struct _reent *ptr _AND
|
||||
void *cookie _AND
|
||||
_fpos64_t pos _AND
|
||||
|
|
|
@ -0,0 +1,330 @@
|
|||
/* Copyright (C) 2007 Eric Blake
|
||||
* Permission to use, copy, modify, and distribute this software
|
||||
* is freely granted, provided that this notice is preserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
FUNCTION
|
||||
<<open_memstream>>---open a write stream around an arbitrary-length string
|
||||
|
||||
INDEX
|
||||
open_memstream
|
||||
|
||||
ANSI_SYNOPSIS
|
||||
#include <stdio.h>
|
||||
FILE *open_memstream(char **restrict <[buf]>,
|
||||
size_t *restrict <[size]>);
|
||||
|
||||
DESCRIPTION
|
||||
<<open_memstream>> creates a seekable <<FILE>> stream that wraps an
|
||||
arbitrary-length buffer, created as if by <<malloc>>. The current
|
||||
contents of *<[buf]> are ignored; this implementation uses *<[size]>
|
||||
as a hint of the maximum size expected, but does not fail if the hint
|
||||
was wrong. The parameters <[buf]> and <[size]> are later stored
|
||||
through following any call to <<fflush>> or <<fclose>>, set to the
|
||||
current address and usable size of the allocated string; although
|
||||
after fflush, the pointer is only valid until another stream operation
|
||||
that results in a write. Behavior is undefined if the user alters
|
||||
either *<[buf]> or *<[size]> prior to <<fclose>>.
|
||||
|
||||
The stream is write-only, since the user can directly read *<[buf]>
|
||||
after a flush; see <<fmemopen>> for a way to wrap a string with a
|
||||
readable stream. The user is responsible for calling <<free>> on
|
||||
the final *<[buf]> after <<fclose>>.
|
||||
|
||||
Any time the stream is flushed, a NUL byte is written at the current
|
||||
position (but is not counted in the buffer length), so that the string
|
||||
is always NUL-terminated after at most *<[size]> bytes. However, data
|
||||
previously written beyond the current stream offset is not lost, and
|
||||
the NUL byte written during a flush is restored to its previous value
|
||||
when seeking elsewhere in the string.
|
||||
|
||||
RETURNS
|
||||
The return value is an open FILE pointer on success. On error,
|
||||
<<NULL>> is returned, and <<errno>> will be set to EINVAL if <[buf]>
|
||||
or <[size]> is NULL, ENOMEM if memory could not be allocated, or
|
||||
EMFILE if too many streams are already open.
|
||||
|
||||
PORTABILITY
|
||||
This function is being added to POSIX 200x, but is not in POSIX 2001.
|
||||
|
||||
Supporting OS subroutines required: <<sbrk>>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/lock.h>
|
||||
#include "local.h"
|
||||
|
||||
#ifndef __LARGE64_FILES
|
||||
# define OFF_T off_t
|
||||
#else
|
||||
# define OFF_T _off64_t
|
||||
#endif
|
||||
|
||||
/* Describe details of an open memstream. */
|
||||
typedef struct memstream {
|
||||
void *storage; /* storage to free on close */
|
||||
char **pbuf; /* pointer to the current buffer */
|
||||
size_t *psize; /* pointer to the current size, smaller of pos or eof */
|
||||
size_t pos; /* current position */
|
||||
size_t eof; /* current file size */
|
||||
size_t max; /* current malloc buffer size, always > eof */
|
||||
char saved; /* saved character that lived at *psize before NUL */
|
||||
} memstream;
|
||||
|
||||
/* Write up to non-zero N bytes of BUF into the stream described by COOKIE,
|
||||
returning the number of bytes written or EOF on failure. */
|
||||
static _READ_WRITE_RETURN_TYPE
|
||||
_DEFUN(memwriter, (ptr, cookie, buf, n),
|
||||
struct _reent *ptr _AND
|
||||
void *cookie _AND
|
||||
const char *buf _AND
|
||||
int n)
|
||||
{
|
||||
memstream *c = (memstream *) cookie;
|
||||
char *cbuf = *c->pbuf;
|
||||
|
||||
/* size_t is unsigned, but off_t is signed. Don't let stream get so
|
||||
big that user cannot do ftello. */
|
||||
if (sizeof (OFF_T) == sizeof (size_t) && (ssize_t) (c->pos + n) < 0)
|
||||
{
|
||||
ptr->_errno = EFBIG;
|
||||
return EOF;
|
||||
}
|
||||
/* Grow the buffer, if necessary. Choose a geometric growth factor
|
||||
to avoid quadratic realloc behavior, but use a rate less than
|
||||
(1+sqrt(5))/2 to accomodate malloc overhead. Overallocate, so
|
||||
that we can add a trailing \0 without reallocating. The new
|
||||
allocation should thus be max(prev_size*1.5, c->pos+n+1). */
|
||||
if (c->pos + n >= c->max)
|
||||
{
|
||||
size_t newsize = c->max * 3 / 2;
|
||||
if (newsize < c->pos + n + 1)
|
||||
newsize = c->pos + n + 1;
|
||||
cbuf = _realloc_r (ptr, cbuf, newsize);
|
||||
if (! cbuf)
|
||||
return EOF; /* errno already set to ENOMEM */
|
||||
*c->pbuf = cbuf;
|
||||
c->max = newsize;
|
||||
}
|
||||
/* If we have previously done a seek beyond eof, ensure all
|
||||
intermediate bytes are NUL. */
|
||||
if (c->pos > c->eof)
|
||||
memset (cbuf + c->eof, '\0', c->pos - c->eof);
|
||||
memcpy (cbuf + c->pos, buf, n);
|
||||
c->pos += n;
|
||||
/* If the user has previously written further, remember what the
|
||||
trailing NUL is overwriting. Otherwise, extend the stream. */
|
||||
if (c->pos > c->eof)
|
||||
c->eof = c->pos;
|
||||
else
|
||||
c->saved = cbuf[c->pos];
|
||||
cbuf[c->pos] = '\0';
|
||||
*c->psize = c->pos;
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Seek to position POS relative to WHENCE within stream described by
|
||||
COOKIE; return resulting position or fail with EOF. */
|
||||
static _fpos_t
|
||||
_DEFUN(memseeker, (ptr, cookie, pos, whence),
|
||||
struct _reent *ptr _AND
|
||||
void *cookie _AND
|
||||
_fpos_t pos _AND
|
||||
int whence)
|
||||
{
|
||||
memstream *c = (memstream *) cookie;
|
||||
OFF_T offset = (OFF_T) pos;
|
||||
|
||||
if (whence == SEEK_CUR)
|
||||
offset += c->pos;
|
||||
else if (whence == SEEK_END)
|
||||
offset += c->eof;
|
||||
if (offset < 0)
|
||||
{
|
||||
ptr->_errno = EINVAL;
|
||||
offset = -1;
|
||||
}
|
||||
else if ((size_t) offset != offset)
|
||||
{
|
||||
ptr->_errno = ENOSPC;
|
||||
offset = -1;
|
||||
}
|
||||
#ifdef __LARGE64_FILES
|
||||
else if ((_fpos_t) offset != offset)
|
||||
{
|
||||
ptr->_errno = EOVERFLOW;
|
||||
offset = -1;
|
||||
}
|
||||
#endif /* __LARGE64_FILES */
|
||||
else
|
||||
{
|
||||
if (c->pos < c->eof)
|
||||
{
|
||||
(*c->pbuf)[c->pos] = c->saved;
|
||||
c->saved = '\0';
|
||||
}
|
||||
c->pos = offset;
|
||||
if (c->pos < c->eof)
|
||||
{
|
||||
c->saved = (*c->pbuf)[c->pos];
|
||||
(*c->pbuf)[c->pos] = '\0';
|
||||
*c->psize = c->pos;
|
||||
}
|
||||
else
|
||||
*c->psize = c->eof;
|
||||
}
|
||||
return (_fpos_t) offset;
|
||||
}
|
||||
|
||||
/* Seek to position POS relative to WHENCE within stream described by
|
||||
COOKIE; return resulting position or fail with EOF. */
|
||||
#ifdef __LARGE64_FILES
|
||||
static _fpos64_t
|
||||
_DEFUN(memseeker64, (ptr, cookie, pos, whence),
|
||||
struct _reent *ptr _AND
|
||||
void *cookie _AND
|
||||
_fpos64_t pos _AND
|
||||
int whence)
|
||||
{
|
||||
_off64_t offset = (_off64_t) pos;
|
||||
memstream *c = (memstream *) cookie;
|
||||
|
||||
if (whence == SEEK_CUR)
|
||||
offset += c->pos;
|
||||
else if (whence == SEEK_END)
|
||||
offset += c->eof;
|
||||
if (offset < 0)
|
||||
{
|
||||
ptr->_errno = EINVAL;
|
||||
offset = -1;
|
||||
}
|
||||
else if ((size_t) offset != offset)
|
||||
{
|
||||
ptr->_errno = ENOSPC;
|
||||
offset = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c->pos < c->eof)
|
||||
{
|
||||
(*c->pbuf)[c->pos] = c->saved;
|
||||
c->saved = '\0';
|
||||
}
|
||||
c->pos = offset;
|
||||
if (c->pos < c->eof)
|
||||
{
|
||||
c->saved = (*c->pbuf)[c->pos];
|
||||
(*c->pbuf)[c->pos] = '\0';
|
||||
*c->psize = c->pos;
|
||||
}
|
||||
else
|
||||
*c->psize = c->eof;
|
||||
}
|
||||
return (_fpos64_t) offset;
|
||||
}
|
||||
#endif /* __LARGE64_FILES */
|
||||
|
||||
/* Reclaim resources used by stream described by COOKIE. */
|
||||
static int
|
||||
_DEFUN(memcloser, (ptr, cookie),
|
||||
struct _reent *ptr _AND
|
||||
void *cookie)
|
||||
{
|
||||
memstream *c = (memstream *) cookie;
|
||||
char *buf;
|
||||
|
||||
/* Be nice and try to reduce any unused memory. */
|
||||
buf = _realloc_r (ptr, *c->pbuf, *c->psize + 1);
|
||||
if (buf)
|
||||
*c->pbuf = buf;
|
||||
_free_r (ptr, c->storage);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Open a memstream that tracks a dynamic buffer in BUF and SIZE.
|
||||
Return the new stream, or fail with NULL. */
|
||||
FILE *
|
||||
_DEFUN(_open_memstream_r, (ptr, buf, size),
|
||||
struct _reent *ptr _AND
|
||||
char **buf _AND
|
||||
size_t *size)
|
||||
{
|
||||
FILE *fp;
|
||||
memstream *c;
|
||||
int flags;
|
||||
|
||||
if (!buf || !size)
|
||||
{
|
||||
ptr->_errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if ((fp = __sfp (ptr)) == NULL)
|
||||
return NULL;
|
||||
if ((c = (memstream *) _malloc_r (ptr, sizeof *c)) == NULL)
|
||||
{
|
||||
__sfp_lock_acquire ();
|
||||
fp->_flags = 0; /* release */
|
||||
#ifndef __SINGLE_THREAD__
|
||||
__lock_close_recursive (fp->_lock);
|
||||
#endif
|
||||
__sfp_lock_release ();
|
||||
return NULL;
|
||||
}
|
||||
/* Use *size as a hint for initial sizing, but bound the initial
|
||||
malloc between 64 bytes (same as asprintf, to avoid frequent
|
||||
mallocs on small strings) and 64k bytes (to avoid overusing the
|
||||
heap if *size was garbage). */
|
||||
c->max = *size;
|
||||
if (c->max < 64)
|
||||
c->max = 64;
|
||||
else if (c->max > 64 * 1024)
|
||||
c->max = 64 * 1024;
|
||||
*size = 0;
|
||||
*buf = _malloc_r (ptr, c->max);
|
||||
if (!*buf)
|
||||
{
|
||||
__sfp_lock_acquire ();
|
||||
fp->_flags = 0; /* release */
|
||||
#ifndef __SINGLE_THREAD__
|
||||
__lock_close_recursive (fp->_lock);
|
||||
#endif
|
||||
__sfp_lock_release ();
|
||||
_free_r (ptr, c);
|
||||
return NULL;
|
||||
}
|
||||
**buf = '\0';
|
||||
|
||||
c->storage = c;
|
||||
c->pbuf = buf;
|
||||
c->psize = size;
|
||||
c->eof = 0;
|
||||
c->saved = '\0';
|
||||
|
||||
_flockfile (fp);
|
||||
fp->_file = -1;
|
||||
fp->_flags = __SWR;
|
||||
fp->_cookie = c;
|
||||
fp->_read = NULL;
|
||||
fp->_write = memwriter;
|
||||
fp->_seek = memseeker;
|
||||
#ifdef __LARGE64_FILES
|
||||
fp->_seek64 = memseeker64;
|
||||
fp->_flags |= __SL64;
|
||||
#endif
|
||||
fp->_close = memcloser;
|
||||
_funlockfile (fp);
|
||||
return fp;
|
||||
}
|
||||
|
||||
#ifndef _REENT_ONLY
|
||||
FILE *
|
||||
_DEFUN(open_memstream, (buf, size),
|
||||
char **buf _AND
|
||||
size_t *size)
|
||||
{
|
||||
return _open_memstream_r (_REENT, buf, size);
|
||||
}
|
||||
#endif /* !_REENT_ONLY */
|
|
@ -37,6 +37,7 @@ structure.
|
|||
* fgetpos:: Record position in a stream or file
|
||||
* fgets:: Get character string from a file or stream
|
||||
* fileno:: Get file descriptor associated with stream
|
||||
* fmemopen:: Open a stream around a fixed-length buffer
|
||||
* fopen:: Open a file
|
||||
* fopencookie:: Open a stream with custom callbacks
|
||||
* fputc:: Write a character on a stream or file
|
||||
|
@ -57,6 +58,7 @@ structure.
|
|||
* gets:: Get character string from standard input (obsolete)
|
||||
* getw:: Get a word (int) from a file or stream
|
||||
* mktemp:: Generate unused file name
|
||||
* open_memstream:: Open a write stream around an arbitrary-length buffer
|
||||
* perror:: Print an error message on standard error
|
||||
* putc:: Write a character on a stream or file (macro)
|
||||
* putc_unlocked:: Write a character on a stream or file (macro)
|
||||
|
@ -123,6 +125,9 @@ structure.
|
|||
@page
|
||||
@include stdio/fileno.def
|
||||
|
||||
@page
|
||||
@include stdio/fmemopen.def
|
||||
|
||||
@page
|
||||
@include stdio/fopen.def
|
||||
|
||||
|
@ -183,6 +188,9 @@ structure.
|
|||
@page
|
||||
@include stdio/mktemp.def
|
||||
|
||||
@page
|
||||
@include stdio/open_memstream.def
|
||||
|
||||
@page
|
||||
@include stdio/perror.def
|
||||
|
||||
|
|
Loading…
Reference in New Issue