summaryrefslogtreecommitdiff
path: root/usr/src/lib/libbc/libc/stdio/4.2/flsbuf.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libbc/libc/stdio/4.2/flsbuf.c')
-rw-r--r--usr/src/lib/libbc/libc/stdio/4.2/flsbuf.c291
1 files changed, 291 insertions, 0 deletions
diff --git a/usr/src/lib/libbc/libc/stdio/4.2/flsbuf.c b/usr/src/lib/libbc/libc/stdio/4.2/flsbuf.c
new file mode 100644
index 0000000000..94da8125f5
--- /dev/null
+++ b/usr/src/lib/libbc/libc/stdio/4.2/flsbuf.c
@@ -0,0 +1,291 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1989 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/* Copyright (c) 1984 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* from S5R2 2.8 */
+
+/*LINTLIBRARY*/
+#include <stdio.h>
+#include "../common/stdiom.h"
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+extern void free();
+extern int errno, write(), close(), isatty();
+extern char *malloc();
+extern unsigned char (*_smbuf)[_SBFSIZ];
+
+void _getsmbuf();
+
+/*
+ * Flush buffers on exit
+ */
+
+void
+_cleanup()
+{
+ extern int fclose();
+
+ _fwalk(fclose);
+}
+/*
+ fclose() will flush (output) buffers for a buffered open
+ FILE and then issue a system close on the _fileno. The
+ _base field will be reset to NULL for any but stdin and
+ stdout, the _ptr field will be set the same as the _base
+ field. The _flags and the _cnt field will be zeroed.
+ If buffers had been obtained via malloc(), the space will
+ be free()'d. In case the FILE was not open, or fflush()
+ or close() failed, an EOF will be returned, otherwise the
+ return value is 0.
+ */
+
+int
+fclose(iop)
+register FILE *iop;
+{
+ register int rtn=EOF;
+
+ if(iop == NULL)
+ return(rtn);
+ if(iop->_flag & (_IOREAD | _IOWRT | _IORW)
+ && (iop->_flag & _IOSTRG) == 0) {
+ rtn = (iop->_flag & _IONBF)? 0: fflush(iop);
+ if(close(fileno(iop)) < 0)
+ rtn = EOF;
+ }
+ if(iop->_flag & _IOMYBUF) {
+ free((char*)iop->_base);
+ iop->_base = NULL;
+ }
+ iop->_flag = 0;
+ iop->_cnt = 0;
+ iop->_ptr = iop->_base;
+ iop->_bufsiz = 0;
+ return(rtn);
+}
+
+/*
+ The fflush() routine must take care because of the
+ possibility for recursion. The calling program might
+ do IO in an interupt catching routine that is likely
+ to interupt the write() call within fflush()
+ */
+
+int
+fflush(iop)
+register FILE *iop;
+{
+ if (!(iop->_flag & _IOWRT)) {
+ return(0);
+ }
+ while(!(iop->_flag & _IONBF) && (iop->_flag & _IOWRT) &&
+ (iop->_base != NULL) && (iop->_ptr > iop->_base) )
+ (void) _xflsbuf(iop);
+ return(ferror(iop) ? EOF : 0);
+}
+
+/* The routine _flsbuf may or may not actually flush the output buffer. If
+ * the file is line-buffered, the fact that iop->_cnt has run below zero
+ * is meaningless: it is always kept below zero so that invocations of putc
+ * will consistently give control to _flsbuf, even if the buffer is far from
+ * full. _flsbuf, on seeing the "line-buffered" flag, determines whether the
+ * buffer is actually full by comparing iop->_ptr to the end of the buffer
+ * iop->_base + iop->_bufsiz. If it is full, or if an output line is
+ * completed (with a newline), the buffer is flushed. (Note: the character
+ * argument to _flsbuf is not flushed with the current buffer if the buffer
+ * is actually full -- it goes into the buffer after flushing.)
+ */
+
+int
+_flsbuf(c, iop)
+unsigned char c;
+register FILE *iop;
+{
+ unsigned char c1;
+
+ do {
+ /* check for linebuffered with write perm, but no EOF */
+ if ( (iop->_flag & (_IOLBF | _IOWRT | _IOEOF)) == (_IOLBF | _IOWRT) ) {
+ if ( iop->_ptr >= iop->_base + iop->_bufsiz ) /* if buffer full, */
+ break; /* exit do-while, and flush buf. */
+ if ( (*iop->_ptr++ = c) != '\n' )
+ return(c);
+ return(_xflsbuf(iop) == EOF ? EOF : c);
+ }
+ /* write out an unbuffered file, if have write perm, but no EOF */
+ if ( (iop->_flag & (_IONBF | _IOWRT | _IOEOF)) == (_IONBF | _IOWRT) ) {
+ c1 = c;
+ iop->_cnt = 0;
+ if (write(fileno(iop), (char *) &c1, 1) == 1)
+ return(c);
+ iop->_flag |= _IOERR;
+ return(EOF);
+ }
+ /* The _wrtchk call is here rather than at the top of _flsbuf to re- */
+ /* duce overhead for line-buffered I/O under normal circumstances. */
+
+ if (_WRTCHK(iop)) /* is writing legitimate? */
+ return(EOF);
+ } while ( (iop->_flag & (_IONBF | _IOLBF)) );
+
+
+ (void) _xflsbuf(iop); /* full buffer: flush buffer */
+ (void) putc((char) c, iop); /* then put "c" in newly emptied buf */
+ /* (which, because of signals, may NOT be empty) */
+ return( ferror(iop) ? EOF : c);
+}
+
+/* The function _xflsbuf writes out the current contents of the output
+ * buffer delimited by iop->_base and iop->_ptr.
+ * iop->_cnt is reset appropriately, but its value on entry to _xflsbuf
+ * is ignored.
+ *
+ * The following code is not strictly correct. If a signal is raised,
+ * invoking a signal-handler which generates output into the same buffer
+ * being flushed, a peculiar output sequence may result (for example,
+ * the output generated by the signal-handler may appear twice). At
+ * present no means has been found to guarantee correct behavior without
+ * resorting to the disabling of signals, a means considered too expensive.
+ * For now the code has been written with the intent of reducing the
+ * probability of strange effects and, when they do occur, of confining
+ * the damage. Except under extremely pathological circumstances, this
+ * code should be expected to respect buffer boundaries even in the face
+ * of interrupts and other signals.
+ */
+
+int
+_xflsbuf(iop)
+register FILE *iop;
+{
+ register unsigned char *base;
+ register int n;
+
+ n = iop->_ptr - (base = iop->_base);
+ iop->_ptr = base;
+ iop->_cnt = (iop->_flag &(_IONBF | _IOLBF)) ? 0 : iop->_bufsiz;
+ _BUFSYNC(iop);
+ if (n > 0 && n != write(fileno(iop),(char*)base,(unsigned)n) ) {
+ iop->_flag |= _IOERR;
+ return(EOF);
+ }
+ return(0);
+}
+
+/* The function _wrtchk checks to see whether it is legitimate to write
+ * to the specified device. If it is, _wrtchk sets flags in iop->_flag for
+ * writing, assures presence of a buffer, and returns 0. If writing is not
+ * legitimate, EOF is returned.
+ */
+
+int
+_wrtchk(iop)
+register FILE *iop;
+{
+ if ( (iop->_flag & (_IOWRT | _IOEOF)) != _IOWRT ) {
+ if (!(iop->_flag & (_IOWRT | _IORW)))
+ return(EOF); /* bogus call--read-only file */
+ iop->_flag = iop->_flag & ~_IOEOF | _IOWRT; /* fix flags */
+ }
+ if (iop->_flag & _IOSTRG)
+ return(0); /* not our business to monkey with buffers or counts */
+ if (iop->_base == NULL) /* this is first I/O to file--get buffer */
+ _findbuf(iop);
+ if (iop->_ptr == iop->_base && !(iop->_flag & (_IONBF | _IOLBF)) ) {
+ iop->_cnt = iop->_bufsiz; /* first write since seek--set cnt */
+ _BUFSYNC(iop);
+ }
+ return(0);
+}
+
+/*
+ * _findbuf, called only when iop->_base == NULL, locates a predefined buffer
+ * or allocates a buffer using malloc. If a buffer is obtained from malloc,
+ * the _IOMYBUF flag is set in iop->_flag.
+ */
+
+_findbuf(iop)
+register FILE *iop;
+{
+ register int fno = fileno(iop); /* file number */
+ struct stat statb;
+ register int size;
+
+ /* allocate a small block for unbuffered, large for buffered */
+ if (iop->_flag & _IONBF) {
+ iop->_base = _smbuf[fno];
+ iop->_bufsiz = _SBFSIZ;
+ } else {
+
+ if ( isatty(fno) ) {
+ iop->_flag |= _IOLBF;
+ size = 128;
+ } else {
+ if (fstat(fno, &statb) < 0)
+ size = BUFSIZ;
+ else {
+ if ((size = statb.st_blksize) <= 0)
+ size = BUFSIZ;
+ }
+ }
+ if ((iop->_base = (unsigned char *) malloc(size+8)) != NULL) {
+ /* if we got a buffer */
+ iop->_flag |= _IOMYBUF;
+ iop->_bufsiz = size;
+ } else {
+ /* if no room for buffer, use small buffer */
+ iop->_base = _smbuf[fno];
+ iop->_bufsiz = _SBFSIZ;
+ iop->_flag &= ~_IOLBF;
+ iop->_flag |= _IONBF;
+ }
+ }
+ iop->_ptr = iop->_base;
+}
+
+/* The function _bufsync is called because interrupts and other signals
+ * which occur in between the decrementing of iop->_cnt and the incrementing
+ * of iop->_ptr, or in other contexts as well, may upset the synchronization
+ * of iop->_cnt and iop->ptr. If this happens, calling _bufsync should
+ * resynchronize the two quantities (this is not always possible). Resyn-
+ * chronization guarantees that putc invocations will not write beyond
+ * the end of the buffer. Note that signals during _bufsync can cause
+ * _bufsync to do the wrong thing, but usually with benign effects.
+ */
+
+_bufsync(iop)
+register FILE *iop;
+{
+ register int spaceleft;
+ register unsigned char *bufend = iop->_base + iop->_bufsiz;
+
+ if ((spaceleft = bufend - iop->_ptr) < 0)
+ iop->_ptr = bufend;
+ else if (spaceleft < iop->_cnt)
+ iop->_cnt = spaceleft;
+}