summaryrefslogtreecommitdiffstats
path: root/lib/libc/stdio/freopen.c
diff options
context:
space:
mode:
authortjr <tjr@FreeBSD.org>2003-01-26 10:01:59 +0000
committertjr <tjr@FreeBSD.org>2003-01-26 10:01:59 +0000
commit680c2aca55d1bb75a321735e31280c7281782f2c (patch)
tree563ae2b8d00db2609264cbf43f9b0dd609f80880 /lib/libc/stdio/freopen.c
parent2a088a14174963b45600a538364fa67d69858c11 (diff)
downloadFreeBSD-src-680c2aca55d1bb75a321735e31280c7281782f2c.zip
FreeBSD-src-680c2aca55d1bb75a321735e31280c7281782f2c.tar.gz
Initial implementation of the C99 feature whereby calling freopen() with
a NULL filename argument allows a stream's mode to be changed. At the moment it just recycles the old file descriptor instead of storing the filename somewhere and using that to reopen the file, as the standard seems to require. Strictly conforming C99 applications probably can't tell the difference but POSIX ones can. PR: 46791
Diffstat (limited to 'lib/libc/stdio/freopen.c')
-rw-r--r--lib/libc/stdio/freopen.c59
1 files changed, 58 insertions, 1 deletions
diff --git a/lib/libc/stdio/freopen.c b/lib/libc/stdio/freopen.c
index a22dedd..66794dd 100644
--- a/lib/libc/stdio/freopen.c
+++ b/lib/libc/stdio/freopen.c
@@ -64,7 +64,7 @@ freopen(file, mode, fp)
FILE *fp;
{
int f;
- int flags, isopen, oflags, sverrno, wantfd;
+ int dflags, flags, isopen, oflags, sverrno, wantfd;
if ((flags = __sflags(mode, &oflags)) == 0) {
(void) fclose(fp);
@@ -77,6 +77,59 @@ freopen(file, mode, fp)
__sinit();
/*
+ * If the filename is a NULL pointer, the caller is asking us to
+ * re-open the same file with a different mode. We allow this only
+ * if the modes are compatible.
+ */
+ if (file == NULL) {
+ /* See comment below regarding freopen() of closed files. */
+ if (fp->_flags == 0) {
+ FUNLOCKFILE(fp);
+ errno = EINVAL;
+ return (NULL);
+ }
+ if ((dflags = _fcntl(fp->_file, F_GETFL)) < 0) {
+ sverrno = errno;
+ fclose(fp);
+ FUNLOCKFILE(fp);
+ errno = sverrno;
+ return (NULL);
+ }
+ if ((dflags & O_ACCMODE) != O_RDWR && (dflags & O_ACCMODE) !=
+ (oflags & O_ACCMODE)) {
+ fclose(fp);
+ FUNLOCKFILE(fp);
+ errno = EINVAL;
+ return (NULL);
+ }
+ if ((oflags ^ dflags) & O_APPEND) {
+ dflags &= ~O_APPEND;
+ dflags |= oflags & O_APPEND;
+ if (_fcntl(fp->_file, F_SETFL, dflags) < 0) {
+ sverrno = errno;
+ fclose(fp);
+ FUNLOCKFILE(fp);
+ errno = sverrno;
+ return (NULL);
+ }
+ }
+ if (oflags & O_TRUNC)
+ ftruncate(fp->_file, 0);
+ if (_fseeko(fp, 0, oflags & O_APPEND ? SEEK_END : SEEK_SET,
+ 0) < 0 && errno != ESPIPE) {
+ sverrno = errno;
+ fclose(fp);
+ FUNLOCKFILE(fp);
+ errno = sverrno;
+ return (NULL);
+ }
+ f = fp->_file;
+ isopen = 0;
+ wantfd = -1;
+ goto finish;
+ }
+
+ /*
* There are actually programs that depend on being able to "freopen"
* descriptors that weren't originally open. Keep this from breaking.
* Remember whether the stream was open to begin with, and which file
@@ -112,6 +165,7 @@ freopen(file, mode, fp)
}
sverrno = errno;
+finish:
/*
* Finish closing fp. Even if the open succeeded above, we cannot
* keep fp->_base: it may be the wrong size. This loses the effect
@@ -134,6 +188,9 @@ freopen(file, mode, fp)
FREELB(fp);
fp->_lb._size = 0;
fp->_extra->orientation = 0;
+ memset(&fp->_extra->state, 0, sizeof(fp->_extra->state));
+ memset(&fp->_extra->cstate, 0, sizeof(fp->_extra->cstate));
+ fp->_extra->cstatepos = 0;
if (f < 0) { /* did not get it after all */
fp->_flags = 0; /* set it free */
OpenPOWER on IntegriCloud