Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_FS_1_19910112 - c/lib5/usys/new/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/uio.h"
#include "errno.h"
#if !(SYS_T20+SYS_10X)
#error read() not supported for this system.
#else
#include "jsys.h"

#define ugetc(ufx, c)	if (_uiocnt[ufx]-- <= 0) { \
    			    if ((r = _uiofilbuf(ufx)) <= 0) break; \
			    else (c) = *_uiocp[ufx]; \
			} else (c) = *++_uiocp[ufx];

#define uungetc()	{ _uiocnt[ufx]++; _uiocp[ufx]--; }

static long old_count;		/* global meant for this module */
static int _map();		/* do the actual PMAP of a file */
int read(fd, buf, nbytes)
register int fd, nbytes;
register char *buf;
{
    int ufx, c, r, n;

    if (fd < 0 || fd >= OPEN_MAX || !(ufx = _uioufx[fd])) {
	errno = EBADF;
	return -1;
    } else if (nbytes < 1) {
        errno = EINVAL;
	return -1;
    } else if (!(_uioflgs[ufx] & _UIO_CONVERTED)) {
	if ((n = _uioslurp(ufx, buf, nbytes)) == -1) {
	    errno = EIO;
	    return -1;
	}
	_uiopos[ufx] += n;
	return n;
    } else if (_uiotype[ufx] == _DVTTY) {	/* reading from a TTY */
	if ((n = _readln(ufx, buf, nbytes)) == -1) {
	    errno = EIO;
	    return -1;
	}
	_uiopos[ufx] += n;
	return n;
    } else {
	old_count = _uiocnt[ufx];
	n = 0;	    	    	    	/* number of bytes actually read */
	while (nbytes--) {		/* while they want more bytes... */
	    ugetc(ufx, c);		/* get a char into c */
	    if (c == '\r') {		/* if a CR, */
		ugetc(ufx, c);		/* see what follows. */
		if (c != '\n') {	/* if it's NOT a LF */
		    uungetc();		/* then put it back! */
		    c = '\r';		/* (we had a CR originally) */
		}
	    }
	    *buf++ = c;			/* store the char we got */
	    n++;
	}
	_uiopos[ufx] += (old_count - _uiocnt[ufx]);
	return n;
    }
}
/*
 *	fill the buffer; if no buffer has been assigned yet, make one.
 *  	returns -1 on I/O error, 0 on EOF, else the number of characters
 *  	slurped in.
 */

static int _uiofilbuf(ufx)
register int ufx;
{
    if (_uioeof[ufx]) return 0;		/* at EOF */
    if (_uiotype == _DVDSK)		/* if reading from a disk, */
	return _uiomapbuf(ufx);		/* then do disk-mapping. */
    if (!_uiopbuf[ufx] && (!(_uiopbuf[ufx] = (char *) malloc(UIO_BUFSIZ)))) {
	errno = ENOMEM;
	return -1;
    }
    _uiopos[ufx] += old_count;
    if ((_uiocnt[ufx] = _uioslurp(ufx, _uiopbuf[ufx], UIO_BUFSIZ)) == -1) {
	errno = EIO;
	return -1;
    }
    old_count = _uiocnt[ufx]--;
    _uiocp[ufx] = _uiopbuf[ufx];
    return _uiocnt[ufx];
}

/*
 *	need a new hunk of file, so map it in.
 */

static int _uiomapbuf(ufx)
{
    int next_page, bi, n;

    next_page = _uiolfp[ufx];			/* last page is here. */
    if (!(_uioflgs[ufx] & _UIO_NEW_POS))	/* at a new place in file */
	next_page += BLOCK_SIZE;		/* not first, so advance */
    if ((bi = _uiobi[ufx]) >= 0) {		/* if have a current buf, */
	_uiofp[ufx][bi] = -1;			/* mark finished this buffer */
	_uioiu[ufx]--;				/* & one less buffer in use */
    }
    n = _uiomap(ufx, next_page);		/* map in what we need next */
    if (n == -1) return -1;			/* oops, failed to! */
    bi = _uiobi[ufx];				/* get used Buffer Index */
    if (_uioflgs[ufx] & _UIO_PRE_READ)
	while (_uioiu[ufx] < N_BUFFERS) {
	    next_page += BLOCK_SIZE;		/* step to next hunk */
	    if (_uiomap(ufx, next_page) == -1)	/* slots, fill them.
		return -1;			/* failed to map hunk. */
	}
    _uiocnt[ufx] = n * PAGE_SIZE_INT * 5;
    _uiocp[ufx] = (_KCCtype_char7 *) (int *) (_uiopm[ufx][bi] * PAGE_SIZE_INT);
    _uioflgs[ufx] &= ~_UIO_NEW_POS;		/* not new pos anymore! */
    return _uiocnt[ufx];
}
/*
 *	map in a block starting at the given page#.  selects which slot
 *	to use and pre-reads it, returning 
 *	page# on success, -1 on error.
 */

int _uiomap(ufx, page)
int ufx, page;
{
    int bi, i, buf, n;

    for (i = 0; i < N_BLOCKS; i++)		/* let's see if we already */
	if (_uiofp[ufx][i] == page)		/* have the needed hunk of */
	    return page;			/* file.   yes, we do! */
    for (bi = i = 0; i < N_BLOCKS && !bi; i++)	/* no, so find a free slot. */
	if (_uiofp[ufx][i] == -1)		/* if a free slot, use it.  */
	    bi = i;				/* if none free, use slot 0 */
    if ((buf = _uiopm[ufx][bi]) == -1) {	/* have a buffer yet? */
	if (!(buf = _palloc(BLOCK_SIZE)));	/* no, so get a buffer. */
	    errno = ENOMEM;			/* failed, must be out of */
	    return -1;				/* memory.  ret -1 on error */
	}
	_uiopm[ufx][bi] = buf;			/* have a buf now, save pag# */
    }
    n = _map(ufx, page, buf, BLOCK_SIZE);	/* map in the hunk now */
    if (!n) {					/* didn't get any pages? */
	errno = EIO;				/* failed to map in file */
	return -1;				/* -1 on error */
    }
    _uiofp[ufx][bi] = page;			/* first file page of map */
    _uioiu[ufx]++;				/* one more buffer in use */
    _uiobi[ufx] = bi;				/* save Buffer Index here */
    return n;					/* return the # pages read */
}

static int _map(ufx, f_page, m_page, n)
int ufx, f_page, m_page, n;
{
    int ablock[5];

    ablock[1] = (_uioch[ufx] << 18) + f_page;		/* jfn,,file page */
    ablock[2] = (_FHSLF << 18) + m_page;		/* us,,mem page */
    ablock[3] = (n << 18) | PM_CNT | PM_PRD | PM_RD;	/* count, pre-read */
    jsys(PMAP, ablock);					/* do it! */
    return n - (ablock[3] >> 18);		/* ret # pages really read */
}
/*
 *	_uioslurp(ufx, buf, nbytes)
 *	int ufx, nbytes;
 *	char *buf
 */

static int _uioslurp(ufx, buf, nbytes)
int ufx, nbytes;
char *buf;
{
#asm
	EXTERN .UIOTYPE

	SEARCH MONSYM

	move 1,-1(17)			;get UFX
	move 1,.uiotype(1)		;get device type
	cail 1,0			;make sure it's
	  caile 1,devmax		;  valid,
	    jrst .slrpz			;    then
	jrst @devdsp(1)			;go handle that device

devdsp:	setz .slurp			;0 = disk
	setz .slrpz			;1 = unassigned
	setz .slurp			;2 = magtape
	setz .slrpz			;3 = unassigned
	setz .slrpz			;4 = unassigned
	setz .slrpz			;5 = unassigned
	setz .slrpz			;6 = unassigned
	setz .slrpz			;7 = unassigned
	setz .slurp			;10 = card reader
	setz .slurp			;11 = FE psuedo-device
	setz .readln			;12 = terminal
	setz .readln			;13 = pseudo-terminal
	setz .slrpz			;14 = unassigned
	setz .slurp			;15 = null device
devmax==.-devdsp-1	
/*
 *	generic device slurper
 */
	EXTERN .uioch		; Not otherwise referenced, so declare here.

.slrpz:		; Unknown devices come to this label -- same as generic slurp.

.slurp:	move 1,-1(17)			;get UFX
	skipe .uioeof(1)		;eof on channel?
	  jrst uslrpz			;  yeah, so return with nuttin
	move 1,.uioch(1)		;get JFN
	%CHRBP 2,-2(17)			;get CP to buf (one before, really)
	movn 3,-3(17)			;# of chars
#undef SIN	/* Avoid lossage */
uiosl0:	SIN%				;sssssssSSSSUck
	  erjmp uslrpe			;  got an error!
uslrp0:	move 1,-3(17)
	add 1,3				;# of characters really slurped
	caml 1,-3(17)			;get fewer then asked for?
	  popj 17,			;  naw, just right, peachy keeno
	move 2,-1(17)			;yes so (assume) hit EOF
	setom .uioeof(2)		;set the EOF flag for channel
	popj 17,    	    	    	;return count read anyway

uslrpe:	pushj 17,eofp			;was it an EOF we got?
	  jrst uslrp0	    	    	;  yep, nothing special needed
uslrpz:	seto 1,				;else return a -1 on other errors
	popj 17,

eofp:	movei 1,.fhslf
#undef GETER
	GETER%				;See what error we got
	tlz 2,-1			;just want error code
	caie 2,IOX4			;EOF?
	  aos (17)			;  no, skip return
	popj 17,			;yes, take +1 return
#endasm
}	/* End of _uioslurp() */
#if SYS_T20
/*
 *	readln(fd, buf, nbytes)
 *	int fd, nbytes;
 *	char *buf;
 *
 *	reads a line of text from the terminal, with editing.
 */

int readln(fd, buf, nbytes)
int fd, nbytes;
char *buf;
{
    if (fd < 0 || fd > OPEN_MAX || !_uioufx[fd]) {
	errno = EBADF;
	return -1;
    }
    return _readln(_uioufx[fd], buf, nbytes);
}

static int _readln(ufx, buf, nbytes)
int ufx, nbytes;
char *buf;
{
#asm
	move 1,-1(17)			;get UFX
	skipe .uioeof(1)		;eof on channel?
	  jrst rlnerz			;  yeah, so punt
	hrr 1,.uioch(1)			;get JFN 
	hrls 1				;JFN,,JFN
	movem 1,textib+.RDIOJ
	%CHRBP 1,-2(17)			;point to one before given BP
	movem 1,textib+.RDDBP		;where to put string
	move 1,-3(17)			;count
	movem 1,textib+.RDDBC
	movei 1,textib
	TEXTI%
	  erjmp rlnerr
	ldb 1,textib+.RDDBP		;get char which broke
	caie 1,"Z"-100			;control-z?
	  jrst .rln1			;  nah
	aos textib+.RDDBC		;yes, but don't count it as input!
.rln0:	move 2,-1(17)			;get UFX
	setom .uioeof(2)		;set eof flag for channel
.rln1:	move 1,-3(17)
	sub 1,textib+.RDDBC		;# characters stored
	popj 17,

rlnerr:	pushj 17,eofp			;error was eof?
	  jrst .rln0			;  yeah, so sorta ignore
	movei 1,EIO			;generic error
	movem 1,errno			;store in global location
rlnerz:	seto 1,				;else return a 0 on other errors
	popj 17,

textib:	.RDDBC				;# words following this word
	RD%BEL+RD%CRF+RD%JFN+RD%BRK	;.RDFLG: flag bits
	0				;.RDIOJ: input JFN, output JFN
	0				;.RDDBP: destination BP
	0				;.RDDBC: destination buffer size
#endasm
}	/* End of _readln() */
#endif /* T20 */
#endif	/* T20+10X */
#if 0	/* OLD STUFF */
#if SYS_T20+SYS_10X

entry readln;

#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

static int readln();
#asm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	readln(f, buf, nbytes)
;;	int f, nbytes;
;;	char *buf;
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

textib:	.RDDBC				/* # words following this word */
	RD%BEL+RD%CRF+RD%JFN		/* .RDFLG: flag bits */
	0				/* .RDIOJ: input JFN, output JFN */
	0				/* .RDDBP: destination BP */
	0				/* .RDDBC: destination buffer size */

readln:	move 1,-1(17)			/* get FD */
	hrrz 1,.uioch(1)		/* look up JFN for that FD */
	hrls 1				/* JFN,,JFN */
	movem 1,textib+.RDIOJ
	%CHRBP 1,-2(17)			/* point to one before given BP */
	movem 1,textib+.RDDBP		/* where to put string */
	move 1,-3(17)			/* count */
	movem 1,textib+.RDDBC
	movei 1,textib
	TEXTI%
	  erjmp .read2
	move 1,-3(17)
	sub 1,textib+.RDDBC		/* # characters stored */
	popj p,
#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 */