V9/sys/dev.old/ttyld.c

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

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

extern	char	partab[];

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

struct	ttyld	tty[NTTY];

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,
};

int	ttyopen(), 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 ttyinfo = { &ttrinit, &ttwinit};

/*
 * TTY open
 */
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 = tty; tp->t_state&TTUSE; tp++)
		if (tp >= &tty[NTTY-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;
	qp->ptr = (caddr_t)tp;
	qp->flag |= QDELIM|QNOENB;
	WR(qp)->ptr = (caddr_t)tp;
	return(1);
}

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

	tp->t_state = 0;
}

/*
 * Queue put procedure for tty input
 */
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_DELIM:
			freeb(bp);
			return;

		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->count <= q->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->count==0)
			(*q->next->qinfo->putp)(q->next, bp);
		else
			putq(q, bp);
		return;
	}
	while (bp->rptr<bp->wptr) {
		c = *bp->rptr++ & 0177;
		if (tp->t_state&TTSTOP) {
			if (c==tp->t_chr.t_startc || c==tp->t_chr.t_intrc) {
				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';
		escape = 0;
		if (tp->t_flags & CBREAK) {
			if ((q->next->flag&QFULL)==0 && q->count==0)
				putd(q->next->qinfo->putp, q->next, c);
			else
				putd(putq, q, c);
		} else {
			if (tp->t_state&TTESC) {
				escape = 1;
				c |= 0200;
			}
			if (c == '\\')
				tp->t_state |= TTESC;
			else {
				tp->t_state &= ~TTESC;
				if (c == ('\\'|0200)) {
					c &= 0177;
					tp->t_state |= TTESC;
				}
				/* ttyhog? */
				if (q->count<512 || (c=='\n' && tp->t_delct==0))
					putd(putq, q, c);
				else
					c = '\007';
			}
			c &= 0177;
			if (c=='\n'||c==tp->t_chr.t_eofc||c==tp->t_chr.t_brkc) {
				register struct block *bp1;
				if (bp1 = allocb(1)) {
					bp1->type = M_DELIM;
					putq(q, bp1);
					tp->t_delct++;
				}
				qenable(q);
			}
		}
		if (tp->t_flags&TANDEM && (tp->t_state&TTBLOCK) == 0
		 && q->count >= (q->qinfo->limit+q->qinfo->lolimit)/2 ) {
			q->next->flag |= QWANTW;
			tp->t_state |= TTBLOCK;
			putd(putq, wrq, tp->t_chr.t_stopc);
		}
		if (tp->t_flags&ECHO && (wrq->flag&QFULL)==0) {
			register c1 = c&0177;
			if (c1!=CEOT) {
				putd(putq, wrq, c1);
				if(wrq->next->flag&QDELIM && bp->wptr==bp->rptr)
					putctl(wrq, M_DELIM);
			}
			if (c==tp->t_kill && (tp->t_flags&CBREAK)==0
			 && !escape) {
				putd(putq, wrq, '\n');
				if (wrq->next->flag&QDELIM)
					putctl(wrq, M_DELIM);
			}
		}
	}
	freeb(bp);
}

/*
 * tty input server processing.  Erase-kill and escape processing;
 * gathering into lines.
 */

ttyinsrv(q)
register struct queue *q;
{
	register struct ttyld *tp;
	register struct block *bp;
	register char *op;
	register c;
	static char canonb[CANBSIZ];

	tp = (struct ttyld *)q->ptr;
	if (q->next->flag&QFULL)
		return;
	if (tp->t_flags&(CBREAK|RAW)) {
		while ((q->next->flag&QFULL)==0 && (bp = getq(q)))
			(*q->next->qinfo->putp)(q->next, bp);
	} else {
		op = canonb;
		while (tp->t_delct) {
			bp = getq(q);
			if (bp==NULL || bp->type!=M_DATA) {
				if (op > canonb)
					putcpy(q->next, canonb, op-canonb);
				if (bp) {
					(*q->next->qinfo->putp)(q->next, bp);
					tp->t_delct--;
					op = canonb;
					continue;
				}
				return;
			}
			while (bp->rptr<bp->wptr) {
				c = *bp->rptr++;
				if ((c&0200) == 0) {	/* not escaped */
					if (c == tp->t_erase) {
						if (op > canonb)
							op--;
						continue;
					}
					if (c == tp->t_kill) {
						op = canonb;
						continue;
					}
					if (c == tp->t_chr.t_eofc)
						continue;
				} else {
					c &= 0177;
					if (tp->t_flags&LCASE && maptab[c])
						c = maptab[c];
					else if (c==tp->t_erase || c==tp->t_kill
					      || c==tp->t_chr.t_eofc)
						;
					else
						*op++ = '\\';
				}
				*op++ = c;
				if (op >= &canonb[CANBSIZ-1]) {
					putcpy(q->next, canonb, op-canonb);
					op = canonb;
				}
			}
			freeb(bp);
		}
	}
	if (tp->t_flags&TANDEM && tp->t_state&TTBLOCK
	 && q->count <= q->qinfo->lolimit) {
		tp->t_state &= ~TTBLOCK;
		putd(putq, WR(q), tp->t_chr.t_startc);
	}
}

/*
 * 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_DELIM:
			if ((q->next->flag & QDELIM) == 0) {
				freeb(bp);
				continue;
			}
			if (q->next->flag & QFULL) {
				putbq(q, bp);
				return;
			}
			(*q->next->qinfo->putp)(q->next, 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);
			if (obp = allocb(1)) {
				obp->type = M_DELAY;
				*obp->wptr++ = count;
				(*q->next->qinfo->putp)(q->next, obp);
			}
			obp = NULL;
		}
	}
	if (obp)
		(*q->next->qinfo->putp)(q->next, obp);
	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 union stmsg *sp;
	int s;

	sp = (union stmsg *)bp->rptr;
	tp = (struct ttyld *)q->ptr;
	switch (sp->ioc0.com) {

	/*
	 * Set new parameters
	 */
	case TIOCSETP:
	case TIOCSETN:
		s = spl6();
		if (sp->ioc1.sb.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->ioc1.sb.sg_erase;
		tp->t_kill = sp->ioc1.sb.sg_kill;
		tp->t_flags = sp->ioc1.sb.sg_flags;
		splx(s);
		bp->type = M_IOCACK;
		if (fromdev)
			qreply(rdq, bp); /* reply to device side */
		else
			qreply(q, bp); /* reply to process side */
		if (tp->t_flags & (RAW|CBREAK))
			rdq->flag &= ~(QDELIM|QNOENB);
		else
			rdq->flag |= QDELIM|QNOENB;
		break;

	/*
	 * Send current parameters to user
	 */
	case TIOCGETP:
		sp->ioc1.sb.sg_erase = tp->t_erase;
		sp->ioc1.sb.sg_kill = tp->t_kill;
		sp->ioc1.sb.sg_flags = tp->t_flags;
		sp->ioc1.sb.sg_ispeed =
		 sp->ioc1.sb.sg_ospeed = B9600;
		bp->wptr = bp->rptr+sizeof(struct ioc1);
		bp->type = M_IOCACK;
		if (fromdev)
			qreply(rdq, bp); /* reply to device side */
		else
			qreply(q, bp); /* reply to process side */
		break;

	/*
	 * Set and fetch special characters
	 */
	case TIOCSETC:
		tp->t_chr = sp->ioc2.sb;
		bp->wptr = bp->rptr;
		bp->type = M_IOCACK;
		if (fromdev)
			qreply(rdq, bp); /* reply to device side */
		else
			qreply(q, bp); /* reply to process side */
		break;

	case TIOCGETC:
		sp->ioc2.sb = tp->t_chr;
		bp->wptr = bp->rptr+sizeof(struct ioc2);
		bp->type = M_IOCACK;
		if (fromdev)
			qreply(rdq, bp); /* reply to device side */
		else
			qreply(q, bp); /* reply to process side */
		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 */
		break;

	}
}