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