xref: /titanic_50/usr/src/lib/libbc/libc/stdio/sys5/flsbuf.c (revision c77a61a72b5ecdc507d6cf104142edd371a16c84)
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 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*LINTLIBRARY*/
30 #include <stdio.h>
31 #include <errno.h>
32 #include "../common/stdiom.h"
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <unistd.h>
36 #include <malloc.h>
37 
38 extern unsigned char (*_smbuf)[_SBFSIZ];
39 
40 void	_findbuf(FILE *);
41 void	_bufsync(FILE *);
42 
43 extern int fclose();
44 
45 /*
46  * Flush buffers on exit
47  */
48 void
49 _cleanup(void)
50 {
51 
52 	_fwalk(fclose);
53 }
54 
55 /*
56  *	fclose() will flush (output) buffers for a buffered open
57  *	FILE and then issue a system close on the _fileno.  The
58  *	_base field will be reset to NULL for any but stdin and
59  *	stdout, the _ptr field will be set the same as the _base
60  *	field. The _flags and the _cnt field will be zeroed.
61  *	If buffers had been obtained via malloc(), the space will
62  *	be free()'d.  In case the FILE was not open, or fflush()
63  *	or close() failed, an EOF will be returned, otherwise the
64  *	return value is 0.
65  */
66 int
67 fclose(FILE *iop)
68 {
69 	int rtn=EOF;
70 
71 	if(iop == NULL)
72 		return(rtn);
73 	if(iop->_flag & (_IOREAD | _IOWRT | _IORW)
74 	   && (iop->_flag & _IOSTRG) == 0) {
75 		rtn = (iop->_flag & _IONBF)? 0: fflush(iop);
76 		if(close(fileno(iop)) < 0)
77 			rtn = EOF;
78 	}
79 	if(iop->_flag & _IOMYBUF) {
80 		free((char*)iop->_base);
81 		iop->_base = NULL;
82 	}
83 	iop->_flag = 0;
84 	iop->_cnt = 0;
85 	iop->_ptr = iop->_base;
86 	iop->_bufsiz = 0;
87 	return(rtn);
88 }
89 
90 /*
91  *	The fflush() routine must take care because of the
92  *	possibility for recursion. The calling program might
93  *	do IO in an interupt catching routine that is likely
94  *	to interupt the write() call within fflush()
95  */
96 
97 int
98 fflush(FILE *iop)
99 {
100 	if (!(iop->_flag & _IOWRT)) {
101 		if ((iop->_base != NULL) && iop->_cnt) {
102 			lseek(iop->_file, -(iop->_cnt), SEEK_CUR);
103 			iop->_cnt = 0;
104 		}
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 /*
114  * The routine _flsbuf may or may not actually flush the output buffer.  If
115  * the file is line-buffered, the fact that iop->_cnt has run below zero
116  * is meaningless: it is always kept below zero so that invocations of putc
117  * will consistently give control to _flsbuf, even if the buffer is far from
118  * full.  _flsbuf, on seeing the "line-buffered" flag, determines whether the
119  * buffer is actually full by comparing iop->_ptr to the end of the buffer
120  * iop->_base + iop->_bufsiz.  If it is full, or if an output line is
121  * completed (with a newline), the buffer is flushed.  (Note: the character
122  * argument to _flsbuf is not flushed with the current buffer if the buffer
123  * is actually full -- it goes into the buffer after flushing.)
124  */
125 
126 int
127 _flsbuf(unsigned char c, FILE *iop)
128 {
129     unsigned char c1;
130 
131     do {
132 	/* check for linebuffered with write perm, but no EOF */
133 	if ( (iop->_flag & (_IOLBF | _IOWRT | _IOEOF)) == (_IOLBF | _IOWRT) ) {
134 		if ( iop->_ptr >= iop->_base + iop->_bufsiz )  /* if buffer full, */
135 			break;		    /* exit do-while, and flush buf. */
136 		if ( (*iop->_ptr++ = c) != '\n' )
137 			return(c);
138 		return(_xflsbuf(iop) == EOF ? EOF : c);
139 	}
140 	/* write out an unbuffered file, if have write perm, but no EOF */
141 	if ( (iop->_flag & (_IONBF | _IOWRT | _IOEOF)) == (_IONBF | _IOWRT) ) {
142 		c1 = c;
143 		iop->_cnt = 0;
144 		if (write(fileno(iop), (char *) &c1, 1) == 1)
145 			return(c);
146 		iop->_flag |= _IOERR;
147 		return(EOF);
148 	}
149 	/* The _wrtchk call is here rather than at the top of _flsbuf to re- */
150 	/* duce overhead for line-buffered I/O under normal circumstances.  */
151 
152 	if (_WRTCHK(iop))			/* is writing legitimate? */
153 		return(EOF);
154     } while ( (iop->_flag & (_IONBF | _IOLBF)) );
155 
156 
157     (void) _xflsbuf(iop);   /* full buffer:  flush buffer */
158     (void) putc((char) c, iop);  /* then put "c" in newly emptied buf */
159 			/* (which, because of signals, may NOT be empty) */
160     return( ferror(iop) ? EOF : c);
161 }
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(FILE *iop)
184 {
185 	unsigned char *base;
186 	int n;
187 
188 	n = iop->_ptr - (base = iop->_base);
189 	iop->_ptr = base;
190 	iop->_cnt = (iop->_flag &(_IONBF | _IOLBF)) ? 0 : iop->_bufsiz;
191 	_BUFSYNC(iop);
192 	if (n > 0 && n != write(fileno(iop),(char*)base,(unsigned)n) )  {
193 		iop->_flag |= _IOERR;
194 		return(EOF);
195 	}
196 	return(0);
197 }
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(FILE *iop)
208 {
209 	if ( (iop->_flag & (_IOWRT | _IOEOF)) != _IOWRT ) {
210 		if (!(iop->_flag & (_IOWRT | _IORW)))
211 			return(EOF);  /* bogus call--read-only file */
212 		iop->_flag = iop->_flag & ~_IOEOF | _IOWRT; /* fix flags */
213 	}
214 	if (iop->_flag & _IOSTRG)
215 		return(0);	/* not our business to monkey with buffers or counts */
216 	if (iop->_base == NULL)    /* this is first I/O to file--get buffer */
217 		_findbuf(iop);
218 	if (iop->_ptr == iop->_base && !(iop->_flag & (_IONBF | _IOLBF)) )  {
219 		iop->_cnt = iop->_bufsiz; /* first write since seek--set cnt */
220 		_BUFSYNC(iop);
221 	}
222 	return(0);
223 }
224 
225 /*
226  * _findbuf, called only when iop->_base == NULL, locates a predefined buffer
227  * or allocates a buffer using malloc.  If a buffer is obtained from malloc,
228  * the _IOMYBUF flag is set in iop->_flag.
229  */
230 
231 void
232 _findbuf(FILE *iop)
233 {
234 	int fno = fileno(iop); /* file number */
235 	struct stat statb;
236 	int size;
237 
238 	/* allocate a small block for unbuffered, large for buffered */
239 	if (iop->_flag & _IONBF)  {
240 		iop->_base = _smbuf[fno];
241 		iop->_bufsiz = _SBFSIZ;
242 	}  else  {
243 
244 		if ( isatty(fno) ) {
245 			iop->_flag |= _IOLBF;
246 			size = 128;
247 		} else {
248 			if (fstat(fno, &statb) < 0)
249 				size = BUFSIZ;
250 			else {
251 				if ((size = statb.st_blksize) <= 0)
252 					size = BUFSIZ;
253 			}
254 		}
255 		if ((iop->_base = (unsigned char *) malloc(size+8)) != NULL) {
256 			/* if  we got a buffer */
257 			iop->_flag |= _IOMYBUF;
258 			iop->_bufsiz = size;
259 		} else {
260 			/* if no room for buffer, use small buffer */
261 			iop->_base = _smbuf[fno];
262 			iop->_bufsiz = _SBFSIZ;
263 			iop->_flag &= ~_IOLBF;
264 			iop->_flag |= _IONBF;
265 		}
266 	}
267 	iop->_ptr = iop->_base;
268 }
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 void
282 _bufsync(FILE *iop)
283 {
284 	int spaceleft;
285 	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