xref: /titanic_44/usr/src/lib/libbc/libc/stdio/sys5/flsbuf.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 	  /* from ../4.2/flsbuf.c  */
29 
30 /*LINTLIBRARY*/
31 #include <stdio.h>
32 #include <sys/errno.h>
33 #include "../common/stdiom.h"
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <unistd.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 		if ((iop->_base != NULL) && iop->_cnt) {
106 			lseek(iop->_file, -(iop->_cnt), SEEK_CUR);
107 			iop->_cnt = 0;
108 		}
109 		return(0);
110 	}
111 	while(!(iop->_flag & _IONBF) && (iop->_flag & _IOWRT) &&
112 			(iop->_base != NULL) && (iop->_ptr > iop->_base) )
113 		(void) _xflsbuf(iop);
114 	return(ferror(iop) ? EOF : 0);
115 }
116 
117 /* The routine _flsbuf may or may not actually flush the output buffer.  If
118  * the file is line-buffered, the fact that iop->_cnt has run below zero
119  * is meaningless: it is always kept below zero so that invocations of putc
120  * will consistently give control to _flsbuf, even if the buffer is far from
121  * full.  _flsbuf, on seeing the "line-buffered" flag, determines whether the
122  * buffer is actually full by comparing iop->_ptr to the end of the buffer
123  * iop->_base + iop->_bufsiz.  If it is full, or if an output line is
124  * completed (with a newline), the buffer is flushed.  (Note: the character
125  * argument to _flsbuf is not flushed with the current buffer if the buffer
126  * is actually full -- it goes into the buffer after flushing.)
127  */
128 
129 int
130 _flsbuf(c, iop)
131 unsigned char c;
132 register FILE *iop;
133 {
134     unsigned char c1;
135 
136     do {
137 	/* check for linebuffered with write perm, but no EOF */
138 	if ( (iop->_flag & (_IOLBF | _IOWRT | _IOEOF)) == (_IOLBF | _IOWRT) ) {
139 		if ( iop->_ptr >= iop->_base + iop->_bufsiz )  /* if buffer full, */
140 			break;		    /* exit do-while, and flush buf. */
141 		if ( (*iop->_ptr++ = c) != '\n' )
142 			return(c);
143 		return(_xflsbuf(iop) == EOF ? EOF : c);
144 	}
145 	/* write out an unbuffered file, if have write perm, but no EOF */
146 	if ( (iop->_flag & (_IONBF | _IOWRT | _IOEOF)) == (_IONBF | _IOWRT) ) {
147 		c1 = c;
148 		iop->_cnt = 0;
149 		if (write(fileno(iop), (char *) &c1, 1) == 1)
150 			return(c);
151 		iop->_flag |= _IOERR;
152 		return(EOF);
153 	}
154 	/* The _wrtchk call is here rather than at the top of _flsbuf to re- */
155 	/* duce overhead for line-buffered I/O under normal circumstances.  */
156 
157 	if (_WRTCHK(iop))			/* is writing legitimate? */
158 		return(EOF);
159     } while ( (iop->_flag & (_IONBF | _IOLBF)) );
160 
161 
162     (void) _xflsbuf(iop);   /* full buffer:  flush buffer */
163     (void) putc((char) c, iop);  /* then put "c" in newly emptied buf */
164 			/* (which, because of signals, may NOT be empty) */
165     return( ferror(iop) ? EOF : c);
166 }
167 
168 /* The function _xflsbuf writes out the current contents of the output
169  * buffer delimited by iop->_base and iop->_ptr.
170  * iop->_cnt is reset appropriately, but its value on entry to _xflsbuf
171  * is ignored.
172  *
173  * The following code is not strictly correct.  If a signal is raised,
174  * invoking a signal-handler which generates output into the same buffer
175  * being flushed, a peculiar output sequence may result (for example,
176  * the output generated by the signal-handler may appear twice).  At
177  * present no means has been found to guarantee correct behavior without
178  * resorting to the disabling of signals, a means considered too expensive.
179  * For now the code has been written with the intent of reducing the
180  * probability of strange effects and, when they do occur, of confining
181  * the damage.  Except under extremely pathological circumstances, this
182  * code should be expected to respect buffer boundaries even in the face
183  * of interrupts and other signals.
184  */
185 
186 int
187 _xflsbuf(iop)
188 register FILE *iop;
189 {
190 	register unsigned char *base;
191 	register int n;
192 
193 	n = iop->_ptr - (base = iop->_base);
194 	iop->_ptr = base;
195 	iop->_cnt = (iop->_flag &(_IONBF | _IOLBF)) ? 0 : iop->_bufsiz;
196 	_BUFSYNC(iop);
197 	if (n > 0 && n != write(fileno(iop),(char*)base,(unsigned)n) )  {
198 		iop->_flag |= _IOERR;
199 		return(EOF);
200 	}
201 	return(0);
202 }
203 
204 /* The function _wrtchk checks to see whether it is legitimate to write
205  * to the specified device.  If it is, _wrtchk sets flags in iop->_flag for
206  * writing, assures presence of a buffer, and returns 0.  If writing is not
207  * legitimate, EOF is returned.
208  */
209 
210 int
211 _wrtchk(iop)
212 register FILE *iop;
213 {
214 	if ( (iop->_flag & (_IOWRT | _IOEOF)) != _IOWRT ) {
215 		if (!(iop->_flag & (_IOWRT | _IORW)))
216 			return(EOF);  /* bogus call--read-only file */
217 		iop->_flag = iop->_flag & ~_IOEOF | _IOWRT; /* fix flags */
218 	}
219 	if (iop->_flag & _IOSTRG)
220 		return(0);	/* not our business to monkey with buffers or counts */
221 	if (iop->_base == NULL)    /* this is first I/O to file--get buffer */
222 		_findbuf(iop);
223 	if (iop->_ptr == iop->_base && !(iop->_flag & (_IONBF | _IOLBF)) )  {
224 		iop->_cnt = iop->_bufsiz; /* first write since seek--set cnt */
225 		_BUFSYNC(iop);
226 	}
227 	return(0);
228 }
229 
230 /*
231  * _findbuf, called only when iop->_base == NULL, locates a predefined buffer
232  * or allocates a buffer using malloc.  If a buffer is obtained from malloc,
233  * the _IOMYBUF flag is set in iop->_flag.
234  */
235 
236 _findbuf(iop)
237 register FILE *iop;
238 {
239 	register int fno = fileno(iop); /* file number */
240 	struct stat statb;
241 	register int size;
242 
243 	/* allocate a small block for unbuffered, large for buffered */
244 	if (iop->_flag & _IONBF)  {
245 		iop->_base = _smbuf[fno];
246 		iop->_bufsiz = _SBFSIZ;
247 	}  else  {
248 
249 		if ( isatty(fno) ) {
250 			iop->_flag |= _IOLBF;
251 			size = 128;
252 		} else {
253 			if (fstat(fno, &statb) < 0)
254 				size = BUFSIZ;
255 			else {
256 				if ((size = statb.st_blksize) <= 0)
257 					size = BUFSIZ;
258 			}
259 		}
260 		if ((iop->_base = (unsigned char *) malloc(size+8)) != NULL) {
261 			/* if  we got a buffer */
262 			iop->_flag |= _IOMYBUF;
263 			iop->_bufsiz = size;
264 		} else {
265 			/* if no room for buffer, use small buffer */
266 			iop->_base = _smbuf[fno];
267 			iop->_bufsiz = _SBFSIZ;
268 			iop->_flag &= ~_IOLBF;
269 			iop->_flag |= _IONBF;
270 		}
271 	}
272 	iop->_ptr = iop->_base;
273 }
274 
275 /* The function _bufsync is called because interrupts and other signals
276  * which occur in between the decrementing of iop->_cnt and the incrementing
277  * of iop->_ptr, or in other contexts as well, may upset the synchronization
278  * of iop->_cnt and iop->ptr.  If this happens, calling _bufsync should
279  * resynchronize the two quantities (this is not always possible).  Resyn-
280  * chronization guarantees that putc invocations will not write beyond
281  * the end of the buffer.  Note that signals during _bufsync can cause
282  * _bufsync to do the wrong thing, but usually with benign effects.
283  */
284 
285 _bufsync(iop)
286 register FILE *iop;
287 {
288 	register int spaceleft;
289 	register unsigned char *bufend = iop->_base + iop->_bufsiz;
290 
291 	if ((spaceleft = bufend - iop->_ptr) < 0)
292 		iop->_ptr = bufend;
293 	else if (spaceleft < iop->_cnt)
294 		iop->_cnt = spaceleft;
295 }
296