Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_FS_1_19910112 - kccdist/lib/usys/write.c
There are 9 other files named write.c in the archive. Click here to see a list.
/*
 *	WRITE - URT low-level I/O write
 *
 *	Copyright (C) 1986 by Ian Macky, SRI International
 */

#include "c-env.h"
#include "signal.h"		/* for SIGXFSZ */
#include "sys/usysio.h"
#include "sys/usysig.h"
#include "errno.h"
#if SYS_T20
#include "jsys.h"
#endif

static int outsys();
int
write(fd, buf, nbytes)
register int fd, nbytes;
register char *buf;
{
    register int ufx, n, i;
    register char *cp;
    char *bufp;
    char cbuf[UIO_BUFSIZ];	/* Temporary conversion buffer on stack */
    int ncvt;

    USYS_BEG();
    if (fd < 0 || fd >= OPEN_MAX || !(ufx = _uioufx[fd]))
	USYS_RETERR(EBADF);
    if (nbytes == 0)
	USYS_RET(0);
    if (nbytes < 0)
        USYS_RETERR(EINVAL);

    /* Check for and handle unconverted case */
    if (!(_uioflgs[ufx] & _UIO_CONVERTED)) {
	for (;;) {			/* Loop for interrupt continuation */
	    if ((n = outsys(ufx, buf, nbytes)) > 0)
		USYS_RET(n);		/* Normally wins */
	    if (n == 0)			/* Failed? */
		USYS_RETERR(EIO);
	    /* Interrupted.  n has negative of # bytes left to write. */
	    if (USYS_END() < 0) {	/* Allow ints, see if handler done */
		errno = EINTR;		/* Yeah, fail this way */
		return nbytes + n;	/* Return # of bytes written. */
	    }
	    /* Can proceed from interrupt!  Update things... */
	    USYS_BEG();			/* Disable interrupts again */
	    if (ufx != _uioufx[fd])	/* Ensure FD still OK */
		USYS_RETERR(EIO);	/* Fail if switcheroo happened */
	    buf += nbytes + n;		/* Update pointer by # bytes written */
	    nbytes = -n;		/* Set new # bytes to write */
	}
    }

    /* Handle converted case */
    ncvt = nbytes;		/* Get # bytes to convert */
    bufp = cbuf-1;		/* Use temporary conversion buffer on stack */
    --buf;
    while (ncvt > 0) {
	register char *cp;
	if (ncvt < (UIO_BUFSIZ/2))		/* Find # to cvt this pass */
	    n = ncvt;
	else n = UIO_BUFSIZ/2;
	ncvt -= n;
	cp = bufp;
	do {
	    if ((*++cp = *++buf) == '\n') {	/* Copy bytes - if see LF, */
		*cp = '\r';			/* replace with CR */
		*++cp = '\n';			/* and add LF */
	    }
	} while (--n > 0);

	/* Now find # bytes converted and actually output them. */
	i = cp - bufp;
	cp = bufp+1;
	for (;;) {		/* Permit loop for interrupt continuation */
	    if ((n = outsys(ufx, cp, i)) > 0)
		break;			/* Normally we win... */
	    if (n == 0) {
		USYS_RET(-1);		/* Fail.  Don't bother with # bytes. */
	    }
	    /* Interrupted!  n has negative # bytes left to write. */
	    if (USYS_END() < 0) {	/* Allow ints, see if must fail */
		errno = EINTR;		/* Yeah, fail this way */
		return -1;
	    }
	    /* Can proceed from interrupt!  Update things... */
	    USYS_BEG();			/* Disable interrupts again */
	    if (ufx != _uioufx[fd])	/* Ensure FD still OK */
		USYS_RETERR(EIO);	/* Fail if switcheroo happened */
	    cp += i + n;		/* Update pointer by # bytes written */
	    i = -n;			/* Set new # bytes to write */
	}				/* And continue loop to re-try call! */
    }

    USYS_RET(nbytes);			/* Return # bytes */
}
/* outsys(ufx, buf, nbytes) - system-dependent output
**	Returns:
**		> 0  Won, return value is # of bytes written.
**		= 0  Failed.
**		< 0  Interrupted; value is -<# of bytes LEFT to be written>.
**	In all cases, _uiopos is updated to reflect
**	any bytes that were actually written.
*/

static int
outsys(ufx, buf, nbytes)
int ufx, nbytes;
char *buf;
{
#if SYS_10X+SYS_T20
    int i, num, ablock[5];

    switch (_uiotype[ufx]) {
	case _DVDSK:
	    num = SOUT;		/* Not interruptible */
	    break;
	case _DVTTY:
	case _DVPTY:
	default:
	    num = SOUT | JSYS_OKINT;	/* Allow interrupts */
	    break;
	case _DVTCP:				/* SOUTR to Force output */
	    num = SOUTR | JSYS_OKINT;
	    break;
    }
    ablock[1] = _uioch[ufx];		/* JFN */
    ablock[2] = (int) (buf - 1);	/* 1 before buffer */
    ablock[3] = -nbytes;		/* -# bytes to write */
    num = jsys(num, ablock);

    /* Now update vars */
    _uiopos[ufx] += (i = nbytes + ablock[3]);	/* Find # bytes written */
    if (num > 0)		/* SOUT succeeded? */
	return i;		/* Yes, all's well (probably) */
    else if (num < 0)		/* Interrupted? */
	return (ablock[3] < 0 ?	/* Yes, see if anything left to write */
		ablock[3] : i);	/* return -N if so, else claim we won. */

    switch (ablock[0]) {	/* SOUT failed somehow, translate error */
	case IOX11:	errno = EDQUOT; break;	/* Quota exceeded */
	case IOX34:	errno = ENOSPC; break;	/* No space on disk */
	default:
	    errno = EIO;		/* Random error */
	    return 0;
    }
    /* SOUT% error to be turned into SIGXFSZ signal */
    raise(SIGXFSZ);		/* Turn on signal */
    return (ablock[3] < 0 ?	/* See if anything left to write */
	    ablock[3] : i);	/* return -N if so, else claim we won. */

#elif SYS_ITS
#asm
	%chrbp 2,-2(17)		/* Get buffer ptr */
	skipg 3,-3(17)		/* Get count */
	 jrst outsy9		/* No count */
	skipge 1,-1(17)		/* Get UFX */
	 jrst outsy9
	.call [	setz
		sixbit /siot/
		.uioch(1)	/* Channel # from table */
		2		/* Byte ptr to source */
		setz 3]		/* Count of bytes */
	 jrst outsy9		/* Failed */
	skipa 1,-1(17)
outsy9:	 tdza 1,1		/* Return 0 for failure */
	  sub 1,3		/* Return # bytes read/written */
#else
#error write() not supported for this system.
#endif
}
#if 0	/* OLD STUFF */
#if SYS_WAITS
/* --------------- */
/*	write      */
/* --------------- */

write(f,buf,n)
char *buf;
{
    int    chan;
    int i;
    char *c;
    struct bufhead *p;

    if ((chan=_uioch[f]) < 1 || n <= 0) return -1; /* find output channel */
    if (chan == 1) {			/* tty output? */
	for (i = n; i-- ; ) _putty(*buf++); /* yes, one char at a time */
	return n;			/* return the count */
    }

    p = &buffers[chan];			/* other output, get buffer */
    c = p->user;			/* user deposit pointer */
    i = p->count;			/* number of chars in buffer */
    while (n--) {			/* for all chars in buffer */
	*++c = *buf++;			/* drop next char in */
	if (--i <= 0) {			/* if no more room */
	    if (!_out(chan)) return -1;	/* send the buffer out */
	    c = p->user;		/* get new deposit pointer */
	    i = p->count;		/* and count */
	}
    }
    p->user = c;			/* save updated deposit pointer */
    p->count = i;			/* and buffer space count */
    return n;				/* return the number of chars sent */
}
/* -------------------- */
/*	byte write      */
/* -------------------- */

bwrite(f,buf,n)
char *buf;
{
    int chan;
    int i,save;
    char *c;
    struct bufhead *p;

    if ((chan=_uioch[f]) < 1 || n < 0) return -1;

    if (chan == 1) {			/* tty output? */
	for (i = n; i-- ; ) _putty(*buf++); /* yes, do char at a time */
	return n;			/* and return count */
    }

    p = &buffers[chan];			/* normal output, find buffer */
    save = p->user;			/* and pointer */
    save++;
    c = (save & 0777777) | (0341000<<18); /* turn into 8-bit byte pointer */
    c--;
    i = p->count*4;			/* get number of bytes avail */
    while (n--) {			/* while still things to do */
	*++c = *buf++;			/* add char to buffer */
	if (--i <= 0) {			/* if space in buffer gone */
	    if (!_out(chan)) return -1;	/* send it off */
	    save = p->user;		/* refill buffer */
	    c = (save & 0777777) | (0341000<<18); /* make pointer again */
	    i = p->count*4;		/* and fix up count */
	}
    }
    chan = c;				/* get final word */
    p->user = (chan & 0777777) | (save & (0777777<<18)); /* as 8-bit ptr */
    p->count = i/4;			/* fix count */
    return n;				/* all done */
}
/* -------------------------- */
/*	image mode write      */
/* -------------------------- */

iwrite(f,buf,n)
char *buf;
{
    int    chan;
    int i,save;
    char *c;
    struct bufhead *p;

    if ((chan=_uioch[f]) < 1 || n < 0) return -1;

    if (chan == 1) {			/* tty output? */
	for (i = n; i-- ; ) _putty(*buf++); /* yes, send one by one */
	return n;			/* and return count */
    }

    p = &buffers[chan];			/* get buffer */
    c = p->user;			/* and buffer pointer */
    i = p->count;			/* and buffer space count */
    while (n--) {			/* while bytes to send */
	*++c = *buf++;			/* send one */
	if (--i <= 0) {			/* if out of room */
	    if (!_out(chan)) return -1;	/* send buffer off */
	}
    }
    p->count = i;			/* put back count */
    p->user = c;			/* and deposit pointer */
    return n;				/* return number of bytes sent */
}
static _putty(), _out();
#asm
; ************************************************************
;	output a character to the tty
; ************************************************************
;
.PUTTY:	MOVE	1,-1(17)
	OUTCHR	1
	POPJ	17,

; ************************************************************
;	output buffer (chan #, bufptr)
; ************************************************************
;
.OUT:	MOVE	1,-1(17)
	ANDI	1,17
	LSH	1,27			; shift channel # into ac field
	IOR	1,[OUT 0,0]
	MOVEM	1,.+1
	OUT 	0,0
	JRST	$RETT			; no error
	JRST	$RETF			; error
#endasm
#endif /* WAITS */

#endif	/* Commented-out stuff */