Trailing-Edge
-
PDP-10 Archives
-
SRI_NIC_PERM_FS_1_19910112
-
c/old/lib/stdio.c
There is 1 other file named stdio.c in the archive. Click here to see a list.
/* <KCC.LIB>STDIO.C.47, 8-Aug-85 12:15:22, Edit by KRONJ */
/* Clean up so writing '\0' as first char of file works */
/* <KCC.LIB>STDIO.C.46, 8-Jul-85 14:50:15, Edit by KRONJ */
/* Had _IOEOF and _IOERR swapped when setting codes for losing read */
/* <KCC.LIB>STDIO.C.36, 1-Mar-85 00:31:02, Edit by SATZ */
/* Teach freopen about modes 'a', 'A', and 'c' */
/*
** stdio - standard I/O for TOPS-20 and WAITS, per K&R and the UNIX manual
*/
entry _iob, fgets, fopen, freopen, fputs, fclose, uopen;
entry fflush, getc, fgetc, ungetc, putc, fputc, _putc, fread, fwrite;
#include "c-env.h" /* Set up sys config definitions */
#include <stdio.h> /* use standard I/O defs */
#define PMODE 0 /* let directory supply protection */
#define _IMAGE 01000 /* 36-bit image mode file */
#define _FIRST 02000 /* first read of file, for E files */
#define _BYTE 04000 /* 8-bit files */
#define _EFILE 010000 /* E editor file (WAITS) */
#define MAXFILE 32 /* must match defn in RUNTM */
/* ------------------------------------- */
/* file structure [ref. p.165] */
/* ------------------------------------- */
FILE _iob[_NFILE] = {
{ NULL, 0, NULL, _IOREAD + _IONBF, 0 }, /* stdin */
{ NULL, 0, NULL, _IOWRT + _IONBF, 1 }, /* stdout */
{ NULL, 0, NULL, _IOWRT + _IONBF, 2 } /* stderr */
};
static struct {
char body[BUFSIZ];
int use;
} _bigbuf[_NFILE];
static char _smallbuf[MAXFILE];
/* ----------------------------------------------- */
/* stdio called at runtime initialization */
/* ----------------------------------------------- */
static _stdio = stdio(); /* make sure called by runtimes */
extern (*_sexit)(); /* routine to call for stdio exit */
static stdio ()
{
int i, sexit();
for (i = 0 ; i < _NFILE ; i++) _bigbuf[i].use = 0;
for (i = 3 ; i < _NFILE ; i++) _iob[i]._flag = 0;
stdout->_cnt = 0;
stderr->_cnt = 0;
_sexit = sexit; /* set up to fix stdio on exit */
}
/* ------------------------------ */
/* open buffered file */
/* [ref. p.151] */
/* ------------------------------ */
FILE *fopen (name, mode)
char *name, *mode;
{
FILE *freopen();
int i;
for (i=3 ; i < _NFILE ; i++)
if (!(_iob[i]._flag & (_IOREAD|_IOWRT)))
return freopen(name, mode, &_iob[i]);
fputs ("No I/O buffer left.\n", stderr);
return NULL;
}
FILE *freopen (name, mode, fp)
char *name, *mode;
FILE *fp;
{
int i, m, n, fd, flag;
if (fp->_flag & (_IOREAD | _IOWRT)) fclose(fp);
m = mode[0];
n = mode[1];
if (n != '\0' && n != 't' &&
m != 'r' && m != 'w' && m != 'a' && m != 'R' && m != 'W' &&
m != 'A' && m != 'i' && m != 'o' && m != 'c') {
fprintf(stderr, "illegal mode %s opening %s\n", mode, name);
sexit (1);
}
switch (m) {
case 'r':
fd = open (name, 0);
flag = _IOREAD | _FIRST;
break;
case 'R':
fd = bopen (name, 0);
flag = _IOREAD | _BYTE;
break;
case 'i':
fd = iopen (name, 0);
flag = _IOREAD | _IMAGE;
break;
case 'w':
fd = creat (name, PMODE);
flag = _IOWRT;
break;
case 'W':
fd = bcreat (name, PMODE);
flag = _IOWRT | _BYTE;
break;
case 'o':
fd = icreat (name, PMODE);
flag = _IOWRT | _IMAGE;
break;
case 'a':
fd = _cfile(name, PMODE, 7, 1);
flag = _IOWRT;
break;
case 'A':
fd = _cfile(name, PMODE, 8, 1);
flag = _BYTE | _IOWRT;
break;
case 'c':
fd = _cfile(name, PMODE, 36, 1);
flag = _IMAGE | _IOWRT;
break;
}
if (fd <= 0) return NULL;
fp->_file = fd;
fp->_cnt = 0;
fp->_base = NULL;
fp->_flag = flag;
return (fp);
}
/* ---------------------------------------- */
/* open unbuffered file */
/* same as fopen but unbuffered */
/* ---------------------------------------- */
FILE *uopen (name, mode)
char *name, *mode;
{
FILE *fp;
fp = fopen(name, mode); /* open in unbuffered mode */
if (fp != NULL) fp->_flag |= _IONBF; /* remember unbuffered */
return fp;
}
/* --------------------------------------- */
/* flush output to buffered file */
/* --------------------------------------- */
fflush (fp)
FILE *fp;
{
char *p;
int i;
_flushbuf (fp); /* write buffer contents */
p = fp->_base; /* get pointer to buffer */
if (p != NULL) for (i=0 ; i < _NFILE ; i++) { /* looking through buffers */
if (_bigbuf[i].body == p) { /* if it's this one */
_bigbuf[i].use = 0; /* it's no longer in use */
break; /* stop looking */
}
}
fp->_base = NULL; /* no longer have a buffer */
fp->_cnt = 0; /* no chars in our nonexistent buf */
}
/* ---------------------------- */
/* close buffered file */
/* [ref. p.153] */
/* ---------------------------- */
fclose (fp)
FILE *fp;
{
fflush(fp);
close (fp->_file);
fp->_flag = 0;
}
/* ------------------------------ */
/* close files and exit */
/* ------------------------------ */
static sexit (n)
{
int i;
for (i=0 ; i < _NFILE ; i++) fflush(&_iob[i]);
}
/* ------------------------------------ */
/* get character from buffer */
/* [ref. p.166] */
/* ------------------------------------ */
fgetc (fp)
FILE *fp;
{
return getc(fp);
}
getc (fp)
FILE *fp;
{
int i;
if (--fp->_cnt < 0) return _fillbuf (fp); /* none left, get more */
i = *fp->_ptr++; /* get the char */
if (i == '\r' && !(fp->_flag & (_BYTE + _IMAGE))) {
i = getc (fp); /* CR, look for LF */
if (i != '\n') { /* if not LF */
ungetc (i, fp); /* then put it back */
return '\r'; /* and return the CR */
}
}
#if SYS_WAITS
if (i == '\0' && (fp->_flag & _EFILE)) {
while (*fp->_ptr == '\0' && --fp->_cnt >= 0) fp->_ptr++;
return getc(fp);
}
#endif
return i;
}
/* ------------------------------- */
/* pushback a character */
/* ------------------------------- */
ungetc (x, fp)
FILE *fp;
{
if (fp->_base == NULL) { /* any buffer there? */
__findbuf (fp); /* no, get one */
fp->_cnt = 0; /* no chars there now */
}
if (fp->_cnt > 0) fp->_ptr--; /* protect following data */
else fp->_ptr = fp->_base; /* none there, go to top of buf */
fp->_cnt++; /* remember we have another char */
*fp->_ptr = x; /* set the char */
}
/*
** Output character to buffer
**
** Takes care of adding a CR before every LF for text files,
** and passes the character on to _putc().
*/
fputc (x, fp)
FILE *fp;
{
putc (x, fp);
}
putc (x, fp)
FILE *fp;
{
if (x == '\n' && !(fp->_flag & (_BYTE + _IMAGE))) _putc('\r', fp);
_putc(x, fp);
}
/*
** putc() without CRLF conversion
**
** Does actual dealings of putting char in buffer,
** emptying buffer when full, etc.
**
** All I/O goes a character at a time through here, so it better be efficient.
*/
_putc (x, fp)
FILE *fp;
{
if (fp->_cnt-- > 0) { /* space in buffer? */
*fp->_ptr++ = x; /* just add char */
return;
}
if (fp->_flag & _IONBF) { /* no space, maybe unbuffered? */
_bout (x, fp); /* yes, go do it this way */
return;
}
fp->_cnt++; /* buffered but no space, fix count */
_flushbuf (fp); /* and send filled buffer */
_putc (x, fp); /* now try again */
}
/*
** Send unbuffered character off
**
** Separate from _putc to not confuse KCC peephole
** optimizer with address of argument in buffered case.
*/
static _bout (x, fp)
char x;
FILE *fp;
{
write (fp->_file, &x, 1); /* and send char directly */
fp->_cnt = 0; /* set count for next putc */
}
/* -------------------- */
/* get line */
/* [ref. p.155] */
/* -------------------- */
char *fgets (line, maxline, fp)
FILE *fp; char *line;
{
int i, c;
char *l;
l = line;
for (i=1 ; i < maxline ; i++) {
if ((c=getc (fp)) == EOF) {
line = NULL;
break;
}
if ((*l++ = c) == '\n') break;
}
*l = 0;
return line;
}
/* ----------------------- */
/* output string */
/* [ref. p.155] */
/* ----------------------- */
fputs (s, fp)
char *s;
FILE *fp;
{
while (*s) putc (*s++, fp);
}
/*
** Flush buffered file output [ref. p.166]
**
** We used to pass the char to be output here, or a zero for no char;
** but that turns out to lose in the case that we want to output a zero.
** So now we make _putc() do its own cleanup.
*/
static _flushbuf (fp)
FILE *fp;
{
if ((fp->_flag & _IONBF) || !(fp->_flag & _IOWRT)) return; /* chk write */
if (fp->_base == NULL) __findbuf (fp); /* no buf, get one */
else if (fp->_cnt != BUFSIZ) {
#if SYS_WAITS /* WAITS has several write routines */
if (fp->_flag & _BYTE)
bwrite (fp->_file, fp->_base, BUFSIZ - fp->_cnt);
else if (fp->_flag & _IMAGE)
iwrite (fp->_file, fp->_base, BUFSIZ - fp->_cnt);
else if (write (fp->_file, fp->_base, BUFSIZ - fp->_cnt) < 0)
fp->_flag |= _IOERR;
#else
if (write (fp->_file, fp->_base, BUFSIZ - fp->_cnt) < 0)
fp->_flag |= _IOERR;
#endif
}
fp->_ptr = fp->_base;
fp->_cnt = BUFSIZ;
}
/* ------------------------------------------ */
/* fill buffer and return character */
/* ------------------------------------------ */
static _fillbuf (fp)
FILE *fp;
{
if (!(fp->_flag & _IOREAD) || (fp->_flag & (_IOEOF|_IOERR))) return EOF;
if (fp->_base == NULL) __findbuf (fp);
fp->_ptr = fp->_base;
#if SYS_WAITS /* WAITS: diff depending on mode */
if ((fp->_flag & _BYTE) && !(fp->_flag & _IONBF))
fp->_cnt = bread (fp->_file, fp->_base, BUFSIZ);
else if (fp->_flag & _IMAGE)
fp->_cnt = iread (fp->_file, fp->_base,
(fp->_flag & _IONBF)? 1 : BUFSIZ);
else fp->_cnt = read (fp->_file, fp->_base,
(fp->_flag & _IONBF)? 1 : BUFSIZ);
if (fp->_flag & _FIRST) { /* check for E directory */
fp->_flag &=~ FIRST; /* but only on first page */
if (fp->_cnt >= 9 && _efile (fp->_base)) {
fp->_ptr = fp->_base; /* start at buffer beginning */
while (*fp->_ptr++ != 014) { /* look for formfeed */
if (--fp->_cnt <= 0) { /* refilling when necessary */
fp->_cnt = read(fp->_file, fp->_base, BUFSIZ);
if (fp->_cnt <= 0) { /* error of some sort */
fp->_flag |= _IOERR; /* remember so in fp */
fp->_cnt = 0; /* fix up count */
return EOF; /* return lossage */
} else fp->_ptr = fp->_base; /* otherwise reset to start */
}
}
fp->_flag |= _EFILE; /* this is an E file */
return getc (fp); /* chain back to getc */
}
}
#else /* TOPS20/TENEX/ITS */
fp->_cnt = read (fp->_file, fp->_base, (fp->_flag & _IONBF) ? 1 : BUFSIZ);
#endif
if (fp->_cnt <= 0) {
fp->_flag |= (fp->_cnt == 0 ? _IOEOF : _IOERR);
fp->_cnt = 0;
return EOF;
}
return getc (fp); /* finish up for getc() */
}
/*
** See if we have an E format file (WAITS only)
**
** E files start with "COMMENT (x)", so we do a simple compare against that.
** We might be fooled by a null in the file, but let's not worry about it.
*/
#if SYS_WAITS
static _efile (t)
char *t;
{
char *s = "COMMENT " - 1; /* get ILDB ptr to string */
--t; /* prepare other ptr for ILDB loop */
while (*++s == *++t) ; /* compare against "COMMENT " */
return (*s == '\0' && *t == 026); /* next char in buff should be splat */
}
#endif
/* ----------------------------- */
/* find buffer for I/O */
/* ----------------------------- */
static __findbuf (fp)
FILE *fp;
{
int flag, i;
if (fp->_flag & _IONBF) { /* unbuffered? */
fp->_base = &_smallbuf[fp->_file]; /* yes, one char buf for ungetc */
return; /* that's all */
}
for (i=3 ; i < _NFILE ; i++) if (_bigbuf[i].use == 0) break; /* find buf */
if (i < _NFILE) { /* if found one */
fp->_flag |= _IOLBF; /* remember that */
fp->_base = _bigbuf[i].body; /* set buffer */
_bigbuf[i].use = 1; /* remember that buffer now in use */
} else {
fp->_flag |= _IONBF; /* couldn't find one, run unbuffered */
fp->_base = &_smallbuf[fp->_file]; /* set ungetc buffer */
}
}
/* ---------------------------- */
/* file stream read */
/* ---------------------------- */
fread(ptr, size, count, iop)
char *ptr;
unsigned size, count;
FILE *iop;
{
int ch;
unsigned done = 0, s;
if (size > 0)
for ( ; done < count; done++) {
s = 0;
while (s++ < size)
if ((ch = getc(iop)) >= 0)
*ptr++ = ch;
else
return (done);
}
return (done);
}
/* ---------------------------- */
/* file stream write */
/* ---------------------------- */
fwrite(ptr, size, count, iop)
char *ptr;
unsigned size, count;
FILE *iop;
{
unsigned done = 0, s;
if (size > 0)
for ( ; done < count; done++) {
for (s = 0; s < size; s++)
putc(*ptr++, iop);
if (ferror(iop))
break;
}
return (done);
}