Trailing-Edge
-
PDP-10 Archives
-
SRI_NIC_PERM_FS_1_19910112
-
kccdist/lib/usys/read.c
There are 10 other files named read.c in the archive. Click here to see a list.
/*
* READ - URT low-level I/O read
*
* Copyright (C) 1986 by Ian Macky, SRI International
*/
#include "c-env.h"
#include "sys/usysio.h"
#include "sys/usysig.h"
#include "sys/usytty.h"
#include "errno.h"
#if !(SYS_T20+SYS_10X)
#error read() not supported for this system.
#else
#include "jsys.h"
int
read(fd, buf, nbytes)
register int fd, nbytes;
register char *buf;
{
register int ufx, c, n;
int r, slowdev;
long old_count;
USYS_BEG();
if (fd < 0 || fd >= OPEN_MAX || !(ufx = _uioufx[fd]))
USYS_RETERR(EBADF);
if (nbytes < 1)
USYS_RETERR(EINVAL);
/* Check for and handle unconverted case */
if (!(_uioflgs[ufx] & _UIO_CONVERTED)) /* If not being converted */
for (;;) { /* Loop for interrupt continuation */
if ((n = insys(ufx, buf, nbytes)) > 0)
USYS_RET(n-1); /* Normally wins - note decrement! */
if (n == 0) /* Failed? */
USYS_RETERR(EIO);
/* Interrupted. n has negative of # bytes left to read.
** If we've read anything already, always return OK. Otherwise
** if nothing has been read, we try to continue rather than
** return EINTR.
*/
if ((r = nbytes + n) > 0) /* If anything was read */
USYS_RET(r); /* Return that much! */
/* Nothing whatsoever was read... */
if (USYS_END() < 0) { /* Allow ints, see if handler done */
errno = EINTR; /* Yeah, fail this way */
return -1; /* Return failure. */
}
/* Can proceed from interrupt! */
USYS_BEG(); /* Disable interrupts again */
if (ufx != _uioufx[fd]) /* Ensure FD still OK */
USYS_RETERR(EIO); /* Fail if switcheroo happened */
/* Nothing needs updating since nothing was read, just re-try. */
}
/* Converting input.
** Do hairy conversion loop so input CRLF sequences are furnished as LF.
** Need to be careful of slow devices that could hang up; if we're about
** to refill our UIO buffer but some converted chars were already read
** into the user buffer, we just return and don't even attempt to check
** the system input channel. So a refill happens only if using a fast
** device, or if the buffer was empty at start of the read().
*/
slowdev = (_uiotype[ufx] == _DVDSK) ? 0 : 1; /* Set flag if slow */
old_count = _uiocnt[ufx];
r = 1; /* Things OK so far */
n = 0; /* number of bytes actually read */
while (nbytes--) { /* while they want more bytes... */
if (--_uiocnt[ufx] < 0) { /* Get a char into c */
if (slowdev && n) /* If may hang and already got some */
break; /* then stop, don't try refill */
if ((r = in_filbuf(ufx,&old_count)) <= 1)
break;
else c = *_uiocp[ufx];
} else c = *++_uiocp[ufx];
if (c == '\r') { /* if a CR, see what follows. */
if (--_uiocnt[ufx] < 0) { /* Get a char into c */
if (slowdev && n) { /* If may hang and already got some */
_uiocnt[ufx]++; /* then put CR back! */
_uiocp[ufx]--;
break; /* then stop, don't try refill */
}
if ((r = in_filbuf(ufx,&old_count)) <= 1)
break;
else c = *_uiocp[ufx];
} else c = *++_uiocp[ufx];
if (c != '\n') { /* if it's NOT a LF */
_uiocnt[ufx]++; /* then put it back! */
_uiocp[ufx]--;
c = '\r'; /* (we had a CR originally) */
}
}
*buf++ = c; /* store the char we got */
n++;
}
_uiopos[ufx] += (old_count - _uiocnt[ufx]);
/* r has stop indicator. Pos means OK, counted out;
** 0 means I/O error, and -1 means interrupted. errno is already set.
*/
if (r > 0 /* Normal case -- return success */
|| (r < 0 && n > 0)) /* also win if interrupted but stuff read */
USYS_RET(n);
if (r == 0) /* If error, errno is already set */
USYS_RET(-1);
USYS_RETERR(EINTR); /* Otherwise was interrupted, nothing read */
}
/* IN_FILBUF
** fill the buffer; if no buffer has been assigned yet, make one.
** Returns:
** < 0 if interrupted, nothing was read.
** 0 if error
** 1 if EOF
** > 0 the number of characters (PLUS ONE) slurped in.
*/
static int
in_filbuf(ufx, aoldcnt)
register int ufx;
long *aoldcnt;
{
register int n;
if (_uioeof[ufx])
return 1;
if (!_uiopbuf[ufx] && (!(_uiopbuf[ufx]= _getbuf()))) {
errno = ENOMEM;
return 0;
}
_uiopos[ufx] += *aoldcnt;
_uiocnt[ufx] = 0;
for (;;) {
if ((n = insys(ufx, _uiopbuf[ufx], UIO_BUFSIZ)) > 0) {
--n;
break; /* Normally wins, drop out of loop */
}
if (n == 0) {
errno = EIO;
return 0;
}
/* Interrupted. n has negative of # bytes left to read.
** If we've read anything already, always return OK. Otherwise
** if nothing has been read, we try to continue rather than
** return EINTR.
*/
if ((n += UIO_BUFSIZ) > 0) /* Was anything read? */
break; /* Yes, n now has # bytes read! */
/* Nothing was read... */
if (USYS_END() < 0) { /* Allow ints, see if handler done */
errno = EINTR; /* Yeah, fail this way */
return -1; /* Return interrupt indicator */
}
/* Can proceed from interrupt! */
USYS_BEG(); /* Disable interrupts again */
if (!_uiopbuf[ufx]) { /* Ensure FD still OK */
errno = EIO; /* Fail if switcheroo happened */
return 0;
}
/* Nothing needs updating since nothing was read, just re-try. */
}
_uiocp[ufx] = _uiopbuf[ufx]; /* Set pointer to start of buffer */
*aoldcnt = n; /* Remember # bytes read (may be 0!) */
_uiocnt[ufx] = n; /* Set # of bytes now in buffer */
#if 1 /* Ugh. insys() already updated _uiopos, but caller wants to do it. */
_uiopos[ufx] -= n; /* Restore position value prior to insys() */
#endif
if (n > 0)
_uiocnt[ufx]--; /* Bump count down as if ugetc read char */
return n+1; /* Return # bytes read, plus 1 */
}
/* INSYS - system-dependent input.
** Returns:
** > 0 Won, value is # bytes read, PLUS ONE!!!
** = 0 Lost, some kind of error.
** < 0 Interrupted. Value is neg of # bytes LEFT to read.
*/
static int
insys(ufx, buf, cnt)
int ufx, cnt;
char *buf;
{
switch (_uiotype[ufx]) {
/* Superfast input devices which can do input using PMAP% to map
** data pages directly into our address space.
** This is only possible for DSK: really.
** PMAP input is not yet implemented.
*/
#if 0
case _DVDSK:
return inmap(ufx);
#endif
/* Fast input devices, which should always completely satisfy the
** input request (unless EOF or error).
*/
case _DVDSK:
return indev(SIN, ufx, buf, cnt);
/* Special TTY input devices, which may permit line editing */
case _DVTTY:
case _DVPTY:
return intty(ufx, buf, cnt);
/* Slow input devices, which may hang indefinitely and for which
** we always want to return the available input without waiting
** for more to fill out the count.
*/
default:
return in_slow(ufx, buf, cnt);
}
}
static int
indev(num, ufx, buf, cnt)
int num, ufx, cnt;
char *buf;
{
int i, n, acs[5];
acs[1] = _uioch[ufx]; /* JFN */
acs[2] = (int) (buf - 1); /* pointer to 1 before buffer */
acs[3] = -cnt; /* -# to read */
i = jsys(num, acs); /* Do it! */
n = cnt + acs[3]; /* Find # bytes read */
_uiopos[ufx] += n; /* Update count */
if (i > 0) {
if (n == 0) /* If call won, but nothing read, */
_uioeof[ufx] = -1; /* then say we're at EOF */
return n+1; /* Return N+1 so 0 looks winning. */
} else if (i < 0) /* Interrupted? */
return (acs[3] < 0 ? /* Yes, see if anything left to read */
acs[3] : n+1); /* return -N if so, else claim we won */
/* Call failed somehow... */
if (eofp(ufx)) { /* Was it EOF of some kind? */
_uioeof[ufx] = -1; /* Yes, set flag */
return n+1; /* And return win. */
}
errno = EIO;
return 0; /* Else return failure. */
}
/* IN_SLOW - system-dependent slow device input.
** Returns:
** > 0 Won, value is # bytes read, PLUS ONE!!!
** = 0 Lost, some kind of error.
** < 0 Interrupted. Value is neg of # bytes LEFT to read.
*/
static int
in_slow(ufx, buf, cnt)
int ufx, cnt;
char *buf;
{
int n, acs[5];
if (_uioeof[ufx])
return 1; /* Return EOF */
acs[1] = _uioch[ufx]; /* Get JFN */
switch (jsys(SIBE, acs)) { /* Anything to read? */
case 1:
if (acs[2] < cnt) /* Yes! AC2 has # available, read minimum */
cnt = acs[2];
if (cnt <= 0) /* Just in case SIBE% screws up... */
break;
return indev(SIN|JSYS_OKINT, ufx, buf, cnt);
case 2: /* No input available, ask for just one */
default: /* If error, we try BIN% anyway on the grounds that
** SIBE% is poorly supported; if there is really
** a problem with the JFN then BIN% will find it.
*/
break;
}
n = jsys(BIN|JSYS_OKINT, acs); /* Wait until we read 1 byte */
if (n < 0) /* Interrupted? */
return -cnt; /* Say interrupted, nothing read */
if (n == 0) { /* Error? */
if (eofp(ufx)) { /* Yes, was it EOF? */
_uioeof[ufx] = -1; /* If so, mark it */
return 1; /* and return EOF */
}
errno = EIO; /* Otherwise, set error # */
return 0; /* and return error indication */
}
/* Got a byte! Update things and see if there's any more input. */
_uiopos[ufx]++;
*buf++ = acs[2]; /* Store byte */
if (--cnt <= 0) /* Update count */
return 1+1;
switch (jsys(SIBE, acs)) { /* Want more, so check for more! */
default: /* If SIBE% lost, then SIBE% must be losing
** since the BIN% just won. Ignore the
** failure, and act as if no more input was available.
*/
case 2: /* No more input available */
break;
case 1: /* Still have more input! */
if (acs[2] < cnt) /* Set # to read */
cnt = acs[2];
if (cnt <= 0) /* SIBE% sometimes returns 0?? */
break;
n = indev(SIN|JSYS_OKINT, ufx, buf, cnt);
if (n > 0) n++; /* Account for the single byte we read */
return n;
}
return 1+1; /* Say read just 1 char (plus one) */
}
/* INTTY - system-dependent TTY input routine.
** Return values are same as for IN_SLOW.
*/
static int
intty(ufx, buf, cnt)
int ufx, cnt;
char *buf;
{
register struct _tty *tp;
tp = &_ttys[_uiodnum[ufx]]; /* Get ptr to TTY struct */
if (tp->tt_ufx != ufx) { /* Cross-check... */
errno = EIO;
return 0;
}
switch (tp->sg.sg_flags & (RAW|CBREAK)) { /* Determine mode */
case 0: /* Cooked mode */
return in_rdln(tp, ufx, buf, cnt);
case CBREAK: /* CBREAK mode */
default: /* RAW mode */
return in_slow(ufx, buf, cnt);
}
}
struct texti { /* Command block for TEXTI% */
int rdcwb; /* # words following in block */
int rdflg; /* Flag bits */
union { /* I/O designators - one word */
char *str; /* Input str */
struct { /* or two JFNs */
int in : 18;
int out: 18;
} jfn;
} rdioj;
char *rddbp; /* Where input should go */
int rddbc; /* # bytes available in buffer */
};
static int
in_rdln(tp, ufx, buf, cnt)
struct _tty *tp;
int ufx, cnt;
char *buf;
{
static struct texti /* for TEXTI */
textib = {4, RD_BEL|RD_CRF|RD_JFN|RD_BRK };
int i, acs[5];
if (_uioeof[ufx])
return 1; /* EOF, punt */
textib.rdioj.jfn.in = _uioch[ufx];
textib.rdioj.jfn.out = _uioch[ufx];
textib.rddbp = buf-1;
textib.rddbc = cnt;
acs[1] = (int) &textib;
i = jsys(TEXTI|JSYS_OKINT, acs);
if (i == 0) {
if (eofp(ufx)) {
_uioeof[ufx] = -1;
return (cnt - textib.rddbc)+1; /* Return # read, plus 1 */
}
errno = EIO;
return 0;
}
if (i < 0) { /* Interrupted? */
if (textib.rddbc) /* If any chars unread, */
return -textib.rddbc; /* return # unread. */
} /* Else drop thru for normal return! */
/* Won normally */
if (*textib.rddbp == ('Z'&037)) { /* Stopped on ^Z? */
textib.rddbc++; /* Yes, don't count as input */
_uioeof[ufx] = -1; /* Say EOF seen */
}
return (cnt - textib.rddbc)+1; /* Return # chars read, plus 1 */
}
/* EOFP(jfn)
* given a JFN in AC1 return 0 (in AC1) if there's no EOF on that
* JFN, else 1 if there is.
*/
static int
eofp(ufx)
int ufx;
{
int acs[5];
acs[1] = _uioch[ufx];
jsys(GTSTS, acs); /* Always succeeds */
return acs[2]&GS_EOF; /* Return state of EOF bit */
}
#endif /* T20/10X */
#if 0 /* OLD STUFF */
#if SYS_T20+SYS_10X
#include <urtio.h>
int read(f, buf, n)
char *buf;
{
if (_uioch[f] < 1 || n < 1) /* check channel and byte count */
return -1;
return _read(_uioch[f], buf, n); /* do low level read */
}
int iread(f, buf, n) /* image-mode read */
int *buf;
{
if (_uioch[f] < 1 || n < 1)
return -1;
return _read(_uioch[f], 04400000000|(int)buf, n);
}
static int _read();
#asm
; ****************************************************************
;
; nread = read(fildes, buffer, nbytes)
; char *buffer;
;
; nread == 0 for EOF, -1 for other error
; ****************************************************************
SEARCH MONSYM
.read: MOVE 1,-1(17) /* Get JFN */
%CHRBP 2,-2(17) /* Point to prev byte of buffer */
MOVN 3,-3(17) /* Negate count (no term byte) */
SIN% /* Read in the string */
ERJMP .read2 /* Error, see if eof */
.read1: MOVE 1,3 /* Ok, just get count */
ADD 1,-3(17) /* Calculate number of chars read */
POPJ 17,
.read2: MOVEI 1,.FHSLF /* On self */
GETER% /* See what error we got */
HRRZ 2,2 /* Just look at error condition */
CAIN 2,IOX4 /* End of file? */
JRST .read1 /* Yes, just return num chars read */
SETO 1, /* No, set retval to -1 for error */
POPJ 17, /* And return with it */
#endasm
#endif /* T20+10X */
#if SYS_WAITS
/* -------------- */
/* read */
/* -------------- */
read(f,buf,n)
char *buf;
{
int chan;
int i,k,m;
char *c;
struct bufhead *p;
if ((chan=_uioch[f]) == 1 || n < 0) return -1;
if (!chan) { /* tty input */
if (_uioeof) return 0;
for (i = 0; n-- ; i++) {
*buf = _getln();
if (!*buf++) {
_uioeof = 1;
break;
}
}
return i;
}
p = &buffers[chan];
c = p->user;
i = p->count;
m = 0;
k = n;
while (n--) {
if (i <= 0) {
if (!_in(chan)) {
p->count = 0;
return m;
}
c = p->user;
i = p->count;
}
*buf++ = *++c;
i--;
m++;
}
p->user = c;
p->count = i;
return k;
}
/* ------------------- */
/* byte read */
/* ------------------- */
bread(f,buf,n)
char *buf;
{
int chan;
int i,k,m, save, *addr;
char *c;
struct bufhead *p;
if ((chan=_uioch[f]) == 1 || n < 0) return -1;
if (!chan) { /* tty input */
if (_uioeof) return 0;
for (i = 0; n-- ; i++) {
*buf = _getty();
if (!*buf++) {
_uioeof = 1;
break;
}
}
return i;
}
p = &buffers[chan];
save = p->user;
save++;
c = (save & 0777777) | (0341000<<18);
c--;
i = p->count*4;
m = 0;
k = n;
while (n--) {
if (i <= 0) {
if (!_in(chan)) {
p->count = 0;
return m;
}
save = p->user;
save++;
c = (save & 0777777) | (0341000<<18);
c--;
i = p->count*4;
}
*buf++ = *++c;
i--;
m++;
}
chan = c;
p->user = (chan & 0777777) | (save & (0777777<<18));
p->count = i/4;
return k;
}
/* ------------------------- */
/* image mode read */
/* ------------------------- */
iread(f,buf,n)
char *buf;
{
int chan;
int i,k,m, save, *addr;
char *c;
struct bufhead *p;
if ((chan=_uioch[f]) == 1 || n < 0) return -1;
if (!chan) { /* tty input */
if (_uioeof) return 0;
for (i = 0; n-- ; i++) {
*buf = _getty();
if (!*buf++) {
_uioeof = 1;
break;
}
}
return i;
}
p = &buffers[chan];
i = p->count;
m = 0;
k = n;
while (n--) {
if (i <= 0) {
if (!_in(chan)) {
p->count = 0;
return m;
}
i = p->count;
}
*buf++ = *++p->user;
i--;
m++;
}
p->count = i;
return k;
}
static _getty(), _getln(), _in();
#asm
; ************************************************************
; read a character from the tty
; ************************************************************
;
.GETTY: INCHRW 1
POPJ 17,
; ************************************************************
; read a character from the tty, line edit mode
; ************************************************************
;
.GETLN: INCHWL 1
POPJ 17,
; ************************************************************
; input buffer (chan #, bufptr)
; ************************************************************
;
.IN: MOVE 1,-1(17)
ANDI 1,17
LSH 1,27 ; shift channel # into ac field
IOR 1,[IN 0,0]
MOVEM 1,.+1
IN 0,0
JRST $RETT ; no error
JRST $RETF ; error
#endasm
#endif /* WAITS */
#if SYS_ITS
/* Misc I/O support stuff */
#asm
; read(fd, bufp, n)
; Do in units of words
IREAD: SKIPN 2,-2(17)
JRST $RETN ; Bad address
HRLI 2,444400
JRST READ2
READ: %CHRBP 2,-2(17) ; Get buffer ptr
READ2: SKIPG 3,-3(17)
JRST $RETN ; No count
SKIPGE 1,-1(17) ; Get FD
JRST $RETN
.CALL [ SETZ
SIXBIT /SIOT/
.CH(1) ; Channel # from table
2 ; Byte ptr to source
SETZ 3] ; Count of bytes
JRST $RETN ; Failed
MOVE 1,-1(17)
SUB 1,3 ; Return # bytes read/written
POPJ 17,
#endif /* ITS */
#endif /* Commented-out stuff */