V10/sys/io/Nttyld.c

Compare this file to the similar file:
Show the results in this format:

#include "sys/param.h"
#include "sys/stream.h"
#include "sys/ttyio.h"
#include "sys/ttyld.h"
#include "sys/conf.h"

extern	char	partab[];

#define	CANBSIZ	256		/* size of largest input line */

extern	struct	ttyld	ttyld[];
extern	int ttycnt;

char	maptab[] = {
	000,000,000,000,000,000,000,000,
	000,000,000,000,000,000,000,000,
	000,000,000,000,000,000,000,000,
	000,000,000,000,000,000,000,000,
	000,'|',000,000,000,000,000,'`',
	'{','}',000,000,000,000,000,000,
	000,000,000,000,000,000,000,000,
	000,000,000,000,000,000,000,000,
	000,000,000,000,000,000,000,000,
	000,000,000,000,000,000,000,000,
	000,000,000,000,000,000,000,000,
	000,000,000,000,'\\',000,'~',000,
	000,'A','B','C','D','E','F','G',
	'H','I','J','K','L','M','N','O',
	'P','Q','R','S','T','U','V','W',
	'X','Y','Z',000,000,000,000,000,
};

long	ttyopen();
int	ttyclose(), ttyldin(), ttyinsrv(), ttyosrv();
static struct qinit ttrinit = { ttyldin, ttyinsrv, ttyopen, ttyclose, 600, 60};
static struct qinit ttwinit = { putq, ttyosrv, ttyopen, ttyclose, 300, 200};
struct streamtab ttystream = { &ttrinit, &ttwinit};

/*
 * TTY open
 */
long
ttyopen(qp, dev)
register struct queue *qp;
{
	register struct ttyld *tp;
	static struct tchars tchars = {CINTR,CQUIT,CSTART,CSTOP,CEOT,0377};

	if (qp->ptr)				/* already attached */
		return(1);
	for (tp = ttyld; tp->t_state&TTUSE; tp++)
		if (tp >= &ttyld[ttycnt-1])
			return(0);
	tp->t_state = TTUSE;
	tp->t_flags = ECHO|CRMOD;
	tp->t_delct = 0;
	tp->t_col = 0;
	tp->t_erase = CERASE;
	tp->t_kill = CKILL;
	tp->t_chr = tchars;
	tp->t_iblk = NULL;
	qp->ptr = (caddr_t)tp;
	qp->flag |= QDELIM|QNOENB;
	WR(qp)->ptr = (caddr_t)tp;
	return(1);
}

ttyclose(qp)
struct queue *qp;
{
	struct ttyld *tp = (struct ttyld *)qp->ptr;

	tp->t_state = 0;
	if (tp->t_iblk)
		freeb(tp->t_iblk);
	tp->t_iblk = NULL;
}

/*
 * Queue put procedure for tty input
 *  -- RAW and CBREAK input is passed immediately;
 *  -- cooked input accumulates in tp->t_iblk until a full line.
 */
ttyldin(q, bp)
struct queue *q;
register struct block *bp;
{
	register struct ttyld *tp;
	register c;
	register struct queue *wrq = WR(q);	/* writer side */
	int escape, flags;

	tp = (struct ttyld *)q->ptr;
	flags = tp->t_flags;
	if (bp->type!=M_DATA) {
		switch(bp->type) {

		case M_BREAK:
			if (tp->t_flags&RAW) {		/* speed-change hack*/
				bp->type = M_DATA;
				if (bp->wptr<bp->lim)
					*bp->wptr++ = '\0';
				break;
			}
			ttysig(q, SIGINT);
			freeb(bp);
			return;

		case M_HANGUP:
		case M_IOCACK:
		case M_IOCNAK:
			(*q->next->qinfo->putp)(q->next, bp);
			return;

		case M_IOCTL:
			ttldioc(WR(q), bp, q, 1);
			return;
		}
		flags |= RAW;
	}
	if (tp->t_flags&TANDEM && tp->t_state&TTBLOCK
	 && q->next->count <= q->next->qinfo->lolimit) {
		tp->t_state &= ~TTBLOCK;
		putd(putq, WR(q), tp->t_chr.t_startc);
	}
	if (flags&RAW) {
		if ((q->next->flag&QFULL)==0)
			(*q->next->qinfo->putp)(q->next, bp);
		else
			freeb(bp);
		return;
	}
	while (bp->rptr<bp->wptr) {
		register struct queue *nq = q->next;
		c = *bp->rptr++;
		if (tp->t_state&TTSTOP) {
			if (c!=tp->t_chr.t_stopc
			 || tp->t_chr.t_stopc==tp->t_chr.t_startc) {
				tp->t_state &= ~TTSTOP;
				putctl(wrq->next, M_START);
			}
		} else {
			if (c==tp->t_chr.t_stopc) {
				tp->t_state |= TTSTOP;
				putctl(wrq->next, M_STOP);
			}
		}
		if (c==tp->t_chr.t_stopc || c==tp->t_chr.t_startc)
			continue;
		if (c==tp->t_chr.t_intrc) {
			ttysig(q, SIGINT);
			continue;
		}
		if (c==tp->t_chr.t_quitc) {
			ttysig(q, SIGQUIT);
			continue;
		}
		if (c=='\r' && tp->t_flags&CRMOD)
			c = '\n';
		if (tp->t_flags&LCASE && c>='A' && c<='Z')
			c += 'a'-'A';
		extraecho = 0;
		if (tp->t_flags & CBREAK) {
			if ((q->next->flag&QFULL)==0)
				putd(q->next->qinfo->putp, q->next, c);
			else
				continue;
		} else
			extraecho = ttycanon(q, tp, c);
		if (wrq->flag&QFULL)
			continue;	/* can't echo or do flow control */
		if (tp->t_flags&ECHO) {
			putctl1d(wrq, M_DATA, c);
			if (extraecho)
				putctl1d(wrq, M_DATA, extraecho);
		}
		if (tp->t_flags&TANDEM && (tp->t_state&TTBLOCK) == 0
		 && nq->count >= (nq->qinfo->limit+nq->qinfo->lolimit)/2)
			tp->t_state |= TTBLOCK;
			putctl1d(wrq, M_DATA, tp->t_chr.t_stopc);
		}
	}
	freeb(bp);
}

/*
 * add a character to the input buffer
 */
ttycanon(q, tp, c)
register struct queue *q;
register struct ttyld *tp;
register c;
{
	register struct block *bp, nbp;
	register n, delim=0, escape=0;

	if ((bp = tp->t_iblk) == NULL) {
		tp->t_iblk = bp = allocb(64);
		if (bp==NULL)
			return;
	}
	if (bp->wptr >= bp->lim-2) {	/* move to bigger block? */
		n = bp->wptr-bp->rptr;
		if (n>=CANBSIZ)
			delim = 1;
		else {
			nbp = allocb(2*n);
			if (nbp==NULL || nbp->lim-nbp->base < 2*n) {
				if (nbp)
					freeb(nbp);
				delim = 1;
			} else {
				bcopy(bp->rptr, nbp->rptr, n);
				nbp->wptr += n;
				freeb(bp);
				tp->t_iblk = nbp;
				bp = nbp;
			}
		}
	}
	if (tp->t_state&TTESC) {
		escape = 1;
		c |= 01000;
		tp->t_state &= ~TTESC;
	}
	if (c == '\\') {
		tp->t_stat |= TTESC;
		return(0);
	}
	*bp->wptr++ = c;
	if (c == '\\'|01000) {
		*bp->wptr++ = '\\';	/* escaped \ */
		return(0);
	}
	if (c == tp->t_kill) {
		bp->wptr = bp->rptr;
		return('\n');
	}
	if (c == tp->t_erase) {
		if (bp->wptr>bp->rptr)
			bp->wptr--;
		return(0);
	}
	if ((c&0377)=='\n' || c==tp->t_chr.t_eofc || c==tp->t_chr.t_brkc || delim) {
		putq(q, bp);
		tp->iblk = NULL;
		qenable(q);
	}
	return(0);

}

ttyinsrv(q)
register struct queue *q;
{
	register struct block *bp;

	while ((q->next->flag&QFULL==0) {
		if ((bp = getq(q)) == NULL)
			break
		(*q->next->qinfo->putp)(q->next, bp);
	}
}

/*
 * TTY write processing: delays, tabs, CR/NL and the like.
 */
ttyosrv(q)
register struct queue *q;
{
	register struct ttyld *tp;
	register struct block *bp;

	tp = (struct ttyld *)q->ptr;
	while (bp = getq(q)) {
		switch(bp->type) {

		default:
			freeb(bp);
			continue;

		case M_IOCTL:
			if (q->next->flag & QFULL) {
				putbq(q, bp);
				return;
			}
			ttldioc(q, bp, RD(q), 0);
			continue;

		case M_FLUSH:
			flushq(q, 0);
		case M_IOCNAK:		/* flow through */
		case M_IOCACK:
			(*q->next->qinfo->putp)(q->next, bp);
			continue;

		case M_DATA:
		case M_BREAK:
			if (q->next->flag & QFULL) {
				putbq(q, bp);
				return;
			}
			if (tp->t_flags&RAW || bp->type==M_BREAK) {
				(*q->next->qinfo->putp)(q->next, bp);
			} else
				outconv(q, bp);
			continue;
		}
	}
}

outconv(q, ibp)
struct queue *q;
register struct block *ibp;
{
	register struct ttyld *tp;
	register struct block *obp = NULL;
	register c;
	register count, ctype;

	tp = (struct ttyld *)q->ptr;
   more:
	while (ibp->rptr < ibp->wptr) {
		if (obp==NULL || obp->wptr >= obp->lim) {
			if (obp)
				(*q->next->qinfo->putp)(q->next, obp);
			if (q->next->flag&QFULL || (obp=allocb(QBSIZE))==NULL) {
				putbq(q, ibp);
				return;
			}
		}
		/*
		 * The following dance is an inner loop
		 */
		count = ibp->wptr - ibp->rptr;
		if ((c = obp->lim - obp->wptr) < count)
			count = c;
		while ((ctype = partab[c = *ibp->rptr++ & 0177] & 077) == 0) {
			tp->t_col++;
			*obp->wptr++ = c;
			if (--count <= 0)
				goto more;
		}
		if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
			for (;;) {
				*obp->wptr++ = ' ';
				tp->t_col++;
				if ((tp->t_col & 07) == 0)	/* every 8 */
					break;
				if (obp->wptr >= obp->lim) {
					ibp->rptr--;
					break;
				}
			}
			continue;
		}

		/*
		 * turn <nl> to <cr><lf> if desired.
		 */
		if (c=='\n' && tp->t_flags&CRMOD) {
			if ((tp->t_state&TTCR)==0) {
				tp->t_state |= TTCR;
				c = '\r';
				ctype = partab['\r'] & 077;
				--ibp->rptr;
			} else
				tp->t_state &= ~TTCR;
		}
		/*
		 * store character
		 */
		*obp->wptr++ = c;
		/*
		 * Calculate delays and column movement
		 */
		count = 0;
		switch (ctype) {

		/* ordinary */
		case 0:
			tp->t_col++;
			break;
	
		/* non-printing */
		case 1:
			break;
	
		/* backspace */
		case 2:
			if (tp->t_col)
				tp->t_col--;
			break;
	
		/* newline */
		case 3:
			ctype = (tp->t_flags >> 8) & 03;
			if(ctype == 1) { /* tty 37 */
				if (tp->t_col)
					count = max(((unsigned)tp->t_col>>4) + 3, (unsigned)6);
			} else if (ctype == 2)	/* vt05 */
				count = 6;
			if ((tp->t_flags&CRMOD)==0)
				tp->t_col = 0;
			break;
	
		/* tab */
		case 4:
			ctype = (tp->t_flags >> 10) & 03;
			if(ctype == 1) { /* tty 37 */
				count = 1 - (tp->t_col | ~07);
				if (count < 5)
					count = 0;
			}
			tp->t_col |= 07;
			tp->t_col++;
			break;
	
		/* vertical motion */
		case 5:
			if(tp->t_flags & VTDELAY)
				count = 127;
			break;
	
		/* carriage return */
		case 6:
			ctype = (tp->t_flags >> 12) & 03;
			if (ctype == 1) 	 /* tn 300 */
				count = 5;
			else if (ctype == 2)	/* ti 700 */
				count = 10;
			else if (ctype == 3)
				count = 20;
			tp->t_col = 0;
			break;
		}
		if (count) {
			(*q->next->qinfo->putp)(q->next, obp);
			putctl1(q->next, M_DELAY, count);
			obp = NULL;
		}
	}
	if (obp) {
		obp->class |= ibp->class&S_DELIM;
		(*q->next->qinfo->putp)(q->next, obp);
	} else if (ibp->class&S_DELIM)
		putctld(q->next, M_DATA);
	freeb(ibp);
}

/*
 * Reader generates a signal and passes it up
 */
ttysig(q, sig)
register struct queue *q;
{
	register struct ttyld *tp = (struct ttyld *)q->ptr;

	flushq(q, 0);			/* flush reader */
	flushq(WR(q), 0);
	tp->t_state &= ~TTESC;
	tp->t_delct = 0;
	putctl(q->next, M_FLUSH);
	putctl1(q->next, M_SIGNAL, sig);
	putctl(WR(q)->next, M_FLUSH);
}

ttldioc(q, bp, rdq, fromdev)
register struct block *bp;
struct queue *q, *rdq;
{
	register struct ttyld *tp;
	register struct sgttyb *sp;
	int s;

	sp = (struct sgttyb *)stiodata(bp);
	tp = (struct ttyld *)q->ptr;
	switch (stiocom(bp)) {

	/*
	 * Set new parameters
	 */
	case TIOCSETP:
	case TIOCSETN:
		s = spl6();
		if (sp->sg_flags & (RAW|CBREAK)
		  && (rdq->next->flag&QFULL)==0) {
			register struct block *bp1;
			ttyinsrv(rdq);
			while (bp1 = getq(rdq))
				(*rdq->next->qinfo->putp)(rdq->next, bp1);
		}
		tp->t_erase = sp->sg_erase;
		tp->t_kill = sp->sg_kill;
		tp->t_flags = sp->sg_flags;
		splx(s);
		bp->type = M_IOCACK;
		if (tp->t_flags & (RAW|CBREAK))
			rdq->flag &= ~(QDELIM|QNOENB);
		else
			rdq->flag |= QDELIM|QNOENB;
		break;

	/*
	 * Send current parameters to user
	 */
	case TIOCGETP:
		sp->sg_erase = tp->t_erase;
		sp->sg_kill = tp->t_kill;
		sp->sg_flags = tp->t_flags;
		sp->sg_ispeed = sp->sg_ospeed = B9600;
		bp->wptr = bp->rptr+sizeof(struct sgttyb)+STIOCHDR;
		bp->type = M_IOCACK;
		break;

	/*
	 * Set and fetch special characters
	 */
	case TIOCSETC:
		tp->t_chr = *(struct tchars *)((struct stioctl *)bp->rptr)->data;
		bp->wptr = bp->rptr;
		bp->type = M_IOCACK;
		break;

	case TIOCGETC:
		*(struct tchars *)((struct stioctl *)bp->rptr)->data = tp->t_chr;
		bp->wptr = bp->rptr+sizeof(struct tchars)+STIOCHDR;
		bp->type = M_IOCACK;
		break;

	default:
		if (fromdev) {
			bp->type = M_IOCACK;
			qreply(rdq, bp); /* reply to device side */
		} else
			(*q->next->qinfo->putp)(q->next, bp); /* pass to device */
		return;

	}
	if (fromdev)
		qreply(rdq, bp);	/* to device side */
	else
		qreply(q, bp);		/* to process side */
}