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