V10/sys/io/nttyld.c
#include "sys/param.h"
#include "sys/stream.h"
#include "sys/ttyio.h"
#include "sys/nttyio.h"
#include "sys/ttyld.h"
#include "sys/nttyld.h"
#include "sys/conf.h"
#include "sys/file.h"
extern char maptab[], /* see dev/ttyld.c */
partab[]; /* see sys/partab.c */
extern struct nttyld ntty[];
extern int nttycnt;
int ntclose(), /* queue close routine */
ntin(), /* reader queue put routine */
ntinsrv(), /* reader queue service routine */
ntout(), /* writer queue put routine */
ntoutsrv(); /* writer queue service routine */
long ntopen(); /* queue open routine */
static struct qinit rinit = { ntin, ntinsrv, ntopen, ntclose, 300, 0 },
winit = { ntout, ntoutsrv, ntopen, ntclose, 300, 200 };
struct streamtab nttystream = { &rinit, &winit };
#define CANBSIZ 256 /* why not NT_NIN? */
/*
* Backspace over "n" characters, perhaps erasing them.
* Called from ntrubout().
*/
ntbs (nt, n)
register struct nttyld *nt;
register int n;
{
while (--n >= 0)
if (putd (putq, nt->nt_outq, '\b')) {
nt->nt_state |= NT_ECHO;
if (nt->nt_local & LCRTERA) {
(void) putd (putq, nt->nt_outq, ' ');
(void) putd (putq, nt->nt_outq, '\b');
}
}
return;
}
/*
* Set default control characters.
* Called by ntopen().
*/
ntchars (nt)
register struct nttyld *nt;
{
static struct tchars tchars = { CINTR, CQUIT, CSTART, CSTOP, CEOT,
0377 };
static struct ltchars ltchars = { CSUSP, CDSUSP, CRPRNT, CFLUSH,
CWERAS, CLNEXT };
nt->nt_erase = CERASE;
nt->nt_kill = CKILL;
nt->nt_tchr = tchars;
nt->nt_ltchr = ltchars;
return;
}
ntclose (q)
register struct queue *q;
{
register struct nttyld *nt = (struct nttyld *) q->ptr;
nt->nt_state = 0;
return;
}
/*
* Put input buffer on read queue followed by a delimiter.
* Called from ntinc() when a line break character is read,
* and from ntioctl() when switching from cooked to raw or cbreak mode.
*/
ntcooked (nt)
register struct nttyld *nt;
{
register char *s, *t;
register struct block *b;
register struct queue *q = RD (nt->nt_outq);
if (!(q->flag & QFULL) && (b = allocb (1))) {
for (t = (s = nt->nt_in) + nt->nt_nin; s < t; s++)
(void) putd (putq, q, *s);
b->class |= S_DELIM;
putq (q, b);
nt->nt_delct++;
}
qenable (q);
nt->nt_nin = 0;
nt->nt_trash = 0;
return;
}
/*
* Echo a typed character to a terminal.
*/
ntecho (c, nt)
register int c;
register struct nttyld *nt;
{
register struct queue *echoq = nt->nt_outq;
nt->nt_local &= ~LFLUSHO;
if (!(nt->nt_flags & ECHO) || echoq->flag & QFULL)
return;
c &= 0377;
if (nt->nt_flags & RAW)
goto out;
if (c == '\r' && nt->nt_flags & CRMOD)
c = '\n';
if (c != '\n' && c != '\t' && nt->nt_local & LCTLECH)
if ((c &= 0177) <= 037 || c == 0177) {
(void) putd (putq, echoq, '^');
if (c == 0177)
c = '?';
else if (nt->nt_flags & LCASE)
c += 'a' - 1;
else c += 'A' - 1;
goto out;
}
if ((c &= 0177) == CEOT) /* terminals don't like it */
return;
out:
if (putd (putq, echoq, c))
nt->nt_state |= NT_ECHO;
return;
}
/*
* Flush all input and/or all output tty queues.
*/
ntflush (nt, rw)
struct nttyld *nt;
int rw;
{
struct queue *wrq = nt->nt_outq,
*rdq = RD (wrq);
if (rw & FREAD) {
flushq (rdq, 0);
(void) putctl (rdq->next, M_FLUSH);
nt->nt_delct = 0;
nt->nt_nin = 0;
nt->nt_trash = 0;
nt->nt_lstate = 0;
}
if (rw & FWRITE) {
flushq (wrq, 0);
(void) putctl (wrq->next, M_FLUSH);
}
return;
}
/*
* Reader queue (input from tty) put routine.
*/
ntin (q, b)
struct queue *q;
register struct block *b;
{
register struct nttyld *nt = (struct nttyld *) q->ptr;
switch (b->type) {
case M_DATA:
if (nt->nt_flags & RAW && !(nt->nt_flags & ECHO))
break;
nt->nt_state &= ~NT_ECHO;
while (b->rptr < b->wptr)
ntinc ((int) *b->rptr++, nt);
freeb (b);
if (nt->nt_state & NT_ECHO && nt->nt_outq->next->flag & QDELIM)
(void) qpctld (nt->nt_outq, M_DATA);
return;
case M_BREAK:
if (nt->nt_flags & RAW) { /* speed-change hack */
b->type = M_DATA;
if (b->wptr < b->lim)
*b->wptr++ = '\0';
break;
}
(void) putctl1 (q->next, M_SIGNAL, SIGINT);
ntflush (nt, FREAD | FWRITE);
freeb (b);
return;
case M_HANGUP:
(*q->next->qinfo->putp)(q->next, b);
return;
}
if (q->next->flag & QFULL)
freeb (b);
else (*q->next->qinfo->putp)(q->next, b);
return;
}
/*
* Process a single input character.
* Called (at interrupt level) by ntin().
*/
ntinc (c, nt)
register c;
register struct nttyld *nt;
{
register int t_flags;
c &= 0377;
t_flags = nt->nt_flags;
if (t_flags & RAW) {
if (!(nt->nt_readq->next->flag & QFULL))
if (putd (nt->nt_readq->next->qinfo->putp, nt->nt_readq->next, c))
ntecho (c, nt);
return;
}
if (!(nt->nt_lstate & LSTYPEN))
c &= 0177;
/*
* Interpret literal-next-character control character (^V).
*/
if (nt->nt_lstate & LSLNCH) {
c |= 0200;
nt->nt_lstate &= ~LSLNCH;
}
if (c == nt->nt_lnextc) {
nt->nt_lstate |= LSLNCH;
if (nt->nt_flags & ECHO)
if (putd (putq, nt->nt_outq, '^')) {
nt->nt_state |= NT_ECHO;
(void) putd (putq, nt->nt_outq, '\b');
}
return;
}
if (ntstst (c, nt) || /* start, stop */
ntoflush (c, nt) || /* flush output */
ntsigc (c, nt)) /* interrupt/quit/stop */
return;
if (c == '\r' && t_flags & CRMOD)
c = '\n';
if (t_flags & LCASE && c >= 'A' && c <= 'Z')
c += 'a' - 'A';
if (t_flags & CBREAK) {
if (nt->nt_readq->next->flag & QFULL) {
if (putd (putq, nt->nt_outq, CTRL('g')))
nt->nt_state |= NT_ECHO;
}
#ifdef notdef
else if (c == nt->nt_dsuspc)
(void) putctl1 (nt->nt_readq->next, M_SSIGNAL, SIGTSTP);
#endif
else if (putd (nt->nt_readq->next->qinfo->putp, nt->nt_readq->next, c&0177))
ntecho (c, nt);
return;
}
if (nt->nt_lstate & LSQUOT) {
nt->nt_lstate &= ~LSQUOT;
if (c == nt->nt_erase || c == nt->nt_kill) {
c |= 0200;
ntrubout (nt);
}
}
if (c == '\\')
nt->nt_lstate |= LSQUOT;
if (c == nt->nt_erase)
ntrubout (nt); /* erase character */
else if (c == nt->nt_kill)
ntkill (nt); /* erase line */
else if (c == nt->nt_werasc)
ntwerase (nt); /* erase word */
else if (c == nt->nt_rprntc)
ntreprint (nt); /* reprint line */
else {
if (nt->nt_nin < NT_NIN) {
if (nt->nt_nin == 0)
nt->nt_rocol = nt->nt_col;
nt->nt_in[nt->nt_nin++] = c;
}
else {
if (putd (putq, nt->nt_outq, CTRL('g')))
nt->nt_state |= NT_ECHO;
return;
}
if (c == '\n' || c == nt->nt_eofc || c == nt->nt_brkc ||
c == '\r' && (nt->nt_flags & CRMOD))
ntcooked (nt);
if (nt->nt_lstate & LSERASE) {
nt->nt_lstate &= ~LSERASE;
if (putd (putq, nt->nt_outq, '/'))
nt->nt_state |= NT_ECHO;
}
ntecho (c, nt);
if (c == nt->nt_eofc && nt->nt_flags & ECHO &&
nt->nt_local & LCTLECH)
if (putd (putq, nt->nt_outq, '\b')) {
nt->nt_state |= NT_ECHO;
(void) putd (putq, nt->nt_outq, '\b');
}
}
return;
}
/*
* Reader queue (tty input) service routine.
* Only cooked mode data and delimiters come through here, via ntcooked().
*/
ntinsrv (q)
register struct queue *q;
{
register struct nttyld *nt;
register struct block *b;
register char *op;
register int c;
static char canonb[CANBSIZ];
if (q->next->flag & QFULL)
return;
nt = (struct nttyld *) q->ptr;
op = canonb;
while (nt->nt_delct) {
b = getq(q);
if (b == NULL) {
if (op > canonb)
putcpy (q->next, canonb, op - canonb);
return;
}
while (b->rptr < b->wptr) {
c = *b->rptr++;
if (c & 0200) { /* escaped */
c &= 0177;
if (nt->nt_flags & LCASE && maptab[c])
c = maptab[c];
else if (c != nt->nt_erase &&
c != nt->nt_kill && c != nt->nt_eofc)
*op++ = '\\';
}
else {
#ifdef notdef
/*
* Interpret delayed stop process
* control character (^Y).
*/
if (c == nt->nt_dsuspc) {
putcpy (q->next, canonb, op - canonb);
op = canonb;
(void) putctl1 (q->next, M_SSIGNAL,
SIGTSTP);
continue;
}
#endif
if (c == nt->nt_eofc)
continue;
}
*op++ = c;
if (op >= &canonb[CANBSIZ-1]) {
putcpy (q->next, canonb, op - canonb);
op = canonb;
}
}
if ((b->class & S_DELIM) == 0)
freeb(b);
else { /* end of line */
if (op > canonb)
putcpy(q->next, canonb, op - canonb);
(*q->next->qinfo->putp)(q->next, b); /* empty S_DELIM */
nt->nt_delct--;
op = canonb;
}
}
return;
}
/*
* Acknowledge ioctl message.
* Called by ntioctl().
*/
ntiocack (q, b, n)
register struct queue *q;
register struct block *b;
register int n;
{
if (n > 0)
n += sizeof (int); /* for ioctl command */
b->wptr = b->rptr + n;
b->type = M_IOCACK;
qreply (q, b);
return;
}
/*
* Terminal I/O control operations.
* Called by ntoutsrv().
*/
ntioctl (q, b)
register struct queue *q;
register struct block *b;
{
register struct nttyld *nt = (struct nttyld *) q->ptr;
register struct ntioc *ioc = (struct ntioc *) b->rptr;
int s;
switch (ioc->command) {
/*
* Set new parameters
*/
case TIOCSETP:
case TIOCSETN:
s = spl6();
if (ioc->arg.sg.sg_flags & (RAW|CBREAK) &&
!(nt->nt_flags & (RAW|CBREAK))) {
/*
* Before leaving cooked mode, push through
* any characters that made it to ntin().
*/
if (nt->nt_nin > 0)
ntcooked (nt);
ntinsrv (RD (nt->nt_outq));
}
nt->nt_erase = ioc->arg.sg.sg_erase;
nt->nt_kill = ioc->arg.sg.sg_kill;
nt->nt_flags = ioc->arg.sg.sg_flags;
nt->nt_readq->flag &= ~QDELIM;
if ((nt->nt_flags & (RAW|CBREAK))==0)
nt->nt_readq->flag |= QDELIM;
splx (s);
ntiocack (q, b, 0);
break;
/*
* Send current parameters to user
*/
case TIOCGETP:
ioc->arg.sg.sg_erase = nt->nt_erase;
ioc->arg.sg.sg_kill = nt->nt_kill;
ioc->arg.sg.sg_flags = nt->nt_flags;
ioc->arg.sg.sg_ispeed =
ioc->arg.sg.sg_ospeed = B9600;
b->wptr = b->rptr + sizeof (int) + sizeof (struct sgttyb);
b->wptr = 2 + b->rptr + sizeof (int) + sizeof (struct sgttyb);
ntiocack (q, b, sizeof (struct sgttyb));
break;
/*
* Set/get special characters
*/
case TIOCSETC:
nt->nt_tchr = ioc->arg.tchr;
ntiocack (q, b, 0);
break;
case TIOCGETC:
ioc->arg.tchr = nt->nt_tchr;
ntiocack (q, b, sizeof (struct tchars));
break;
/*
* Set/get local special characters.
*/
case TIOCSLTC:
nt->nt_ltchr = ioc->arg.ltchr;
ntiocack (q, b, 0);
break;
case TIOCGLTC:
ioc->arg.ltchr = nt->nt_ltchr;
ntiocack (q, b, sizeof (struct ltchars));
break;
/*
* Modify local mode word.
*/
case TIOCLBIS:
nt->nt_local |= ioc->arg.local;
ntiocack (q, b, 0);
break;
case TIOCLBIC:
nt->nt_local &= ~ioc->arg.local;
ntiocack (q, b, 0);
break;
case TIOCLSET:
nt->nt_local = ioc->arg.local;
ntiocack (q, b, 0);
break;
case TIOCLGET:
ioc->arg.local = nt->nt_local;
ntiocack (q, b, sizeof (short));
break;
/*
* Return number of characters in the output.
*/
case TIOCOUTQ:
default:
(*q->next->qinfo->putp)(q->next, b);
break;
}
return;
}
/*
* Erase entire input buffer.
* Called by ntinc().
*/
ntkill (nt)
register struct nttyld *nt;
{
if (nt->nt_local & LCRTKIL && !nt->nt_trash) {
while (nt->nt_nin > 0)
ntrubout (nt);
}
else {
ntecho (nt->nt_kill, nt);
ntecho ('\n', nt);
nt->nt_nin = 0;
nt->nt_trash = 0;
}
nt->nt_lstate = 0;
return;
}
/*
* Interpret the flush-output (^O) control character.
* Called by ntinc().
*/
int
ntoflush (c, nt)
register int c;
register struct nttyld *nt;
{
if (nt->nt_local & LFLUSHO) {
nt->nt_local &= ~LFLUSHO;
if (c == nt->nt_flushc)
return (1);
}
else if (c == nt->nt_flushc) {
ntflush (nt, FWRITE);
ntecho (c, nt);
ntreprint (nt);
nt->nt_local |= LFLUSHO;
return (1);
}
return (0);
}
/*ARGSUSED*/
long
ntopen (q, dev)
register struct queue *q;
int dev;
{
register struct nttyld *nt;
if (q->ptr)
return (1); /* already attached */
for (nt = ntty; nt->nt_state & NT_USE; nt++)
if (nt >= &ntty[nttycnt-1])
return (0);
WR (q)->ptr = q->ptr = (caddr_t) nt;
nt->nt_outq = WR (q);
nt->nt_readq = q;
nt->nt_nin = 0;
nt->nt_state = NT_USE;
nt->nt_flags = ECHO | CRMOD;
nt->nt_col = 0;
nt->nt_delct = 0;
ntchars (nt); /* set default control characters */
nt->nt_trash = 0;
nt->nt_local = 0;
nt->nt_lstate = 0;
q->flag |= QDELIM;
return (1);
}
/*
* Writer queue (output to tty) put routine.
*/
ntout (wrq, b)
register struct queue *wrq;
register struct block *b;
{
if (b->type == M_DATA)
b->type = M_CTL; /* see ntoutsrv() */
putq (wrq, b);
return;
}
/*
* Output a block of data to a terminal.
* Handle tab expansion, case conversion, turning CR to CRLF, delays, etc.
* Called from ntoutsrv().
*/
ntoutb (nt, ib)
register struct nttyld *nt;
register struct block *ib;
{
register struct block *ob = 0;
register struct queue *q = nt->nt_outq;
register int c, delay, ctype;
char *colp;
while (ib->rptr < ib->wptr) {
if (!ob || ob->wptr >= ob->lim) {
if (ob) {
if (nt->nt_local & LFLUSHO)
break;
(*q->next->qinfo->putp)(q->next, ob);
}
if (q->next->flag & QFULL || !(ob = allocb (QBSIZE))) {
putbq (q, ib);
return;
}
}
switch (c = *ib->rptr++ & 0177) {
case '\t':
if ((nt->nt_flags & TBDELAY) != XTABS)
break;
/*
* Expand tabs to spaces.
*/
for (;;) {
*ob->wptr++ = ' ';
nt->nt_col++;
if ((nt->nt_col & 07) == 0) /* every 8 */
break;
if (ob->wptr >= ob->lim) {
ib->rptr--;
break;
}
}
continue;
case '\n':
if (!(nt->nt_flags & CRMOD))
break;
/*
* Turn <nl> to <cr><lf>.
*/
if (nt->nt_state & NT_CR)
nt->nt_state &= ~NT_CR;
else {
nt->nt_state |= NT_CR;
c = '\r';
ib->rptr--;
}
break;
case '~':
if (nt->nt_local & LTILDE)
c = '`';
/* no break */
default:
if (!(nt->nt_flags & LCASE))
break;
/*
* Generate escapes for upper-case-only terminals.
*/
if (nt->nt_state & NT_CASE) {
nt->nt_state &= ~NT_CASE;
break;
}
for (colp = "{(})|!~^`'"; *colp && c != *colp;
colp += 2);
if (*colp || c >= 'A' && c <= 'Z') {
*--ib->rptr = *colp ? colp[1] : c;
nt->nt_state |= NT_CASE;
c = '\\';
}
else if (c >= 'a' && c <= 'z')
c += 'A' - 'a';
break;
}
/*
* Store character.
*/
*ob->wptr++ = c;
/*
* Calculate delays and column movement.
* The delay values are in clock ticks and aren't
* necessarily optimal for all terminals.
*/
delay = 0;
switch (ctype = partab[c] & 077) {
case ORDINARY:
nt->nt_col++;
break;
case CONTROL:
break;
case BACKSPACE:
if (nt->nt_col)
nt->nt_col--;
break;
case NEWLINE:
ctype = (nt->nt_flags >> 8) & 03;
if (ctype == 1) { /* tty 37 */
if (nt->nt_col)
if ((delay = nt->nt_col >> 4) < 6)
delay = 6;
}
else if (ctype == 2) /* vt05 */
delay = 6;
if (!(nt->nt_flags & CRMOD))
nt->nt_col = 0;
break;
case TAB:
ctype = (nt->nt_flags >> 10) & 03;
if (ctype == 1) /* tty 37 */
if ((delay = 1 - (nt->nt_col | ~07)) < 5)
delay = 0;
nt->nt_col |= 07;
nt->nt_col++;
break;
case VTAB:
if (nt->nt_flags & VTDELAY)
delay = 127;
break;
case RETURN:
ctype = (nt->nt_flags >> 12) & 03;
if (ctype == 1) /* tn 300 */
delay = 5;
else if (ctype == 2) /* ti 700 */
delay = 10;
else if (ctype == 3) /* concept 100 */
if ((delay = 9 - nt->nt_col) < 0)
delay = 0;
nt->nt_col = 0;
break;
}
if (delay) {
if (nt->nt_local & LFLUSHO)
break;
(*q->next->qinfo->putp)(q->next, ob);
if (ob = allocb(1)) {
ob->type = M_DELAY;
*ob->wptr++ = delay;
(*q->next->qinfo->putp)(q->next, ob);
}
ob = 0;
}
}
if (ib->class & S_DELIM) {
if (ob == NULL)
ob = allocb(0);
if (ob)
ob->class |= S_DELIM;
}
freeb(ib);
if (ob) {
if (nt->nt_local & LFLUSHO)
freeb(ob);
else
(*q->next->qinfo->putp)(q->next, ob);
}
}
/*
* Writer queue (tty output) service routine.
* All tty output comes through here. Upstream data comes in M_CTL
* blocks via ntout(); echoed data comes in M_DATA blocks.
*/
ntoutsrv (q)
register struct queue *q;
{
register struct nttyld *nt = (struct nttyld *) q->ptr;
register struct block *b;
while (b = getq (q))
switch (b->type) {
default:
freeb (b);
continue;
case M_BREAK:
if (q->next->flag & QFULL) {
putbq (q, b);
return;
}
(*q->next->qinfo->putp)(q->next, b);
continue;
case M_IOCTL:
if (q->next->flag & QFULL) {
putbq (q, b);
return;
}
ntioctl (q, b);
continue;
case M_FLUSH:
flushq (q, 0);
/* no break */
case M_IOCNAK:
case M_IOCACK:
(*q->next->qinfo->putp)(q->next, b);
continue;
case M_CTL:
case M_DATA:
if (nt->nt_local & LFLUSHO) {
freeb (b);
continue;
}
if (q->next->flag & QFULL) {
putbq (q, b);
return;
}
if (b->type == M_CTL) {
b->type = M_DATA;
nt->nt_trash = nt->nt_nin;
}
if (nt->nt_flags & RAW || nt->nt_local & LLITOUT) {
(*q->next->qinfo->putp)(q->next, b);
}
else ntoutb (nt, b);
continue;
}
return;
}
/*
* Reprint input buffer.
*/
ntreprint (nt)
register struct nttyld *nt;
{
register char *in;
register int nin;
if (nt->nt_rprntc != 0377)
ntecho ((int) nt->nt_rprntc, nt);
(void) putd (putq, nt->nt_outq, '\n');
for (in = nt->nt_in, nin = nt->nt_nin; nin > 0; in++, nin--)
ntecho (*in, nt);
nt->nt_lstate &= ~LSERASE;
nt->nt_trash = 0;
return;
}
/*
* Rubout the last character of the input buffer.
*/
ntrubout (nt)
register struct nttyld *nt;
{
register int c, cc, col, i;
if (nt->nt_nin <= 0)
return;
c = nt->nt_in[--nt->nt_nin];
if (!(nt->nt_flags & ECHO))
return;
nt->nt_local &= ~LFLUSHO;
if (nt->nt_local & LPRTERA) {
if (!(nt->nt_lstate & LSERASE)) {
(void) putd (putq, nt->nt_outq, '\\');
nt->nt_lstate |= LSERASE;
}
ntecho (c, nt);
return;
}
if (!(nt->nt_local & LCRTBS)) {
ntecho (nt->nt_erase, nt);
return;
}
if (nt->nt_trash > nt->nt_nin) {
ntreprint (nt);
return;
}
if (c == ('\t'|0200) || c == ('\n'|0200)) {
ntbs (nt, 2);
return;
}
switch (partab[c&=0177] & 0177) {
case ORDINARY:
if (nt->nt_flags&LCASE && c >= 'A' && c <= 'Z')
ntbs (nt, 2);
else ntbs (nt, 1);
break;
case TAB:
for (col = nt->nt_rocol, i = 0; i < nt->nt_nin; i++) {
cc = nt->nt_in[i];
if (cc == ('\t'|0200) || cc == ('\n'|0200)) {
col += 2;
continue;
}
switch (partab[cc&=0177] & 0177) {
case ORDINARY:
if (nt->nt_flags&LCASE && cc>='A' && cc<='Z')
col += 2;
else col++;
break;
case TAB:
col = (col + 8) & ~7;
break;
default:
if (nt->nt_local & LCTLECH)
col += 2;
break;
}
}
ntbs (nt, 8 - (col & 7));
break;
default:
if (nt->nt_local & LCTLECH)
ntbs (nt, 2);
break;
}
return;
}
/*
* Interpret the control characters that cause signals to be generated
* immediately: interrupt (^?), quit (^\), stop (^Z).
* Called from ntinc().
*/
int
ntsigc (c, nt)
register c;
register struct nttyld *nt;
{
if (c == nt->nt_intrc) {
ntflush (nt, FREAD | FWRITE);
(void) putctl1 (nt->nt_readq->next, M_SIGNAL, SIGINT);
}
else if (c == nt->nt_quitc) {
ntflush (nt, FREAD | FWRITE);
(void) putctl1 (nt->nt_readq->next, M_SIGNAL, SIGQUIT);
}
else if (c == nt->nt_suspc) {
ntflush (nt, FREAD);
(void) putctl1 (nt->nt_readq->next, M_SIGNAL, SIGTSTP);
}
else return (0);
ntecho (c, nt);
return (1);
}
/*
* Interpret the start (^S) and stop (^Q) control characters.
* Called from ntinc().
*/
int
ntstst (c, nt)
register int c;
register struct nttyld *nt;
{
if (nt->nt_state & NT_STOP) {
if (c == nt->nt_startc ||
!(nt->nt_local & LDECCTQ) &&
(c != nt->nt_stopc || nt->nt_stopc == nt->nt_startc)) {
if (putctl (nt->nt_outq->next, M_START))
nt->nt_state &= ~NT_STOP;
}
}
else if (c == nt->nt_stopc) {
if (putctl (nt->nt_outq->next, M_STOP))
nt->nt_state |= NT_STOP;
}
return (c == nt->nt_startc || c == nt->nt_stopc);
}
/*
* Erase the last word of the input buffer.
* Called from ntinc().
*/
ntwerase (nt)
register struct nttyld *nt;
{
register char *s;
for (s = nt->nt_in + nt->nt_nin - 1; s >= nt->nt_in; s--)
if (*s == ' ' || *s == '\t')
ntrubout (nt);
else break;
for (; s >= nt->nt_in; s--)
if (*s == ' ' || *s == '\t')
break;
else ntrubout (nt);
return;
}