cechew@bruce.OZ (Earl Chew) (09/04/89)
#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 2 (of 7)." # Contents: stdiolib.h _allocbu.c _cleanup.c _filbuf.c _file.c # _flsbuf.c _fopen.c _slot.c # Wrapped by cechew@bruce on Mon Sep 4 12:50:13 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'stdiolib.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'stdiolib.h'\" else echo shar: Extracting \"'stdiolib.h'\" \(5997 characters\) sed "s/^X//" >'stdiolib.h' <<'END_OF_FILE' X/* s t d i o l i b X * X * This include file is used by the stdio code. It provides some X * useful macro definitions that make the code a bit easier to X * write. X * X * Edit History: X * X * 03-Sep-1989 Added BUFFERSIZE() and altered UNUSEDINBUFFER() to X * accommodate line buffered streams. Added PUTC() X * and NPUTC() for non line buffered streams. X */ X X#include <stdio.h> X X#ifdef MINIX Xextern void (*__cleanup) Prototype(()); /* pointer to cleanup function */ X#endif X Xvoid _cleanup Prototype(()); /* cleanup function */ Xint _allocbuf Prototype((FILE *)); /* internal buffering */ Xint _fopen Prototype((char *, char *, int, short *)); /* fopen assist */ XFILE **_slot Prototype((FILE *)); /* find a slot */ XFILE *_file Prototype((FILE *, int, short)); /* initialise FILE */ X X/* Flag manipulation macros */ X X#define TESTFLAG(f,x) (((f)->_flag & (x)) != 0) X#define SETFLAG(f,x) ((f)->_flag |= (x)) X#define CLEARFLAG(f,x) ((f)->_flag &= ~(x)) X#define GETFLAG(f,x) ((f)->_flag & (x)) X#define TOGGLEFLAG(f,x) ((f)->_flag ^= (x)) X X/* Add _cleanup to exit code X * X * Check is _cleanup needs to be added to the exit code. If so then X * add it. This macro is run time system dependent. X */ X#if defined(MINIX) X# define SETCLEANUP() { if (__cleanup == NULL) __cleanup = _cleanup; } X#endif X#if !defined(SETCLEANUP) X# define SETCLEANUP() X#endif X X/* Putc for non buffered streams X * X * This version of putc is explicitly for unbuffered streams. A X * call is made directly to the buffer flushing code. X */ X#define NPUTC(x,p) ( _flsbuf((x),(p)) ) X X/* Putc without line buffering X * X * This version of putc() should be exactly the same as that declared X * in stdio.h except that it shouldn't worry about line buffering. X */ X#define PUTC(x,p) ( \ X (p)->_ptr < (p)->_base + (p)->_bufsiz \ X ? *(p)->_ptr++ = (unsigned char)(x) \ X : _flsbuf((x),(p)) \ X) X X/* Initialise an output buffer X * X * This macro uses _base and _bufsiz to initialise _ptr and _end. _ptr X * will be set to point at the base of the buffer. _end will be set X * to point at one past the end of the buffer if the stream is buffered X * otherwise it will point at the base of the buffer. Line buffered X * streams are considered to be fully buffered. X */ X#define INITWRITEBUFFER(f) ( \ X (f)->_end = ((f)->_ptr = (f)->_base) + \ X (TESTFLAG(f, _IONBF | _IOLBF) ? 0 : (f)->_bufsiz) \ X) X X/* Initialise a buffer to call either _flsbuf or _filbuf X * X * This macro initialises the buffer by setting _end and _ptr to X * _base. This will force the next putc or getc to call the X * appropriate routine. This is used by the r+, w+ and a+ modes X * of access. X */ X#define FLUSHNEXTACCESS(f) ( \ X (f)->_end = (f)->_ptr = (f)->_base \ X) X X/* Initialise an output buffer to call _flsbuf X * X * This macro initialises the output buffer setting _ptr to _base. X * _end is set to be _base so that _flsbuf will be called on the X * next putc. X */ X#define FLUSHNEXTWRITE(f) ( \ X (f)->_end = (f)->_ptr = (f)->_base \ X) X X/* Initialise an input buffer X * X * This macro empties an input buffer. It uses _base to initialise X * _ptr and sets _end to point to the high water mark of the buffer. X * X * If the argument v is zero, this macro must have the same effect X * as a call to FLUSHNEXTACCESS(f). X */ X#define INITREADBUFFER(f, v) ( \ X (f)->_end = ((f)->_ptr = (f)->_base) + (v) \ X) X X/* Initialise a buffer X * X * This macro will empty a buffer. It will decide whether it is X * an input or output buffer by examining _IOWRITE. In the case X * of a read, _ptr is set so that _filbuf will be called when X * the stream is next read. In the case of a write, the X * buffer is initialised so that it can be used for writing. X * X * Note that streams opened for update will be set as if they X * were opened for reading. X */ X#define INITBUFFER(f) ( \ X TESTFLAG((f), _IOWRITE) ? INITWRITEBUFFER((f)) \ X : INITREADBUFFER((f), 0) \ X) X X/* Buffer size X * X * Return the size of the output buffer. This will return rubbish X * for unbuffered streams. Line and fully buffered streams will X * have the true buffer size returned. X */ X#define BUFFERSIZE(f) ( (f)->_bufsiz ) X X/* Bytes left in input buffer X * X * This macro returns the number of bytes left in an input buffer. X */ X#define BYTESINREADBUFFER(f) ( (f)->_end - (f)->_ptr ) X X/* Bytes written in output buffer X * X * This macro returns the number of bytes left in an output buffer. X */ X#define BYTESINWRITEBUFFER(f) ( (f)->_ptr - (f)->_base ) X X/* Unused bytes in output buffer X * X * This macro returns the number of unused bytes in an output buffer. X * Unbuffered streams will return rubbish. Line and fully buffered streams X * will have the amount of space remaining returned. X */ X#define UNUSEDINWRITEBUFFER(f) ( (f)->_bufsiz - ((f)->_ptr - (f)->_base) ) X X/* Get pointer into write buffer X * X * This macro gets the pointer into the write buffer. X */ X#define GETWRITEPTR(f) ( (f)->_ptr ) X X/* Set pointer into write buffer X * X * This macro sets the pointer into the write buffer. X */ X#define SETWRITEPTR(f,p) ( (f)->_ptr = (p) ) X X/* Get pointer into read buffer X * X * This macro gets the pointer into the read buffer. X */ X#define GETREADPTR(f) ( (f)->_ptr ) X X/* Set pointer into read buffer X * X * This macro sets the pointer into the read buffer. X */ X#define SETREADPTR(f,p) ( (f)->_ptr = (p) ) X X/* Check if buffering has been set X * X * Return true if buffering has already been set. A stream X * set for unbuffered output is considered to have had X * its buffering set. X */ X#define HASBUFFER(f) ( (f)->_base != 0 ) X X/* Unroll a loop X * X * Assume that the loop must execute at least once. The first argument X * is the name of the loop control variable. The second argument is X * the expression to be placed in the loop body. The control variable X * should be unsigned, otherwise the right shift might propagate the sign X * bit. The caller must also provide the name of a unique label. X */ X# define UNROLL_DO(l,v,x) { \ X char t = (v); \ X (v) = ((v)+1) >> 1; \ X if (t & 1) goto l; \ X do { x; l: x; } while (--(v)); \ X} END_OF_FILE if test 5997 -ne `wc -c <'stdiolib.h'`; then echo shar: \"'stdiolib.h'\" unpacked with wrong size! fi # end of 'stdiolib.h' fi if test -f '_allocbu.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'_allocbu.c'\" else echo shar: Extracting \"'_allocbu.c'\" \(989 characters\) sed "s/^X//" >'_allocbu.c' <<'END_OF_FILE' X/* _ a l l o c b u f X * X * Allocate a buffer to a stream. This routine is designed to X * be called from _flsbuf or _filbuf and hence has some hooks X * in it for these routines. X * X * The routine initialises _bufsiz, _base, _ptr and _ctr. No X * buffer is allocated if _IONBF is in effect. Line buffering X * is engaged if the stream is attached to a terminal and the X * stream is not opened for input. X * X * Patchlevel 1.0 X * X * Edit History: X */ X X#include "stdiolib.h" X X/*LINTLIBRARY*/ X Xint _allocbuf(fp) X XFILE *fp; /* stream */ X X{ X int isatty(); /* channel is tty */ X void *malloc(); /* memory allocator */ X X if (TESTFLAG(fp, _IONBF)) { X fp->_base = &fp->_buf; X fp->_bufsiz = sizeof(fp->_buf); X } X else { X if ((fp->_base = (unsigned char *) malloc(BUFSIZ)) == NULL) X return -1; X SETFLAG(fp, _IOMYBUF); X fp->_bufsiz = BUFSIZ; X if (! TESTFLAG(fp, _IOREAD) && isatty(fp->_file)) X SETFLAG(fp, _IOLBF); X } X INITBUFFER(fp); X return fp->_bufsiz; X} END_OF_FILE if test 989 -ne `wc -c <'_allocbu.c'`; then echo shar: \"'_allocbu.c'\" unpacked with wrong size! fi # end of '_allocbu.c' fi if test -f '_cleanup.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'_cleanup.c'\" else echo shar: Extracting \"'_cleanup.c'\" \(355 characters\) sed "s/^X//" >'_cleanup.c' <<'END_OF_FILE' X/* _ c l e a n u p X * X * Cleanly close and flush all output buffers. This ensures that X * all streams are written out and closed. X * X * Patchlevel 1.0 X * X * Edit History: X */ X X#include "stdiolib.h" X X/*LINTLIBRARY*/ X Xvoid _cleanup() X X{ X int i; /* slot index */ X X for (i = 0; i < _NFILE; i++) X if (_iop[i] != NULL) X (void) fclose(_iop[i]); X} END_OF_FILE if test 355 -ne `wc -c <'_cleanup.c'`; then echo shar: \"'_cleanup.c'\" unpacked with wrong size! fi # end of '_cleanup.c' fi if test -f '_filbuf.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'_filbuf.c'\" else echo shar: Extracting \"'_filbuf.c'\" \(1232 characters\) sed "s/^X//" >'_filbuf.c' <<'END_OF_FILE' X/* _ f i l b u f X * X * Allocate and fill a stream IO buffer. This function is X * intimately tied to the macro getc() in the stdio library. X * X * The function will get a buffer full of data then return X * the first character. EOF is returned on error. X * X * Patchlevel 1.0 X * X * Edit History: X */ X X#include "stdiolib.h" X X/*LINTLIBRARY*/ X Xint _filbuf(fp) X XFILE *fp; /* stream */ X X{ X int bytes; /* bytes read */ X int read(); /* read from channel */ X X if (GETFLAG(fp, (_IORW | _IOREAD | _IOWRITE)) == _IORW) X SETFLAG(fp, _IOREAD); X X if (GETFLAG(fp, (_IOREAD | _IOERR | _IOEOF | _IOSTRING)) != _IOREAD) X return EOF; X X/* Locate buffer space for this stream */ X if (fp->_base == NULL && _allocbuf(fp) < 0) { X SETFLAG(fp, _IOERR); X return EOF; X } X X/* Flush stdout if we're reading from stdin */ X if (fp == stdin && TESTFLAG(stdout, _IOLBF)) X (void) fflush(stdout); X X/* Read data into the buffer */ X bytes = read(fp->_file, (char *) fp->_base, X TESTFLAG(fp, _IONBF) ? 1 : fp->_bufsiz); X X INITREADBUFFER(fp, bytes == -1 ? 0 : bytes); X X switch (bytes) { X case -1: SETFLAG(fp, _IOERR); return EOF; X case 0: SETFLAG(fp, _IOEOF); return EOF; X default: return *fp->_ptr++; X } X} END_OF_FILE if test 1232 -ne `wc -c <'_filbuf.c'`; then echo shar: \"'_filbuf.c'\" unpacked with wrong size! fi # end of '_filbuf.c' fi if test -f '_file.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'_file.c'\" else echo shar: Extracting \"'_file.c'\" \(813 characters\) sed "s/^X//" >'_file.c' <<'END_OF_FILE' X/* _ f i l e X * X * Allocate and initialise a FILE structure. If the pointer passed X * to the function is NULL, a FILE will be allocated, otherwise X * the one specified will be used. The function will return X * a pointer to the FILE structure, or NULL if it fails. X * X * Patchlevel 1.0 X * X * Edit History: X */ X X#include "stdiolib.h" X X/*LINTLIBRARY*/ X XFILE *_file(fp, fd, flags) X XFILE *fp; /* stream */ Xint fd; /* channel */ Xshort flags; /* flags */ X X{ X void *malloc(); /* memory allocator */ X X/* Allocate a file structure */ X if (fp == NULL) X fp = (FILE *) malloc(sizeof(*fp)); X X/* Now initialise the structure */ X if (fp != NULL) { X fp->_end = NULL; X fp->_ptr = NULL; X fp->_base = NULL; X fp->_bufsiz = 0; X fp->_flag = flags; X fp->_file = fd; X } X X return fp; X} END_OF_FILE if test 813 -ne `wc -c <'_file.c'`; then echo shar: \"'_file.c'\" unpacked with wrong size! fi # end of '_file.c' fi if test -f '_flsbuf.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'_flsbuf.c'\" else echo shar: Extracting \"'_flsbuf.c'\" \(1850 characters\) sed "s/^X//" >'_flsbuf.c' <<'END_OF_FILE' X/* _ f l s b u f X * X * Allocate and flush an output buffer. If no buffer has been X * previously allocated, one will be allocated. This function X * is intimately tied to the putc() macro in the stdio library. X * X * The function returns the character that was written to the X * file, otherwise EOF on error. X * X * Patchlevel 1.0 X * X * Edit History: X */ X X#include "stdiolib.h" X X/*LINTLIBRARY*/ X Xint _flsbuf(c, fp) X Xchar c; /* character to write */ XFILE *fp; /* stream */ X X{ X char valid; /* character still valid */ X int length; /* length of write */ X int write(); /* write to channel */ X X if (TESTFLAG(fp, _IOSTRING)) X return (unsigned char) (*fp->_ptr++ = c); X X if (GETFLAG(fp, _IORW | _IOWRITE) == _IORW) { X if (! TESTFLAG(fp, _IOREAD)) X SETFLAG(fp, _IOWRITE); X else { X if (TESTFLAG(fp, _IOEOF)) X TOGGLEFLAG(fp, (_IOEOF | _IOREAD | _IOWRITE)); X } X } X X if (GETFLAG(fp, (_IOWRITE | _IOERR)) != _IOWRITE) X return EOF; X X if (! HASBUFFER(fp)) { X if (_allocbuf(fp) < 0) X return EOF; X SETCLEANUP(); X } X X/* Signal character valid if fully buffered output */ X if (! TESTFLAG(fp, (_IONBF | _IOLBF))) X valid = 1; X X/* Do the write here if unbuffered or line buffered */ X else { X if (TESTFLAG(fp, _IONBF)) { X *fp->_ptr++ = c; X valid = 0; X } X else if (fp->_ptr < fp->_base + fp->_bufsiz) { X if ((*fp->_ptr++ = c) == '\n') X valid = 0; X else X return (unsigned char) c; X } X else X valid = 1; X } X X/* Flush the current buffer load */ X if ((length = fp->_ptr - fp->_base) != 0 && X write(fp->_file, (char *) fp->_base, length) != length) { X SETFLAG(fp, _IOERR); X FLUSHNEXTWRITE(fp); X return EOF; X } X X/* Reset the buffer pointers --- unbuffered => not valid */ X INITWRITEBUFFER(fp); X if (valid) X *fp->_ptr++ = c; X X return (unsigned char) c; X} END_OF_FILE if test 1850 -ne `wc -c <'_flsbuf.c'`; then echo shar: \"'_flsbuf.c'\" unpacked with wrong size! fi # end of '_flsbuf.c' fi if test -f '_fopen.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'_fopen.c'\" else echo shar: Extracting \"'_fopen.c'\" \(1892 characters\) sed "s/^X//" >'_fopen.c' <<'END_OF_FILE' X/* _ f o p e n m o d e X * X * This function scans the mode with which a channel should be X * opened. It then opens the channel using that mode and returns X * the channel number to the caller. On error, the value -1 will X * be returned. X * X * If the function succeeds, the flags argument will be set to the X * mode with which the channel was opened. If the fd argument is X * -1, the channel will be allocated, otherwise the specified channel X * will be used. X * X * Patchlevel 1.0 X * X * Edit History: X */ X X X#include <fcntl.h> X#include <errno.h> X#include "stdiolib.h" X X/*LINTLIBRARY*/ X Xextern int errno; /* error code */ X X#define CREATMODE 0666 /* mode to creat file */ X Xint _fopen(name, mode, fd, flags) X Xchar *name; /* name of file */ Xchar *mode; /* mode to open */ Xint fd; /* allocated channel */ Xshort *flags; /* stdio flags */ X X{ X int rw; /* basic mode */ X int update; /* read and write required */ X int close(); /* close a file */ X int creat(); /* create a file */ X int open(); /* open a file */ X long lseek(); /* seek to position */ X X rw = *mode++; X update = *mode == '+'; X X switch (rw) { X X case 'w': X *flags = update ? _IORW : _IOWRITE; X if (fd == -1) { X fd = creat(name, CREATMODE); X if (update && fd != -1 && (fd = close(fd)) != -1) X fd = open(name, O_RDWR); X } X break; X X case 'r': X *flags = update ? _IORW : _IOREAD; X if (fd == -1) X fd = open(name, update ? O_RDWR : O_RDONLY); X break; X X case 'a': X *flags = update ? _IORW : _IOWRITE; X if (fd == -1) { X fd = open(name, update ? O_RDWR : O_WRONLY); X if (fd == -1 && errno == ENOENT) { X fd = creat(name, CREATMODE); X if (update && fd != -1 && (fd = close(fd)) != -1) X fd = open(name, O_RDWR); X } X } X if (fd != -1 && lseek(fd, 0L, SEEK_END) != -1) X break; X X default: X fd = -1; X } X X return fd; X} END_OF_FILE if test 1892 -ne `wc -c <'_fopen.c'`; then echo shar: \"'_fopen.c'\" unpacked with wrong size! fi # end of '_fopen.c' fi if test -f '_slot.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'_slot.c'\" else echo shar: Extracting \"'_slot.c'\" \(533 characters\) sed "s/^X//" >'_slot.c' <<'END_OF_FILE' X/* _ s l o t X * X * Locate the stream slot with the specified FILE pointer. If the X * pointer is NULL, this routine will locate the first free slot. X * The function will return a pointer to the slot, otherwise X * NULL. X * X * Patchlevel 1.0 X * X * Edit History: X */ X X#include "stdiolib.h" X X/*LINTLIBRARY*/ X XFILE **_slot(fp) X XFILE *fp; /* stream required */ X X{ X FILE **sp; /* slot in table */ X int n; /* number of slots */ X X for (n = _NFILE, sp = _iop; *sp != fp; sp++) X if (--n < 0) X return NULL; X X return sp; X} END_OF_FILE if test 533 -ne `wc -c <'_slot.c'`; then echo shar: \"'_slot.c'\" unpacked with wrong size! fi # end of '_slot.c' fi echo shar: End of archive 2 \(of 7\). cp /dev/null ark2isdone MISSING="" for I in 1 2 3 4 5 6 7 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 7 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0
trt@rti.UUCP (Thomas Truscott) (09/07/89)
From postnews Wed Sep 6 14:07:22 1989 > X * Cleanly close and flush all output buffers. This ensures that > X * all streams are written out and closed. ... > X for (i = 0; i < _NFILE; i++) > X if (_iop[i] != NULL) > X (void) fclose(_iop[i]); The last line above should instead be: > X (void) fflush(_iop[i]); The fclose() is an inefficiency dating back to the original stdio. Unless MINIX is strangely different from standard UN*X there is no need to *close* any files, one simply needs to ensure that all streams are written out. If you have a system that can trace system calls, it becomes painfully evident that virtually every command ends with: close(0); close(1); close(2); exit(0); There is no reason whatsoever for the close() calls! Further evidence: * I have changed the fclose to be fflush in various UN*X flavors, the first time was in 1980. Never a glitch. * I have posted flames such as this one (including to this very newsgroup a couple years ago), never a counterargument. I admit this is a minor inefficiency, and I should not be preoccupied with it, but the fix is so trivial that it is very frustrating that no one has bothered to apply it. HELP ME! Tom Truscott