X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/d1778415517f42c0917b262035f731c053f9ccbc..4147b3f690ea42bd015c9077ae49137621134f19:/usr/src/sys/kern/tty.c diff --git a/usr/src/sys/kern/tty.c b/usr/src/sys/kern/tty.c index 2b2318eaf3..b0a5156be6 100644 --- a/usr/src/sys/kern/tty.c +++ b/usr/src/sys/kern/tty.c @@ -1,7 +1,7 @@ -/* tty.c 3.9 %G% */ +/* tty.c 4.24 82/07/24 */ /* - * general TTY subroutines + * TTY subroutines common to more than one line discipline */ #include "../h/param.h" #include "../h/systm.h" @@ -9,7 +9,6 @@ #include "../h/user.h" #include "../h/tty.h" #include "../h/proc.h" -#include "../h/mx.h" #include "../h/inode.h" #include "../h/file.h" #include "../h/reg.h" @@ -17,19 +16,55 @@ #include "../h/buf.h" #include "../h/dk.h" -char partab[]; - /* - * When running dz's using only SAE (silo alarm) on input - * it is necessary to call dzrint() at clock interrupt time. - * This is unsafe unless spl5()s in tty code are changed to - * spl6()s to block clock interrupts. Note that the dh driver - * currently in use works the same way as the dz, even though - * we could try to more intelligently manage its silo. - * Thus don't take this out if you have no dz's unless you - * change clock.c and dhtimer(). + * Table giving parity for characters and indicating + * character classes to tty driver. In particular, + * if the low 6 bits are 0, then the character needs + * no special processing on output. */ -#define spl5 spl6 + +char partab[] = { + 0001,0201,0201,0001,0201,0001,0001,0201, + 0202,0004,0003,0201,0005,0206,0201,0001, + 0201,0001,0001,0201,0001,0201,0201,0001, + 0001,0201,0201,0001,0201,0001,0001,0201, + 0200,0000,0000,0200,0000,0200,0200,0000, + 0000,0200,0200,0000,0200,0000,0000,0200, + 0000,0200,0200,0000,0200,0000,0000,0200, + 0200,0000,0000,0200,0000,0200,0200,0000, + 0200,0000,0000,0200,0000,0200,0200,0000, + 0000,0200,0200,0000,0200,0000,0000,0200, + 0000,0200,0200,0000,0200,0000,0000,0200, + 0200,0000,0000,0200,0000,0200,0200,0000, + 0000,0200,0200,0000,0200,0000,0000,0200, + 0200,0000,0000,0200,0000,0200,0200,0000, + 0200,0000,0000,0200,0000,0200,0200,0000, + 0000,0200,0200,0000,0200,0000,0000,0201, + + /* + * 7 bit ascii ends with the last character above, + * but we contine through all 256 codes for the sake + * of the tty output routines which use special vax + * instructions which need a 256 character trt table. + */ + + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007, + 0007,0007,0007,0007,0007,0007,0007,0007 +}; /* * Input mapping table-- if an entry is non-zero, when the @@ -57,42 +92,13 @@ char maptab[] ={ 'X','Y','Z',000,000,000,000,000, }; - -/* - * shorthand - */ -#define q1 tp->t_rawq -#define q2 tp->t_canq -#define q3 tp->t_outq -#define q4 tp->t_un.t_ctlq +short tthiwat[16] = + { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 }; +short ttlowat[16] = + { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 }; #define OBUFSIZ 100 -/* - * routine called on first teletype open. - * establishes a process group for distribution - * of quits and interrupts from the tty. - */ -ttyopen(dev, tp) -dev_t dev; -register struct tty *tp; -{ - register struct proc *pp; - - pp = u.u_procp; - tp->t_dev = dev; - if(pp->p_pgrp == 0) { - u.u_ttyp = tp; - u.u_ttyd = dev; - if (tp->t_pgrp == 0) - tp->t_pgrp = pp->p_pid; - pp->p_pgrp = tp->t_pgrp; - } - tp->t_state &= ~WOPEN; - tp->t_state |= ISOPEN; - tp->t_line = 0; /* conservative */ -} - /* * set default control characters. */ @@ -115,120 +121,191 @@ register struct tty *tp; tlun.t_flushc = CTRL(o); tlun.t_werasc = CTRL(w); tlun.t_lnextc = CTRL(v); - tlun.t_lintr = CTRL(c); - tlun.t_lerase = CTRL(h); - tlun.t_lkill = CTRL(u); tp->t_local = 0; tp->t_lstate = 0; /* end local */ } /* - * clean tp on last close + * Wait for output to drain, then flush input waiting. */ -ttyclose(tp) -register struct tty *tp; +wflushtty(tp) + register struct tty *tp; { - tp->t_pgrp = 0; - wflushtty(tp); - tp->t_state = 0; - tp->t_line = 0; + (void) spl5(); + while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON + && tp->t_oproc) { /* kludge for pty */ + (*tp->t_oproc)(tp); + tp->t_state |= TS_ASLEEP; + sleep((caddr_t)&tp->t_outq, TTOPRI); + } + flushtty(tp, FREAD); + (void) spl0(); } /* - * stty/gtty writearound + * flush all TTY queues */ -stty() +flushtty(tp, rw) +register struct tty *tp; { - u.u_arg[2] = u.u_arg[1]; - u.u_arg[1] = TIOCSETP; - ioctl(); + register s; + + s = spl6(); + if (rw & FREAD) { + while (getc(&tp->t_canq) >= 0) + ; + wakeup((caddr_t)&tp->t_rawq); + } + if (rw & FWRITE) { + wakeup((caddr_t)&tp->t_outq); + tp->t_state &= ~TS_TTSTOP; + (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); + while (getc(&tp->t_outq) >= 0) + ; + } + if (rw & FREAD) { + while (getc(&tp->t_rawq) >= 0) + ; + tp->t_delct = 0; + tp->t_rocount = 0; /* local */ + tp->t_rocol = 0; + tp->t_lstate = 0; + } + splx(s); } -gtty() +/* + * Send stop character on input overflow. + */ +ttyblock(tp) +register struct tty *tp; { - u.u_arg[2] = u.u_arg[1]; - u.u_arg[1] = TIOCGETP; - ioctl(); + register x; + x = tp->t_rawq.c_cc + tp->t_canq.c_cc; + if (tp->t_rawq.c_cc > TTYHOG) { + flushtty(tp, FREAD|FWRITE); + tp->t_state &= ~TS_TBLOCK; + } + if (x >= TTYHOG/2) { + if (putc(tun.t_stopc, &tp->t_outq)==0) { + tp->t_state |= TS_TBLOCK; + tp->t_char++; + ttstart(tp); + } + } } /* - * Do nothing specific version of line - * discipline specific ioctl command. + * Restart typewriter output following a delay + * timeout. + * The name of the routine is passed to the timeout + * subroutine and it is called during a clock interrupt. */ -/*ARGSUSED*/ -nullioctl(tp, cmd, addr) +ttrstrt(tp) register struct tty *tp; -caddr_t addr; { - return (cmd); + if (tp == 0) { + printf("ttrstrt: arg was 0!\n"); + return; + } + tp->t_state &= ~TS_TIMEOUT; + ttstart(tp); } /* - * ioctl system call - * Check legality, execute common code, and switch out to individual - * device routine. + * Start output on the typewriter. It is used from the top half + * after some characters have been put on the output queue, + * from the interrupt routine to transmit the next + * character, and after a timeout has finished. */ -ioctl() +ttstart(tp) +register struct tty *tp; { - register struct file *fp; - register struct inode *ip; - register struct a { - int fdes; - int cmd; - caddr_t cmarg; - } *uap; - register dev_t dev; - register fmt; - - uap = (struct a *)u.u_ap; - if ((fp = getf(uap->fdes)) == NULL) - return; - if (uap->cmd==FIOCLEX) { - u.u_pofile[uap->fdes] |= EXCLOSE; - return; - } - if (uap->cmd==FIONCLEX) { - u.u_pofile[uap->fdes] &= ~EXCLOSE; - return; - } - ip = fp->f_inode; - fmt = ip->i_mode & IFMT; - if (fmt != IFCHR && fmt != IFMPC) { -/* begin local */ - if (uap->cmd==FIONREAD && (fmt == IFREG || fmt == IFDIR)) { - off_t nread = ip->i_size - fp->f_un.f_offset; + register s; - if (copyout((caddr_t)&nread, uap->cmarg, sizeof(off_t))) - u.u_error = EFAULT; - } else -/* end local */ - u.u_error = ENOTTY; - return; - } - dev = ip->i_un.i_rdev; - u.u_r.r_val1 = 0; - (*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, fp->f_flag); + s = spl5(); + if((tp->t_state&(TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 && + tp->t_oproc) /* kludge for pty */ + (*tp->t_oproc)(tp); + splx(s); } /* - * Common code for several tty ioctl commands + * Common code for tty ioctls. */ -ttioccomm(com, tp, addr, dev) +/*ARGSUSED*/ +ttioctl(tp, com, addr, flag) register struct tty *tp; caddr_t addr; { + int dev; unsigned t; struct sgttyb iocb; struct clist tq; extern int nldisp; + register c; + int temp; + /* + * This is especially so that isatty() will + * fail when carrier is gone. + */ + if ((tp->t_state&TS_CARR_ON) == 0) { + u.u_error = EBADF; + return (1); + } + + dev = tp->t_dev; + /* + * If the ioctl involves modification, + * insist on being able to write the device, + * and hang if in the background. + */ switch(com) { + case TIOCSETD: + case TIOCSETP: + case TIOCSETN: + case TIOCFLUSH: + case TIOCSETC: + case TIOCSLTC: + case TIOCSPGRP: + case TIOCLBIS: + case TIOCLBIC: + case TIOCLSET: + case TIOCSTI: +/* this is reasonable, but impractical... + if ((flag & FWRITE) == 0) { + u.u_error = EBADF; + return (1); + } + */ + while (tp->t_line == NTTYDISC && + u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && + (u.u_procp->p_flag&SVFORK) == 0 && + u.u_signal[SIGTTOU] != SIG_IGN && + u.u_signal[SIGTTOU] != SIG_HOLD +/* + && + (u.u_procp->p_flag&SDETACH)==0) { +*/ + ) { + gsignal(u.u_procp->p_pgrp, SIGTTOU); + sleep((caddr_t)&lbolt, TTOPRI); + } + break; + } + /* - * get discipline number + * Process the ioctl. + */ + switch(com) { + + /* + * Get discipline number */ case TIOCGETD: t = tp->t_line; @@ -237,7 +314,7 @@ caddr_t addr; break; /* - * set line discipline + * Set line discipline */ case TIOCSETD: if (copyin(addr, (caddr_t)&t, sizeof(t))) { @@ -259,14 +336,14 @@ caddr_t addr; break; /* - * prevent more opens on channel + * Prevent more opens on channel */ case TIOCEXCL: - tp->t_state |= XCLUDE; + tp->t_state |= TS_XCLUDE; break; case TIOCNXCL: - tp->t_state &= ~XCLUDE; + tp->t_state &= ~TS_XCLUDE; break; /* @@ -279,44 +356,34 @@ caddr_t addr; return(1); } (void) spl5(); - if (tp->t_line == 0) { - if (com == TIOCSETP) - wflushtty(tp); - while (canon(tp)>=0) - ; - } else if (tp->t_line == NTTYDISC) { - if (tp->t_flags&RAW || iocb.sg_flags&RAW || - com == TIOCSETP) - wflushtty(tp); - else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) { - if (iocb.sg_flags & CBREAK) { - catq(&tp->t_rawq, &tp->t_canq); - tq = tp->t_rawq; - tp->t_rawq = tp->t_canq; - tp->t_canq = tq; - } else { - tp->t_local |= LPENDIN; - if (tp->t_canq.c_cc) - panic("ioccom canq"); - if (tp->t_chan) - (void) sdata(tp->t_chan); - else - wakeup((caddr_t)&tp->t_rawq); - } + if (tp->t_flags&RAW || iocb.sg_flags&RAW || + com == TIOCSETP) + wflushtty(tp); + else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) { + if (iocb.sg_flags & CBREAK) { + catq(&tp->t_rawq, &tp->t_canq); + tq = tp->t_rawq; + tp->t_rawq = tp->t_canq; + tp->t_canq = tq; + } else { + tp->t_local |= LPENDIN; + ttwakeup(tp); } } - if ((tp->t_state&SPEEDS)==0) { - tp->t_ispeed = iocb.sg_ispeed; - tp->t_ospeed = iocb.sg_ospeed; - } + tp->t_ispeed = iocb.sg_ispeed; + tp->t_ospeed = iocb.sg_ospeed; tp->t_erase = iocb.sg_erase; tp->t_kill = iocb.sg_kill; tp->t_flags = iocb.sg_flags; + if (tp->t_flags & RAW) { + tp->t_state &= ~TS_TTSTOP; + ttstart(tp); + } (void) spl0(); break; /* - * send current parameters to user + * Send current parameters to user */ case TIOCGETP: iocb.sg_ispeed = tp->t_ispeed; @@ -331,26 +398,50 @@ caddr_t addr; /* * Hang up line on last close */ - case TIOCHPCL: - tp->t_state |= HUPCLS; + tp->t_state |= TS_HUPCLS; break; - case TIOCFLUSH: - flushtty(tp); + case TIOCFLUSH: { + int flags; + if (addr == 0) + flags = FREAD|FWRITE; + else if (copyin(addr, (caddr_t)&flags, sizeof (flags))) { + u.u_error = EFAULT; + return(1); + } + flushtty(tp, flags); break; + } - /* - * ioctl entries to line discipline - */ - case DIOCSETP: - case DIOCGETP: - if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr)) - u.u_error = ENOTTY; + case FIONBIO: { + int nbio; + if (copyin(addr, (caddr_t)&nbio, sizeof (nbio))) { + u.u_error = EFAULT; + return(1); + } + if (nbio) + tp->t_state |= TS_NBIO; + else + tp->t_state &= ~TS_NBIO; break; + } + + case FIOASYNC: { + int async; + if (copyin(addr, (caddr_t)&async, sizeof (async))) { + u.u_error = EFAULT; + return(1); + } + if (async) + tp->t_state |= TS_ASYNC; + else + tp->t_state &= ~TS_ASYNC; + break; + } /* - * set and fetch special characters + * Set and fetch special characters */ case TIOCSETC: if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) @@ -363,6 +454,9 @@ caddr_t addr; break; /* local ioctls */ + /* + * Set/get local special characters. + */ case TIOCSLTC: if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) u.u_error = EFAULT; @@ -373,25 +467,11 @@ caddr_t addr; u.u_error = EFAULT; break; + /* + * Return number of characters immediately available. + */ case FIONREAD: { - off_t nread; - - switch (tp->t_line) { - - case NETLDISC: - nread = tp->t_rec ? tp->t_inbuf : 0; - break; - - case NTTYDISC: - nread = tp->t_canq.c_cc; - if (tp->t_flags & (RAW|CBREAK)) - nread += tp->t_rawq.c_cc; - break; - - case 0: - /* do something here ... */ - ; - } + off_t nread = ttnread(tp); if (copyout((caddr_t)&nread, addr, sizeof (off_t))) u.u_error = EFAULT; break; @@ -401,7 +481,8 @@ caddr_t addr; * Should allow SPGRP and GPGRP only if tty open for reading. */ case TIOCSPGRP: - tp->t_pgrp = (int)addr; + if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp))) + u.u_error = EFAULT; break; case TIOCGPGRP: @@ -413,15 +494,24 @@ caddr_t addr; * Modify local mode word. */ case TIOCLBIS: - tp->t_local |= (int)addr; + if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) + u.u_error = EFAULT; + else + tp->t_local |= temp; break; case TIOCLBIC: - tp->t_local &= ~(int)addr; + if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) + u.u_error = EFAULT; + else + tp->t_local &= ~temp; break; case TIOCLSET: - tp->t_local = (int)addr; + if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) + u.u_error = EFAULT; + else + tp->t_local = temp; break; case TIOCLGET: @@ -429,156 +519,167 @@ caddr_t addr; u.u_error = EFAULT; break; + /* + * Return number of characters in + * the output. + */ case TIOCOUTQ: if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc))) u.u_error = EFAULT; break; + /* + * Simulate typing of a character at the terminal. + */ + case TIOCSTI: + c = fubyte(addr); + if (u.u_uid && u.u_ttyp != tp || c < 0) + u.u_error = EFAULT; + else + (*linesw[tp->t_line].l_rint)(c, tp); + break; + + case TIOCSTOP: + c = spl5(); + if ((tp->t_state & TS_TTSTOP) == 0) { + tp->t_state |= TS_TTSTOP; + (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); + } + splx(c); + break; + + case TIOCSTART: + c = spl5(); + if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) { + tp->t_state &= ~TS_TTSTOP; + tp->t_local &= ~LFLUSHO; + ttstart(tp); + } + splx(c); + break; + /* end of locals */ + default: return(0); } return(1); } -/* - * Wait for output to drain, then flush input waiting. - */ -wflushtty(tp) -register struct tty *tp; +ttnread(tp) + struct tty *tp; { + int nread = 0; + + if (tp->t_local & LPENDIN) + ttypend(tp); + nread = tp->t_canq.c_cc; + if (tp->t_flags & (RAW|CBREAK)) + nread += tp->t_rawq.c_cc; + return (nread); +} - (void) spl5(); - while (tp->t_outq.c_cc && tp->t_state&CARR_ON) { - (*tp->t_oproc)(tp); - tp->t_state |= ASLEEP; - sleep((caddr_t)&tp->t_outq, TTOPRI); +ttselect(dev, rw) + dev_t dev; + int rw; +{ + register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; + int nread; + int s = spl5(); + + switch (rw) { + + case FREAD: + nread = ttnread(tp); + if (nread > 0) + goto win; + if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) + tp->t_state |= TS_RCOLL; + else + tp->t_rsel = u.u_procp; + break; + + case FWRITE: + if (tp->t_outq.c_cc <= TTLOWAT(tp)) + goto win; + if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) + tp->t_state |= TS_WCOLL; + else + tp->t_wsel = u.u_procp; + break; } - flushtty(tp); - (void) spl0(); + splx(s); + return (0); +win: + splx(s); + return (1); } +#define OBUFSIZ 100 + /* - * flush all TTY queues + * routine called on opens while tp->t_line == NTTYDISC + * establishes a process group for distribution of + * quits and interrupts from the tty. + * (actually, pp->p_pgrp can't be 0 when this routine + * is called since NTTYDISC is not the default discipline) */ -flushtty(tp) +ttyopen(dev, tp) +dev_t dev; register struct tty *tp; { - register s; + register struct proc *pp; - if (tp->t_line == NETLDISC) - return; - s = spl6(); - while (getc(&tp->t_canq) >= 0) - ; - wakeup((caddr_t)&tp->t_rawq); - wakeup((caddr_t)&tp->t_outq); - tp->t_state &= ~TTSTOP; - (*cdevsw[major(tp->t_dev)].d_stop)(tp); - while (getc(&tp->t_outq) >= 0) - ; - while (getc(&tp->t_rawq) >= 0) - ; - tp->t_delct = 0; - tp->t_rocount = 0; /* local */ - tp->t_lstate = 0; - splx(s); + pp = u.u_procp; + tp->t_dev = dev; + if(pp->p_pgrp == 0) { + u.u_ttyp = tp; + u.u_ttyd = dev; + if (tp->t_pgrp == 0) + tp->t_pgrp = pp->p_pid; + pp->p_pgrp = tp->t_pgrp; + } + tp->t_state &= ~TS_WOPEN; + tp->t_state |= TS_ISOPEN; + if (tp->t_line != NTTYDISC) + wflushtty(tp); } - - /* - * transfer raw input list to canonical list, - * doing erase-kill processing and handling escapes. - * It waits until a full line has been typed in cooked mode, - * or until any character has been typed in raw mode. + * clean tp on last close */ -canon(tp) +ttyclose(tp) register struct tty *tp; { - register char *bp; - char *bp1; - register int c; - int mc; - int s; - - if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0 - || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) { - return(-1); - } - s = spl0(); -loop: - bp = &canonb[2]; - while ((c=getc(&tp->t_rawq)) >= 0) { - if ((tp->t_flags&(RAW|CBREAK))==0) { - if (c==0377) { - tp->t_delct--; - break; - } - if (bp[-1]!='\\') { - if (c==tp->t_erase) { - if (bp > &canonb[2]) - bp--; - continue; - } - if (c==tp->t_kill) - goto loop; - if (c==tun.t_eofc) - continue; - } else { - mc = maptab[c]; - if (c==tp->t_erase || c==tp->t_kill) - mc = c; - if (mc && (mc==c || (tp->t_flags&LCASE))) { - if (bp[-2] != '\\') - c = mc; - bp--; - } - } - } - *bp++ = c; - if (bp>=canonb+CANBSIZ) - break; - } - bp1 = &canonb[2]; - (void) b_to_q(bp1, bp-bp1, &tp->t_canq); - if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { - if (putc(tun.t_startc, &tp->t_outq)==0) { - tp->t_state &= ~TBLOCK; - ttstart(tp); - } - tp->t_char = 0; + if (tp->t_line) { + wflushtty(tp); + tp->t_line = 0; + return; } - - splx(s); - return(0); + tp->t_pgrp = 0; + wflushtty(tp); + tp->t_state = 0; } - /* - * block transfer input handler. + * reinput pending characters after state switch + * call at spl5(). */ -ttyrend(tp, pb, pe) +ttypend(tp) register struct tty *tp; -register char *pb, *pe; { - int tandem; - - tandem = tp->t_flags&TANDEM; - if (tp->t_flags&RAW) { - (void) b_to_q(pb, pe-pb, &tp->t_rawq); - if (tp->t_chan) - (void) sdata(tp->t_chan); else - wakeup((caddr_t)&tp->t_rawq); - } else { - tp->t_flags &= ~TANDEM; - while (pb < pe) - ttyinput(*pb++, tp); - tp->t_flags |= tandem; - } - if (tandem) - ttyblock(tp); + struct clist tq; + register c; + + tp->t_local &= ~LPENDIN; + tp->t_lstate |= LSTYPEN; + tq = tp->t_rawq; + tp->t_rawq.c_cc = 0; + tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; + while ((c = getc(&tq)) >= 0) + ttyinput(c, tp); + tp->t_lstate &= ~LSTYPEN; } /* @@ -593,88 +694,163 @@ register c; register struct tty *tp; { register int t_flags; - register struct chan *cp; + int i; - tk_nin += 1; + if (tp->t_local&LPENDIN) + ttypend(tp); + tk_nin++; c &= 0377; t_flags = tp->t_flags; if (t_flags&TANDEM) ttyblock(tp); if ((t_flags&RAW)==0) { - c &= 0177; - if (tp->t_state&TTSTOP) { - if (c==tun.t_startc) { - tp->t_state &= ~TTSTOP; - ttstart(tp); + if ((tp->t_lstate&LSTYPEN) == 0) + c &= 0177; + /* check for literal nexting very first */ + if (tp->t_lstate&LSLNCH) { + c |= 0200; + tp->t_lstate &= ~LSLNCH; + } + if (tp->t_line == NTTYDISC && c==tlun.t_lnextc) { + if (tp->t_flags&ECHO) + ttyout("^\b", tp); + tp->t_lstate |= LSLNCH; + /* check for output control functions */ + } else if (c==tun.t_stopc) { + if ((tp->t_state&TS_TTSTOP)==0) { + tp->t_state |= TS_TTSTOP; + (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); return; } - if (c==tun.t_stopc) + if (c!=tun.t_startc) return; - tp->t_state &= ~TTSTOP; + } else if (c==tun.t_startc) { + tp->t_state &= ~TS_TTSTOP; + tp->t_local &= ~LFLUSHO; ttstart(tp); - } else { - if (c==tun.t_stopc) { - tp->t_state |= TTSTOP; - (*cdevsw[major(tp->t_dev)].d_stop)(tp); - return; + return; + } else if (tp->t_line == NTTYDISC && c==tlun.t_flushc) { + if (tp->t_local & LFLUSHO) + tp->t_local &= ~LFLUSHO; + else { + flushtty(tp, FWRITE); + ttyecho(c, tp); + if (tp->t_rawq.c_cc+tp->t_canq.c_cc) + ttyretype(tp); + tp->t_local |= LFLUSHO; } - if (c==tun.t_startc) - return; - } - if (c==tun.t_quitc || c==tun.t_intrc) { - flushtty(tp); - c = (c==tun.t_intrc) ? SIGINT:SIGQUIT; - if (tp->t_chan) - scontrol(tp->t_chan, M_SIG, c); - else - gsignal(tp->t_pgrp, c); + ttstart(tp); return; + } else if (c==tun.t_intrc || c==tun.t_quitc || + (tp->t_line == NTTYDISC && c==tlun.t_suspc)) { + if ((tp->t_local & LNOFLSH) == 0) + flushtty(tp, + c==tlun.t_suspc ? FREAD : FREAD|FWRITE); + ttyecho(c, tp); + c = c==tun.t_intrc ? SIGINT : + ((c==tun.t_quitc) ? SIGQUIT : SIGTSTP); + ttsignal(tp, c); + /* check for buffer editing functions - cooked mode */ + } else if ((t_flags&CBREAK) == 0) { + if ((tp->t_lstate&LSQUOT) && + (c==tp->t_erase||c==tp->t_kill)) { + ttyrub(unputc(&tp->t_rawq), tp); + c |= 0200; + } + if (c==tp->t_erase) { + if (tp->t_rawq.c_cc) + ttyrub(unputc(&tp->t_rawq), tp); + } else if (c==tp->t_kill) { + if (tp->t_local&LCRTKIL && + tp->t_rawq.c_cc == tp->t_rocount) { + while (tp->t_rawq.c_cc) + ttyrub(unputc(&tp->t_rawq), tp); + } else { + ttyecho(c, tp); + ttyecho('\n', tp); + while (getc(&tp->t_rawq) > 0) + ; + tp->t_rocount = 0; + } + tp->t_lstate = 0; + } else if (tp->t_line == NTTYDISC && c==tlun.t_werasc) { + if (tp->t_rawq.c_cc == 0) + goto out; + do { + c = unputc(&tp->t_rawq); + if (c != ' ' && c != '\t') + goto erasenb; + ttyrub(c, tp); + } while (tp->t_rawq.c_cc); + goto out; + erasenb: + do { + ttyrub(c, tp); + if (tp->t_rawq.c_cc == 0) + goto out; + c = unputc(&tp->t_rawq); + } while (c != ' ' && c != '\t'); + (void) putc(c, &tp->t_rawq); + } else if (tp->t_line == NTTYDISC && c==tlun.t_rprntc) { + ttyretype(tp); + /* check for cooked mode input buffer overflow */ + } else if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { + ; + /* put data char in q for user and wakeup if a break char */ + } else if (putc(c, &tp->t_rawq) >= 0) { + if (tp->t_rawq.c_cc+tp->t_canq.c_cc==TTYHOG + && tp->t_line == NTTYDISC) + (void) ttyoutput(CTRL(g), tp); + if (!ttbreakc(c, tp)) { + if (tp->t_rocount++ == 0) + tp->t_rocol = tp->t_col; + } else { + tp->t_rocount = 0; + catq(&tp->t_rawq, &tp->t_canq); + /* IF (TP->T_CHAN) (VOID) SDATA(TP->T_CHAN); */ + ttwakeup(tp); + } + tp->t_lstate &= ~LSQUOT; + if (c == '\\') + tp->t_lstate |= LSQUOT; + if (tp->t_lstate&LSERASE) { + tp->t_lstate &= ~LSERASE; + (void) ttyoutput('/', tp); + } + i = tp->t_col; + ttyecho(c, tp); + if (c==tun.t_eofc && tp->t_flags&ECHO) { + i = MIN(2, tp->t_col - i); + while (i > 0) { + (void) ttyoutput('\b', tp); + i--; + } + } + } + /* CBREAK mode */ + } else if (tp->t_rawq.c_cc > TTYHOG) { + if (tp->t_outq.c_cc < TTHIWAT(tp) && + tp->t_line == NTTYDISC) + (void) ttyoutput(CTRL(g), tp); + } else if (putc(c, &tp->t_rawq) >= 0) { + ttwakeup(tp); + ttyecho(c, tp); } - if (c=='\r' && t_flags&CRMOD) - c = '\n'; + /* RAW mode */ + } else if (tp->t_rawq.c_cc > TTYHOG) + flushtty(tp, FREAD|FWRITE); + else { + if (putc(c, &tp->t_rawq) >= 0) + ttwakeup(tp); + ttyecho(c, tp); } - if (tp->t_rawq.c_cc>TTYHOG) { - flushtty(tp); +out: + if (tp->t_local & LDECCTQ && tp->t_state & TS_TTSTOP && + tun.t_startc != tun.t_stopc) return; - } - if (t_flags&LCASE && c>='A' && c<='Z') - c += 'a'-'A'; - (void) putc(c, &tp->t_rawq); - if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) { - if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0) - tp->t_delct++; - if ((cp=tp->t_chan)!=NULL) - (void) sdata(cp); else - wakeup((caddr_t)&tp->t_rawq); - } - if (t_flags&ECHO) { - ttyoutput(c, tp); - if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0) - ttyoutput('\n', tp); - ttstart(tp); - } -} - - -/* - * Send stop character on input overflow. - */ -ttyblock(tp) -register struct tty *tp; -{ - register x; - x = q1.c_cc + q2.c_cc; - if (q1.c_cc > TTYHOG) { - flushtty(tp); - tp->t_state &= ~TBLOCK; - } - if (x >= TTYHOG/2) { - if (putc(tun.t_stopc, &tp->t_outq)==0) { - tp->t_state |= TBLOCK; - tp->t_char++; - ttstart(tp); - } - } + tp->t_state &= ~TS_TTSTOP; + tp->t_local &= ~LFLUSHO; + ttstart(tp); } /* @@ -683,38 +859,46 @@ register struct tty *tp; * It is called both from the top half for output, and from * interrupt level for echoing. * The arguments are the character and the tty structure. + * Returns < 0 if putc succeeds, otherwise returns char to resend + * Must be recursive. */ ttyoutput(c, tp) -register c; -register struct tty *tp; + register c; + register struct tty *tp; { register char *colp; register ctype; + if (tp->t_flags&RAW || tp->t_local&LLITOUT) { + if (tp->t_local&LFLUSHO) + return (-1); + if (putc(c, &tp->t_outq)) + return(c); + tk_nout++; + return (-1); + } /* * Ignore EOT in normal mode to avoid hanging up * certain terminals. - * In raw mode dump the char unchanged. */ - if ((tp->t_flags&RAW)==0) { - c &= 0177; - if ((tp->t_flags&CBREAK)==0 && c==CEOT) - return; - } else { - tk_nout++; - (void) putc(c, &tp->t_outq); - return; - } - + c &= 0177; + if (c==CEOT && (tp->t_flags&CBREAK)==0) + return (-1); /* * Turn tabs to spaces as required */ if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) { - c = 8 - (tp->t_col & 7); - (void) b_to_q(" ", c, &tp->t_outq); + register int s; + + c = 8 - (tp->t_col&7); + if ((tp->t_local&LFLUSHO) == 0) { + s = spl5(); /* don't interrupt tabs */ + c -= b_to_q(" ", c, &tp->t_outq); + tk_nout += c; + splx(s); + } tp->t_col += c; - tk_nout += c; - return; + return (c ? -1 : '\t'); } tk_nout++; /* @@ -725,19 +909,27 @@ register struct tty *tp; colp = "({)}!|^~'`"; while(*colp++) if(c == *colp++) { - ttyoutput('\\', tp); + if (ttyoutput('\\', tp) >= 0) + return (c); c = colp[-2]; break; } - if ('a'<=c && c<='z') + if ('A'<=c && c<='Z') { + if (ttyoutput('\\', tp) >= 0) + return (c); + } else if ('a'<=c && c<='z') c += 'A' - 'a'; } /* * turn to if desired. */ if (c=='\n' && tp->t_flags&CRMOD) - ttyoutput('\r', tp); - (void) putc(c, &tp->t_outq); + if (ttyoutput('\r', tp) >= 0) + return (c); + if (c=='~' && tp->t_local<ILDE) + c = '`'; + if ((tp->t_local&LFLUSHO) == 0 && putc(c, &tp->t_outq)) + return (c); /* * Calculate delays. * The numbers here represent clock ticks @@ -751,22 +943,18 @@ register struct tty *tp; c = 0; switch (ctype&077) { - /* ordinary */ - case 0: + case ORDINARY: (*colp)++; - /* non-printing */ - case 1: + case CONTROL: break; - /* backspace */ - case 2: + case BACKSPACE: if (*colp) (*colp)--; break; - /* newline */ - case 3: + case NEWLINE: ctype = (tp->t_flags >> 8) & 03; if(ctype == 1) { /* tty 37 */ if (*colp) @@ -778,8 +966,7 @@ register struct tty *tp; *colp = 0; break; - /* tab */ - case 4: + case TAB: ctype = (tp->t_flags >> 10) & 03; if(ctype == 1) { /* tty 37 */ c = 1 - (*colp | ~07); @@ -790,14 +977,12 @@ register struct tty *tp; (*colp)++; break; - /* vertical motion */ - case 5: + case VTAB: if(tp->t_flags & VTDELAY) /* tty 37 */ c = 0177; break; - /* carriage return */ - case 6: + case RETURN: ctype = (tp->t_flags >> 12) & 03; if(ctype == 1) { /* tn 300 */ c = 5; @@ -805,44 +990,15 @@ register struct tty *tp; c = 10; } else if(ctype == 3) { /* concept 100 */ int i; - for (i= *colp; i<9; i++) - (void) putc(0177, &tp->t_outq); + if ((i = *colp) >= 0) + for (; i<9; i++) + (void) putc(0177, &tp->t_outq); } *colp = 0; } - if(c) + if(c && (tp->t_local&LFLUSHO) == 0) (void) putc(c|0200, &tp->t_outq); -} - -/* - * Restart typewriter output following a delay - * timeout. - * The name of the routine is passed to the timeout - * subroutine and it is called during a clock interrupt. - */ -ttrstrt(tp) -register struct tty *tp; -{ - - tp->t_state &= ~TIMEOUT; - ttstart(tp); -} - -/* - * Start output on the typewriter. It is used from the top half - * after some characters have been put on the output queue, - * from the interrupt routine to transmit the next - * character, and after a timeout has finished. - */ -ttstart(tp) -register struct tty *tp; -{ - register s; - - s = spl5(); - if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0) - (*tp->t_oproc)(tp); - splx(s); + return (-1); } /* @@ -852,23 +1008,100 @@ register struct tty *tp; ttread(tp) register struct tty *tp; { -register s; + register struct clist *qp; + register c, first; - if ((tp->t_state&CARR_ON)==0) - return(-1); - s = spl5(); - if (tp->t_canq.c_cc==0) - while (canon(tp)<0) - if (tp->t_chan==NULL) { - sleep((caddr_t)&tp->t_rawq, TTIPRI); - } else { - splx(s); - return(0); + if ((tp->t_state&TS_CARR_ON)==0) + return(0); +loop: + (void) spl5(); + if (tp->t_local&LPENDIN) + ttypend(tp); + (void) spl0(); + while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { + if (u.u_signal[SIGTTIN] == SIG_IGN || + u.u_signal[SIGTTIN] == SIG_HOLD || +/* + (u.u_procp->p_flag&SDETACH) || +*/ + u.u_procp->p_flag&SVFORK) + return (0); + gsignal(u.u_procp->p_pgrp, SIGTTIN); + sleep((caddr_t)&lbolt, TTIPRI); + } + if (tp->t_flags&RAW) { + (void) spl5(); + if (tp->t_rawq.c_cc <= 0) { + if ((tp->t_state&TS_CARR_ON)==0 || + (tp->t_state&TS_NBIO)) { + (void) spl0(); + return (0); } - splx(s); - while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0) + sleep((caddr_t)&tp->t_rawq, TTIPRI); + (void) spl0(); + goto loop; + } + (void) spl0(); + while (tp->t_rawq.c_cc && passc(getc(&tp->t_rawq))>=0) ; - return(tp->t_rawq.c_cc+tp->t_canq.c_cc); + return (0); + } else { + qp = tp->t_flags & CBREAK ? &tp->t_rawq : &tp->t_canq; + (void) spl5(); + if (qp->c_cc <= 0) { + if ((tp->t_state&TS_CARR_ON)==0 || + (tp->t_state&TS_NBIO)) { + (void) spl0(); + return (0); + } + sleep((caddr_t)&tp->t_rawq, TTIPRI); + (void) spl0(); + goto loop; + } + (void) spl0(); + first = 1; + while ((c = getc(qp)) >= 0) { + if (tp->t_flags&CRMOD && c == '\r') + c = '\n'; + if (tp->t_flags&LCASE && c <= 0177) + if (tp->t_lstate&LSBKSL) { + if (maptab[c]) + c = maptab[c]; + tp->t_lstate &= ~LSBKSL; + } else if (c >= 'A' && c <= 'Z') + c += 'a' - 'A'; + else if (c == '\\') { + tp->t_lstate |= LSBKSL; + continue; + } + if (c == tlun.t_dsuspc) { + ttsignal(tp, SIGTSTP); + if (first) { + sleep((caddr_t)&lbolt, TTIPRI); + goto loop; + } + break; + } + if (c == tun.t_eofc && (tp->t_flags&CBREAK)==0) + break; + if (passc(c & 0177) < 0) + break; + if ((tp->t_flags&CBREAK)==0 && ttbreakc(c, tp)) + break; + first = 0; + } + tp->t_lstate &= ~LSBKSL; + } + + if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { + if (putc(tun.t_startc, &tp->t_outq)==0) { + tp->t_state &= ~TS_TBLOCK; + ttstart(tp); + } + tp->t_char = 0; + } + + return (tp->t_rawq.c_cc + tp->t_canq.c_cc); } /* @@ -879,79 +1112,324 @@ caddr_t ttwrite(tp) register struct tty *tp; { +#ifdef vax /* * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL * AND MUST NOT BE CHANGED WITHOUT PATCHING * THE 'ASM' INLINES BELOW. WATCH OUT. */ +#endif register char *cp; register int cc, ce; register i; char obuf[OBUFSIZ]; + register c; + int hiwat = TTHIWAT(tp); + int cnt = u.u_count; - if ((tp->t_state&CARR_ON)==0) - return(NULL); + if ((tp->t_state&TS_CARR_ON)==0) + return (NULL); +loop: + while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && + (tp->t_local<OSTOP) && (u.u_procp->p_flag&SVFORK)==0 && + u.u_signal[SIGTTOU] != SIG_IGN && + u.u_signal[SIGTTOU] != SIG_HOLD +/* + && + (u.u_procp->p_flag&SDETACH)==0) { +*/ + ) { + gsignal(u.u_procp->p_pgrp, SIGTTOU); + sleep((caddr_t)&lbolt, TTIPRI); + } while (u.u_count) { cc = MIN(u.u_count, OBUFSIZ); cp = obuf; iomove(cp, (unsigned)cc, B_WRITE); if (u.u_error) break; - (void) spl5(); - while (tp->t_outq.c_cc > TTHIWAT) { - ttstart(tp); - tp->t_state |= ASLEEP; - if (tp->t_chan) { - u.u_base -= cc; - u.u_offset -= cc; - u.u_count += cc; - (void) spl0(); - return((caddr_t)&tp->t_outq); + if (tp->t_outq.c_cc > hiwat) + goto ovhiwat; + if (tp->t_local&LFLUSHO) + continue; + if (tp->t_flags&LCASE || tp->t_local<ILDE) { + while (cc) { + c = *cp++; + tp->t_rocount = 0; + while((c = ttyoutput(c, tp)) >= 0) { + /* out of clists, wait a bit */ + ttstart(tp); + sleep((caddr_t)&lbolt, TTOPRI); + tp->t_rocount = 0; + } + --cc; + if (tp->t_outq.c_cc > hiwat) + goto ovhiwat; } - sleep((caddr_t)&tp->t_outq, TTOPRI); - } - (void) spl0(); - if (tp->t_flags&LCASE) { - while (cc--) - ttyoutput(*cp++,tp); continue; } while (cc) { - if (tp->t_flags&RAW) - ce=cc; + if (tp->t_flags&RAW || tp->t_local&LLITOUT) + ce = cc; else { -#ifdef VAX +#ifdef vax asm(" scanc r9,(r10),_partab,$077"); asm(" subl3 r0,r9,r8"); #else ce=0; - while(((partab[*(cp+ce)]&077)==0)&&(cet_rocount = 0; + if (ttyoutput(*cp, tp) >= 0) { + ttstart(tp); + sleep((caddr_t)&lbolt, TTOPRI); + continue; + } + cp++; cc--; - goto check; + if (tp->t_outq.c_cc > hiwat) + goto ovhiwat; } } + tp->t_rocount = 0; i=b_to_q(cp,ce,&tp->t_outq); ce-=i; tk_nout+=ce; tp->t_col+=ce; cp+=ce; cc-=ce; -check: - if (tp->t_outq.c_cc > TTHIWAT) { - (void) spl5(); - while (tp->t_outq.c_cc > TTHIWAT) { - ttstart(tp); - tp->t_state |= ASLEEP; - sleep((caddr_t)&tp->t_outq, TTOPRI); - } - (void) spl0(); + if (i) { + ttstart(tp); + sleep((caddr_t)&lbolt, TTOPRI); } + if (ce || tp->t_outq.c_cc > hiwat) + goto ovhiwat; } } ttstart(tp); return(NULL); + +ovhiwat: + (void) spl5(); + u.u_base -= cc; + u.u_offset -= cc; + u.u_count += cc; + if (tp->t_outq.c_cc <= hiwat) { + (void) spl0(); + goto loop; + } + ttstart(tp); + if (tp->t_state & TS_NBIO) { + if (u.u_count == cnt) + u.u_error = EWOULDBLOCK; + return (NULL); + } + tp->t_state |= TS_ASLEEP; + sleep((caddr_t)&tp->t_outq, TTOPRI); + (void) spl0(); + goto loop; +} + +/* + * Rubout one character from the rawq of tp + * as cleanly as possible. + */ +ttyrub(c, tp) +register c; +register struct tty *tp; +{ + register char *cp; + register int savecol; + int s; + char *nextc(); + + if ((tp->t_flags&ECHO)==0) + return; + tp->t_local &= ~LFLUSHO; + c &= 0377; + if (tp->t_local&LCRTBS) { + if (tp->t_rocount == 0) { + /* + * Screwed by ttwrite; retype + */ + ttyretype(tp); + return; + } + if (c==('\t'|0200) || c==('\n'|0200)) + ttyrubo(tp, 2); + else switch(partab[c&=0177] & 0177) { + + case ORDINARY: + if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') + ttyrubo(tp, 2); + else + ttyrubo(tp, 1); + break; + + case VTAB: + case BACKSPACE: + case CONTROL: + case RETURN: + if (tp->t_local & LCTLECH) + ttyrubo(tp, 2); + break; + + case TAB: + if (tp->t_rocount < tp->t_rawq.c_cc) { + ttyretype(tp); + return; + } + s = spl5(); + savecol = tp->t_col; + tp->t_lstate |= LSCNTTB; + tp->t_local |= LFLUSHO; + tp->t_col = tp->t_rocol; + for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) + ttyecho(*cp, tp); + tp->t_local &= ~LFLUSHO; + tp->t_lstate &= ~LSCNTTB; + splx(s); + /* + * savecol will now be length of the tab + */ + savecol -= tp->t_col; + tp->t_col += savecol; + if (savecol > 8) + savecol = 8; /* overflow screw */ + while (--savecol >= 0) + (void) ttyoutput('\b', tp); + break; + + default: + panic("ttyrub"); + } + } else if (tp->t_local&LPRTERA) { + if ((tp->t_lstate&LSERASE) == 0) { + (void) ttyoutput('\\', tp); + tp->t_lstate |= LSERASE; + } + ttyecho(c, tp); + } else + ttyecho(tp->t_erase, tp); + tp->t_rocount--; +} + +/* + * Crt back over cnt chars perhaps + * erasing them. + */ +ttyrubo(tp, cnt) +register struct tty *tp; +int cnt; +{ + + while (--cnt >= 0) + ttyout(tp->t_local&LCRTERA ? "\b \b" : "\b", tp); +} + +/* + * Reprint the rawq line. + * We assume c_cc has already been checked. + */ +ttyretype(tp) +register struct tty *tp; +{ + register char *cp; + char *nextc(); + int s; + + if (tlun.t_rprntc != 0377) + ttyecho(tlun.t_rprntc, tp); + (void) ttyoutput('\n', tp); + s = spl5(); + for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) + ttyecho(*cp, tp); + for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) + ttyecho(*cp, tp); + tp->t_lstate &= ~LSERASE; + splx(s); + tp->t_rocount = tp->t_rawq.c_cc; + tp->t_rocol = 0; +} + +/* + * Echo a typed character to the terminal + */ +ttyecho(c, tp) +register c; +register struct tty *tp; +{ + + if ((tp->t_lstate & LSCNTTB) == 0) + tp->t_local &= ~LFLUSHO; + if ((tp->t_flags&ECHO) == 0) + return; + c &= 0377; + if (tp->t_flags&RAW) { + (void) ttyoutput(c, tp); + return; + } + if (c == '\r' && tp->t_flags&CRMOD) + c = '\n'; + if (tp->t_local&LCTLECH) { + if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { + (void) ttyoutput('^', tp); + c &= 0177; + if (c == 0177) + c = '?'; + else if (tp->t_flags&LCASE) + c += 'a' - 1; + else + c += 'A' - 1; + } + } + if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) + c += 'a' - 'A'; + (void) ttyoutput(c & 0177, tp); +} + +/* + * Is c a break char for tp? + */ +ttbreakc(c, tp) +register c; +register struct tty *tp; +{ + return (c == '\n' || c == tun.t_eofc || c == tun.t_brkc || + c == '\r' && (tp->t_flags&CRMOD)); +} + +/* + * send string cp to tp + */ +ttyout(cp, tp) +register char *cp; +register struct tty *tp; +{ + register char c; + + while (c = *cp++) + (void) ttyoutput(c, tp); +} + +ttwakeup(tp) + struct tty *tp; +{ + + if (tp->t_rsel) { + selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); + tp->t_state &= ~TS_RCOLL; + tp->t_rsel = 0; + } + wakeup((caddr_t)&tp->t_rawq); +} + +ttsignal(tp, signo) + struct tty *tp; + int signo; +{ + + gsignal(tp->t_pgrp, signo); }