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 0trt@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