xref: /csrg-svn/lib/libc/stdio/freopen.c (revision 46213)
146085Sbostic /*-
246085Sbostic  * Copyright (c) 1990 The Regents of the University of California.
346085Sbostic  * All rights reserved.
446085Sbostic  *
546085Sbostic  * This code is derived from software contributed to Berkeley by
646085Sbostic  * Chris Torek.
746085Sbostic  *
846085Sbostic  * %sccs.include.redist.c%
921407Sdist  */
1021407Sdist 
1126652Sdonn #if defined(LIBC_SCCS) && !defined(lint)
12*46213Sbostic static char sccsid[] = "@(#)freopen.c	5.4 (Berkeley) 02/01/91";
1346085Sbostic #endif /* LIBC_SCCS and not lint */
1421407Sdist 
1517951Sserge #include <sys/types.h>
1617951Sserge #include <sys/file.h>
1746085Sbostic #include <sys/stat.h>
1846085Sbostic #include <errno.h>
1917951Sserge #include <stdio.h>
2046085Sbostic #include <stdlib.h>
2146085Sbostic #include "local.h"
222008Swnj 
2346085Sbostic /*
2446085Sbostic  * Re-direct an existing, open (probably) file to some other file.
2546085Sbostic  * ANSI is written such that the original file gets closed if at
2646085Sbostic  * all possible, no matter what.
2746085Sbostic  */
282008Swnj FILE *
2946085Sbostic freopen(file, mode, fp)
3046085Sbostic 	char *file, *mode;
3146085Sbostic 	register FILE *fp;
322008Swnj {
3346085Sbostic 	register int f;
3446085Sbostic 	int flags, isopen, oflags, sverrno, wantfd;
352008Swnj 
3646085Sbostic 	if ((flags = __sflags(mode, &oflags)) == 0) {
3746085Sbostic 		(void) fclose(fp);
3846085Sbostic 		return (NULL);
3946085Sbostic 	}
403163Stoy 
4146085Sbostic 	if (!__sdidinit)
4246085Sbostic 		__sinit();
4317951Sserge 
4446085Sbostic 	/*
4546085Sbostic 	 * There are actually programs that depend on being able to "freopen"
4646085Sbostic 	 * descriptors that weren't originally open.  Keep this from breaking.
4746085Sbostic 	 * Remember whether the stream was open to begin with, and which file
4846085Sbostic 	 * descriptor (if any) was associated with it.  If it was attached to
4946085Sbostic 	 * a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin)
5046085Sbostic 	 * should work.  This is unnecessary if it was not a Unix file.
5146085Sbostic 	 */
5246085Sbostic 	if (fp->_flags == 0) {
5346085Sbostic 		fp->_flags = __SEOF;	/* hold on to it */
5446085Sbostic 		isopen = 0;
5546085Sbostic 		wantfd = -1;
5646085Sbostic 	} else {
5746085Sbostic 		/* flush the stream; ANSI doesn't require this. */
5846085Sbostic 		if (fp->_flags & __SWR)
59*46213Sbostic 			(void) __sflush(fp);
6046085Sbostic 		/* if close is NULL, closing is a no-op, hence pointless */
6146085Sbostic 		isopen = fp->_close != NULL;
6246085Sbostic 		if ((wantfd = fp->_file) < 0 && isopen) {
6346085Sbostic 			(void) (*fp->_close)(fp->_cookie);
6446085Sbostic 			isopen = 0;
6546085Sbostic 		}
6617951Sserge 	}
6717951Sserge 
6846085Sbostic 	/* Get a new descriptor to refer to the new file. */
6946085Sbostic 	f = open(file, oflags, DEFFILEMODE);
7046085Sbostic 	if (f < 0 && isopen) {
7146085Sbostic 		/* If out of fd's close the old one and try again. */
7246085Sbostic 		if (errno == ENFILE || errno == EMFILE) {
7346085Sbostic 			(void) (*fp->_close)(fp->_cookie);
7446085Sbostic 			isopen = 0;
7546085Sbostic 			f = open(file, oflags, DEFFILEMODE);
7646085Sbostic 		}
7746085Sbostic 	}
7846085Sbostic 	sverrno = errno;
7946085Sbostic 
8046085Sbostic 	/*
8146085Sbostic 	 * Finish closing fp.  Even if the open succeeded above, we cannot
8246085Sbostic 	 * keep fp->_base: it may be the wrong size.  This loses the effect
8346085Sbostic 	 * of any setbuffer calls, but stdio has always done this before.
8446085Sbostic 	 */
8546085Sbostic 	if (isopen)
8646085Sbostic 		(void) (*fp->_close)(fp->_cookie);
8746085Sbostic 	if (fp->_flags & __SMBF)
8846085Sbostic 		free((char *)fp->_bf._base);
8946085Sbostic 	fp->_w = 0;
9046085Sbostic 	fp->_r = 0;
9146085Sbostic 	fp->_p = NULL;
9246085Sbostic 	fp->_bf._base = NULL;
9346085Sbostic 	fp->_bf._size = 0;
9446085Sbostic 	fp->_lbfsize = 0;
9546085Sbostic 	if (HASUB(fp))
9646085Sbostic 		FREEUB(fp);
9746085Sbostic 	fp->_ub._size = 0;
9846085Sbostic 	if (HASLB(fp))
9946085Sbostic 		FREELB(fp);
10046085Sbostic 	fp->_lb._size = 0;
10146085Sbostic 
10246085Sbostic 	if (f < 0) {			/* did not get it after all */
10346085Sbostic 		fp->_flags = 0;		/* set it free */
10446085Sbostic 		errno = sverrno;	/* restore in case _close clobbered */
10517951Sserge 		return (NULL);
10646085Sbostic 	}
10717951Sserge 
10846085Sbostic 	/*
10946085Sbostic 	 * If reopening something that was open before on a real file, try
11046085Sbostic 	 * to maintain the descriptor.  Various C library routines (perror)
11146085Sbostic 	 * assume stderr is always fd STDERR_FILENO, even if being freopen'd.
11246085Sbostic 	 */
11346085Sbostic 	if (wantfd >= 0 && f != wantfd) {
11446085Sbostic 		if (dup2(f, wantfd) >= 0) {
11546085Sbostic 			(void) close(f);
11646085Sbostic 			f = wantfd;
11746085Sbostic 		}
11846085Sbostic 	}
11917951Sserge 
12046085Sbostic 	fp->_flags = flags;
12146085Sbostic 	fp->_file = f;
12246085Sbostic 	fp->_cookie = fp;
12346085Sbostic 	fp->_read = __sread;
12446085Sbostic 	fp->_write = __swrite;
12546085Sbostic 	fp->_seek = __sseek;
12646085Sbostic 	fp->_close = __sclose;
12746085Sbostic 	return (fp);
1282008Swnj }
129