xref: /titanic_51/usr/src/lib/libbc/libc/stdio/4.2/flsbuf.c (revision bdfc6d18da790deeec2e0eb09c625902defe2498)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1989 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 /*      Copyright (c) 1984 AT&T */
27 /*        All Rights Reserved   */
28 
29 #pragma ident	"%Z%%M%	%I%	%E% SMI"  /* from S5R2 2.8 */
30 
31 /*LINTLIBRARY*/
32 #include <stdio.h>
33 #include "../common/stdiom.h"
34 #include <sys/errno.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 
38 extern void free();
39 extern int errno, write(), close(), isatty();
40 extern char *malloc();
41 extern unsigned char (*_smbuf)[_SBFSIZ];
42 
43 void _getsmbuf();
44 
45 /*
46  * Flush buffers on exit
47  */
48 
49 void
50 _cleanup()
51 {
52 	extern int fclose();
53 
54 	_fwalk(fclose);
55 }
56 /*
57 	fclose() will flush (output) buffers for a buffered open
58 	FILE and then issue a system close on the _fileno.  The
59 	_base field will be reset to NULL for any but stdin and
60 	stdout, the _ptr field will be set the same as the _base
61 	field. The _flags and the _cnt field will be zeroed.
62 	If buffers had been obtained via malloc(), the space will
63 	be free()'d.  In case the FILE was not open, or fflush()
64 	or close() failed, an EOF will be returned, otherwise the
65 	return value is 0.
66  */
67 
68 int
69 fclose(iop)
70 register FILE *iop;
71 {
72 	register int rtn=EOF;
73 
74 	if(iop == NULL)
75 		return(rtn);
76 	if(iop->_flag & (_IOREAD | _IOWRT | _IORW)
77 	   && (iop->_flag & _IOSTRG) == 0) {
78 		rtn = (iop->_flag & _IONBF)? 0: fflush(iop);
79 		if(close(fileno(iop)) < 0)
80 			rtn = EOF;
81 	}
82 	if(iop->_flag & _IOMYBUF) {
83 		free((char*)iop->_base);
84 		iop->_base = NULL;
85 	}
86 	iop->_flag = 0;
87 	iop->_cnt = 0;
88 	iop->_ptr = iop->_base;
89 	iop->_bufsiz = 0;
90 	return(rtn);
91 }
92 
93 /*
94 	The fflush() routine must take care because of the
95 	possibility for recursion. The calling program might
96 	do IO in an interupt catching routine that is likely
97 	to interupt the write() call within fflush()
98  */
99 
100 int
101 fflush(iop)
102 register FILE *iop;
103 {
104 	if (!(iop->_flag & _IOWRT)) {
105 		return(0);
106 	}
107 	while(!(iop->_flag & _IONBF) && (iop->_flag & _IOWRT) &&
108 			(iop->_base != NULL) && (iop->_ptr > iop->_base) )
109 		(void) _xflsbuf(iop);
110 	return(ferror(iop) ? EOF : 0);
111 }
112 
113 /* The routine _flsbuf may or may not actually flush the output buffer.  If
114  * the file is line-buffered, the fact that iop->_cnt has run below zero
115  * is meaningless: it is always kept below zero so that invocations of putc
116  * will consistently give control to _flsbuf, even if the buffer is far from
117  * full.  _flsbuf, on seeing the "line-buffered" flag, determines whether the
118  * buffer is actually full by comparing iop->_ptr to the end of the buffer
119  * iop->_base + iop->_bufsiz.  If it is full, or if an output line is
120  * completed (with a newline), the buffer is flushed.  (Note: the character
121  * argument to _flsbuf is not flushed with the current buffer if the buffer
122  * is actually full -- it goes into the buffer after flushing.)
123  */
124 
125 int
126 _flsbuf(c, iop)
127 unsigned char c;
128 register FILE *iop;
129 {
130     unsigned char c1;
131 
132     do {
133 	/* check for linebuffered with write perm, but no EOF */
134 	if ( (iop->_flag & (_IOLBF | _IOWRT | _IOEOF)) == (_IOLBF | _IOWRT) ) {
135 		if ( iop->_ptr >= iop->_base + iop->_bufsiz )  /* if buffer full, */
136 			break;		    /* exit do-while, and flush buf. */
137 		if ( (*iop->_ptr++ = c) != '\n' )
138 			return(c);
139 		return(_xflsbuf(iop) == EOF ? EOF : c);
140 	}
141 	/* write out an unbuffered file, if have write perm, but no EOF */
142 	if ( (iop->_flag & (_IONBF | _IOWRT | _IOEOF)) == (_IONBF | _IOWRT) ) {
143 		c1 = c;
144 		iop->_cnt = 0;
145 		if (write(fileno(iop), (char *) &c1, 1) == 1)
146 			return(c);
147 		iop->_flag |= _IOERR;
148 		return(EOF);
149 	}
150 	/* The _wrtchk call is here rather than at the top of _flsbuf to re- */
151 	/* duce overhead for line-buffered I/O under normal circumstances.  */
152 
153 	if (_WRTCHK(iop))			/* is writing legitimate? */
154 		return(EOF);
155     } while ( (iop->_flag & (_IONBF | _IOLBF)) );
156 
157 
158     (void) _xflsbuf(iop);   /* full buffer:  flush buffer */
159     (void) putc((char) c, iop);  /* then put "c" in newly emptied buf */
160 			/* (which, because of signals, may NOT be empty) */
161     return( ferror(iop) ? EOF : c);
162 }
163 
164 /* The function _xflsbuf writes out the current contents of the output
165  * buffer delimited by iop->_base and iop->_ptr.
166  * iop->_cnt is reset appropriately, but its value on entry to _xflsbuf
167  * is ignored.
168  *
169  * The following code is not strictly correct.  If a signal is raised,
170  * invoking a signal-handler which generates output into the same buffer
171  * being flushed, a peculiar output sequence may result (for example,
172  * the output generated by the signal-handler may appear twice).  At
173  * present no means has been found to guarantee correct behavior without
174  * resorting to the disabling of signals, a means considered too expensive.
175  * For now the code has been written with the intent of reducing the
176  * probability of strange effects and, when they do occur, of confining
177  * the damage.  Except under extremely pathological circumstances, this
178  * code should be expected to respect buffer boundaries even in the face
179  * of interrupts and other signals.
180  */
181 
182 int
183 _xflsbuf(iop)
184 register FILE *iop;
185 {
186 	register unsigned char *base;
187 	register int n;
188 
189 	n = iop->_ptr - (base = iop->_base);
190 	iop->_ptr = base;
191 	iop->_cnt = (iop->_flag &(_IONBF | _IOLBF)) ? 0 : iop->_bufsiz;
192 	_BUFSYNC(iop);
193 	if (n > 0 && n != write(fileno(iop),(char*)base,(unsigned)n) )  {
194 		iop->_flag |= _IOERR;
195 		return(EOF);
196 	}
197 	return(0);
198 }
199 
200 /* The function _wrtchk checks to see whether it is legitimate to write
201  * to the specified device.  If it is, _wrtchk sets flags in iop->_flag for
202  * writing, assures presence of a buffer, and returns 0.  If writing is not
203  * legitimate, EOF is returned.
204  */
205 
206 int
207 _wrtchk(iop)
208 register FILE *iop;
209 {
210 	if ( (iop->_flag & (_IOWRT | _IOEOF)) != _IOWRT ) {
211 		if (!(iop->_flag & (_IOWRT | _IORW)))
212 			return(EOF);  /* bogus call--read-only file */
213 		iop->_flag = iop->_flag & ~_IOEOF | _IOWRT; /* fix flags */
214 	}
215 	if (iop->_flag & _IOSTRG)
216 		return(0);	/* not our business to monkey with buffers or counts */
217 	if (iop->_base == NULL)    /* this is first I/O to file--get buffer */
218 		_findbuf(iop);
219 	if (iop->_ptr == iop->_base && !(iop->_flag & (_IONBF | _IOLBF)) )  {
220 		iop->_cnt = iop->_bufsiz; /* first write since seek--set cnt */
221 		_BUFSYNC(iop);
222 	}
223 	return(0);
224 }
225 
226 /*
227  * _findbuf, called only when iop->_base == NULL, locates a predefined buffer
228  * or allocates a buffer using malloc.  If a buffer is obtained from malloc,
229  * the _IOMYBUF flag is set in iop->_flag.
230  */
231 
232 _findbuf(iop)
233 register FILE *iop;
234 {
235 	register int fno = fileno(iop); /* file number */
236 	struct stat statb;
237 	register int size;
238 
239 	/* allocate a small block for unbuffered, large for buffered */
240 	if (iop->_flag & _IONBF)  {
241 		iop->_base = _smbuf[fno];
242 		iop->_bufsiz = _SBFSIZ;
243 	}  else  {
244 
245 		if ( isatty(fno) ) {
246 			iop->_flag |= _IOLBF;
247 			size = 128;
248 		} else {
249 			if (fstat(fno, &statb) < 0)
250 				size = BUFSIZ;
251 			else {
252 				if ((size = statb.st_blksize) <= 0)
253 					size = BUFSIZ;
254 			}
255 		}
256 		if ((iop->_base = (unsigned char *) malloc(size+8)) != NULL) {
257 			/* if  we got a buffer */
258 			iop->_flag |= _IOMYBUF;
259 			iop->_bufsiz = size;
260 		} else {
261 			/* if no room for buffer, use small buffer */
262 			iop->_base = _smbuf[fno];
263 			iop->_bufsiz = _SBFSIZ;
264 			iop->_flag &= ~_IOLBF;
265 			iop->_flag |= _IONBF;
266 		}
267 	}
268 	iop->_ptr = iop->_base;
269 }
270 
271 /* The function _bufsync is called because interrupts and other signals
272  * which occur in between the decrementing of iop->_cnt and the incrementing
273  * of iop->_ptr, or in other contexts as well, may upset the synchronization
274  * of iop->_cnt and iop->ptr.  If this happens, calling _bufsync should
275  * resynchronize the two quantities (this is not always possible).  Resyn-
276  * chronization guarantees that putc invocations will not write beyond
277  * the end of the buffer.  Note that signals during _bufsync can cause
278  * _bufsync to do the wrong thing, but usually with benign effects.
279  */
280 
281 _bufsync(iop)
282 register FILE *iop;
283 {
284 	register int spaceleft;
285 	register unsigned char *bufend = iop->_base + iop->_bufsiz;
286 
287 	if ((spaceleft = bufend - iop->_ptr) < 0)
288 		iop->_ptr = bufend;
289 	else if (spaceleft < iop->_cnt)
290 		iop->_cnt = spaceleft;
291 }
292