xref: /csrg-svn/lib/libc/stdio/freopen.c (revision 46085)
1*46085Sbostic /*-
2*46085Sbostic  * Copyright (c) 1990 The Regents of the University of California.
3*46085Sbostic  * All rights reserved.
4*46085Sbostic  *
5*46085Sbostic  * This code is derived from software contributed to Berkeley by
6*46085Sbostic  * Chris Torek.
7*46085Sbostic  *
8*46085Sbostic  * %sccs.include.redist.c%
921407Sdist  */
1021407Sdist 
1126652Sdonn #if defined(LIBC_SCCS) && !defined(lint)
12*46085Sbostic static char sccsid[] = "@(#)freopen.c	5.3 (Berkeley) 01/20/91";
13*46085Sbostic #endif /* LIBC_SCCS and not lint */
1421407Sdist 
1517951Sserge #include <sys/types.h>
1617951Sserge #include <sys/file.h>
17*46085Sbostic #include <sys/stat.h>
18*46085Sbostic #include <errno.h>
1917951Sserge #include <stdio.h>
20*46085Sbostic #include <stdlib.h>
21*46085Sbostic #include "local.h"
222008Swnj 
23*46085Sbostic /*
24*46085Sbostic  * Re-direct an existing, open (probably) file to some other file.
25*46085Sbostic  * ANSI is written such that the original file gets closed if at
26*46085Sbostic  * all possible, no matter what.
27*46085Sbostic  */
282008Swnj FILE *
29*46085Sbostic freopen(file, mode, fp)
30*46085Sbostic 	char *file, *mode;
31*46085Sbostic 	register FILE *fp;
322008Swnj {
33*46085Sbostic 	register int f;
34*46085Sbostic 	int flags, isopen, oflags, sverrno, wantfd;
352008Swnj 
36*46085Sbostic 	if ((flags = __sflags(mode, &oflags)) == 0) {
37*46085Sbostic 		(void) fclose(fp);
38*46085Sbostic 		return (NULL);
39*46085Sbostic 	}
403163Stoy 
41*46085Sbostic 	if (!__sdidinit)
42*46085Sbostic 		__sinit();
4317951Sserge 
44*46085Sbostic 	/*
45*46085Sbostic 	 * There are actually programs that depend on being able to "freopen"
46*46085Sbostic 	 * descriptors that weren't originally open.  Keep this from breaking.
47*46085Sbostic 	 * Remember whether the stream was open to begin with, and which file
48*46085Sbostic 	 * descriptor (if any) was associated with it.  If it was attached to
49*46085Sbostic 	 * a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin)
50*46085Sbostic 	 * should work.  This is unnecessary if it was not a Unix file.
51*46085Sbostic 	 */
52*46085Sbostic 	if (fp->_flags == 0) {
53*46085Sbostic 		fp->_flags = __SEOF;	/* hold on to it */
54*46085Sbostic 		isopen = 0;
55*46085Sbostic 		wantfd = -1;
56*46085Sbostic 	} else {
57*46085Sbostic 		/* flush the stream; ANSI doesn't require this. */
58*46085Sbostic 		if (fp->_flags & __SWR)
59*46085Sbostic 			(void) fflush(fp);
60*46085Sbostic 		/* if close is NULL, closing is a no-op, hence pointless */
61*46085Sbostic 		isopen = fp->_close != NULL;
62*46085Sbostic 		if ((wantfd = fp->_file) < 0 && isopen) {
63*46085Sbostic 			(void) (*fp->_close)(fp->_cookie);
64*46085Sbostic 			isopen = 0;
65*46085Sbostic 		}
6617951Sserge 	}
6717951Sserge 
68*46085Sbostic 	/* Get a new descriptor to refer to the new file. */
69*46085Sbostic 	f = open(file, oflags, DEFFILEMODE);
70*46085Sbostic 	if (f < 0 && isopen) {
71*46085Sbostic 		/* If out of fd's close the old one and try again. */
72*46085Sbostic 		if (errno == ENFILE || errno == EMFILE) {
73*46085Sbostic 			(void) (*fp->_close)(fp->_cookie);
74*46085Sbostic 			isopen = 0;
75*46085Sbostic 			f = open(file, oflags, DEFFILEMODE);
76*46085Sbostic 		}
77*46085Sbostic 	}
78*46085Sbostic 	sverrno = errno;
79*46085Sbostic 
80*46085Sbostic 	/*
81*46085Sbostic 	 * Finish closing fp.  Even if the open succeeded above, we cannot
82*46085Sbostic 	 * keep fp->_base: it may be the wrong size.  This loses the effect
83*46085Sbostic 	 * of any setbuffer calls, but stdio has always done this before.
84*46085Sbostic 	 */
85*46085Sbostic 	if (isopen)
86*46085Sbostic 		(void) (*fp->_close)(fp->_cookie);
87*46085Sbostic 	if (fp->_flags & __SMBF)
88*46085Sbostic 		free((char *)fp->_bf._base);
89*46085Sbostic 	fp->_w = 0;
90*46085Sbostic 	fp->_r = 0;
91*46085Sbostic 	fp->_p = NULL;
92*46085Sbostic 	fp->_bf._base = NULL;
93*46085Sbostic 	fp->_bf._size = 0;
94*46085Sbostic 	fp->_lbfsize = 0;
95*46085Sbostic 	if (HASUB(fp))
96*46085Sbostic 		FREEUB(fp);
97*46085Sbostic 	fp->_ub._size = 0;
98*46085Sbostic 	if (HASLB(fp))
99*46085Sbostic 		FREELB(fp);
100*46085Sbostic 	fp->_lb._size = 0;
101*46085Sbostic 
102*46085Sbostic 	if (f < 0) {			/* did not get it after all */
103*46085Sbostic 		fp->_flags = 0;		/* set it free */
104*46085Sbostic 		errno = sverrno;	/* restore in case _close clobbered */
10517951Sserge 		return (NULL);
106*46085Sbostic 	}
10717951Sserge 
108*46085Sbostic 	/*
109*46085Sbostic 	 * If reopening something that was open before on a real file, try
110*46085Sbostic 	 * to maintain the descriptor.  Various C library routines (perror)
111*46085Sbostic 	 * assume stderr is always fd STDERR_FILENO, even if being freopen'd.
112*46085Sbostic 	 */
113*46085Sbostic 	if (wantfd >= 0 && f != wantfd) {
114*46085Sbostic 		if (dup2(f, wantfd) >= 0) {
115*46085Sbostic 			(void) close(f);
116*46085Sbostic 			f = wantfd;
117*46085Sbostic 		}
118*46085Sbostic 	}
11917951Sserge 
120*46085Sbostic 	fp->_flags = flags;
121*46085Sbostic 	fp->_file = f;
122*46085Sbostic 	fp->_cookie = fp;
123*46085Sbostic 	fp->_read = __sread;
124*46085Sbostic 	fp->_write = __swrite;
125*46085Sbostic 	fp->_seek = __sseek;
126*46085Sbostic 	fp->_close = __sclose;
127*46085Sbostic 	return (fp);
1282008Swnj }
129