+
+ /*
+ * Signals.
+ */
+ if (lflag&ISIG) {
+ if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {
+ if ((lflag&NOFLSH) == 0)
+ ttyflush(tp, FREAD|FWRITE);
+ ttyecho(c, tp);
+ gsignal(tp->t_pgrp, CCEQ(cc[VINTR],c) ?
+ SIGINT : SIGQUIT);
+ goto endcase;
+ }
+ if (CCEQ(cc[VSUSP],c)) {
+ if ((lflag&NOFLSH) == 0)
+ ttyflush(tp, FREAD);
+ ttyecho(c, tp);
+ pgsignal(tp->t_pgrp, SIGTSTP);
+ goto endcase;
+ }
+ if (CCEQ(cc[VINFO], c)) {
+ pgsignal(tp->t_pgrp, SIGINFO);
+ if ((lflag&NOKERNINFO) == 0)
+ ttyinfo(tp);
+ goto endcase;
+ }
+ }
+ /*
+ * Handle start/stop characters.
+ */
+ if (iflag&IXON) {
+ if (CCEQ(cc[VSTOP],c)) {
+ if ((tp->t_state&TS_TTSTOP) == 0) {
+ tp->t_state |= TS_TTSTOP;
+ (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
+ return;
+ }
+ if (!CCEQ(cc[VSTART], c))
+ return;
+ /*
+ * if VSTART == VSTOP we toggle
+ */
+ goto endcase;
+ }
+ if (CCEQ(cc[VSTART], c))
+ goto restartoutput;
+ }
+ /*
+ * IGNCR, ICRNL, & INLCR
+ */
+ if (c == '\r') {
+ if (iflag&IGNCR)
+ goto endcase;
+ else if (iflag&ICRNL)
+ c = '\n';
+ }
+ else if (c == '\n' && iflag&INLCR)
+ c = '\r';
+ else if (c == '\n' && iflag&INLCR)
+ c = '\r';
+ /*
+ * Non canonical mode, don't process line editing
+ * characters; check high water mark for wakeup.
+ *
+ *
+ */
+ if (!(lflag&ICANON)) {
+ if (tp->t_rawq.c_cc > TTYHOG) {
+ if (iflag&IMAXBEL) {
+ if (tp->t_outq.c_cc < tp->t_hiwat)
+ (void) ttyoutput(CTRL('g'), tp);
+ } else
+ ttyflush(tp, FREAD | FWRITE);
+ } else {
+ if (putc(c, &tp->t_rawq) >= 0) {
+ ttwakeup(tp);
+ ttyecho(c, tp);
+ }
+ }
+ goto endcase;
+ }
+ /*
+ * From here on down canonical mode character
+ * processing takes place.
+ */
+
+ /*
+ * Oldstyle quoting of erase, kill, and eof chars.
+ *
+ * Historically is '\' , but can be changed (read: disabled)
+ * with the VQUOTE subscript.
+ */
+
+ /*
+ * erase (^H / ^?)
+ */
+ if (CCEQ(cc[VERASE], c)) {
+ if (tp->t_rawq.c_cc)
+ ttyrub(unputc(&tp->t_rawq), tp);
+ goto endcase;
+ }
+ if (lflag&ECHOKE && tp->t_rawq.c_cc == tp->t_rocount &&
+ (lflag&ECHOPRT) == 0) {
+ while (tp->t_rawq.c_cc)
+ ttyrub(unputc(&tp->t_rawq), tp);
+ } else {
+ ttyecho(c, tp);
+ if (lflag&ECHOK || lflag&ECHOKE)
+ ttyecho('\n', tp);
+ while (getc(&tp->t_rawq) > 0)
+ ;
+ tp->t_rocount = 0;
+ }
+ tp->t_state &= ~TS_LOCAL;
+ goto endcase;
+ }
+ /*
+ * word erase (^W)
+ */
+ c = unputc(&tp->t_rawq);
+ } while (c != ' ' && c != '\t');
+ (void) putc(c, &tp->t_rawq);
+ goto endcase;
+ }
+ /*
+ * reprint line (^R)
+ */
+ if (CCEQ(cc[VREPRINT], c)) {
+ ttyretype(tp);
+ goto endcase;
+ }
+ /*
+ * reprint line (^R)
+ */
+ if (CCEQ(cc[VREPRINT], c)) {
+ ttyretype(tp);
+ goto endcase;
+ }
+ /*
+ * Check for input buffer overflow
+ */
+ if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
+ if (iflag&IMAXBEL) {
+ if (tp->t_outq.c_cc < TTHIWAT(tp))
+ (void) ttyoutput(CTRL('g'), tp);
+ } else
+ ttyflush(tp, FREAD | FWRITE);
+ goto endcase;
+ }
+ /*
+ * Put data char in q for user and
+ * wakeup on seeing a line delimiter.
+ */
+ if (putc(c, &tp->t_rawq) >= 0) {
+ if (ttbreakc(c)) {
+ tp->t_rocount = 0;
+ catq(&tp->t_rawq, &tp->t_canq);
+ ttwakeup(tp);
+ } else if (tp->t_rocount++ == 0)
+ tp->t_rocol = tp->t_col;
+ if (CCEQ(cc[VQUOTE], c) && (iflag&ISTRIP))
+ tp->t_state |= TS_QUOT; /* '\' escape */
+ if (tp->t_state&TS_ERASE) {
+ /*
+ * end of prterase \.../
+ */
+ /*
+ * end of prterase \.../
+ */
+ tp->t_state &= ~TS_ERASE;
+ (void) ttyoutput('/', tp);
+ }
+ i = tp->t_col;
+ ttyecho(c, tp);
+ if (CCEQ(cc[VEOF], c) && lflag&ECHO) {
+ /*
+ * Place the cursor over the '^' of the ^D.
+ */
+ i = MIN(2, tp->t_col - i);
+ while (i > 0) {
+ (void) ttyoutput('\b', tp);
+ i--;
+ }
+ }
+ }
+endcase:
+ /*
+ * IXANY means allow any character to restart output.
+ */
+ if (tp->t_state&TS_TTSTOP && (iflag&IXANY == 0)
+ && cc[VSTART] != cc[VSTOP])
+ return;
+
+restartoutput:
+ tp->t_state &= ~TS_TTSTOP;
+ tp->t_lflag &= ~FLUSHO;
+startoutput:
+ ttstart(tp);
+}
+
+/*
+ * Put character on TTY output queue, adding delays,
+ * expanding tabs, and handling the CR/NL bit.
+ * This 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 char *colp;
+ register ctype;
+ if (!(tp->t_oflag&OPOST)) {
+ if (tp->t_lflag&FLUSHO)
+ return (-1);
+ if (putc(c, &tp->t_outq))
+ return (c);
+ tk_nout++;
+ tp->t_outcc++;
+ return (-1);
+ }
+ c &= 0377;
+ /*
+ * Turn tabs to spaces as required
+ */
+ if (c == '\t' && tp->t_oflag&OXTABS ) {
+ register int s;
+
+ c = 8 - (tp->t_col&7);
+ if ((tp->t_lflag&FLUSHO) == 0) {
+ s = spltty(); /* don't interrupt tabs */
+ c -= b_to_q(" ", c, &tp->t_outq);
+ tk_nout += c;
+ tp->t_outcc += c;
+ splx(s);
+ }
+ tp->t_col += c;
+ return (c ? -1 : '\t');
+ }
+ if (c == CEOT && oflag&ONOEOT)
+ return(-1);
+ tk_nout++;
+ tp->t_outcc++;
+#ifdef notdef
+ /*
+ * turn <nl> to <cr><lf> if desired.
+ */
+#endif
+ if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq))
+ return (c);
+ if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq))
+ return (c);
+ /*
+ * Calculate delays.
+ * The numbers here represent clock ticks
+ * and are not necessarily optimal for all terminals.
+ *
+ * SHOULD JUST ALLOW USER TO SPECIFY DELAYS
+ *
+ * (actually, should THROW AWAY terminals which need delays)
+ */
+ colp = &tp->t_col;
+ ctype = partab[c];
+ c = 0;
+ switch (ctype&077) {
+
+ case ORDINARY:
+ (*colp)++;
+
+ case CONTROL:
+ break;
+
+ case BACKSPACE:
+ if (*colp)
+ (*colp)--;
+ break;
+
+ /*
+ * This macro is close enough to the correct thing;
+ * it should be replaced by real user settable delays
+ * in any event...
+ */
+#define mstohz(ms) (((ms) * hz) >> 10)
+ case NEWLINE:
+ ctype = (tp->t_flags >> 8) & 03;
+ if (ctype == 1) { /* tty 37 */
+ if (*colp > 0) {
+ c = (((unsigned)*colp) >> 4) + 3;
+ if ((unsigned)c > 6)
+ c = 6;
+ }
+ } else if (ctype == 2) /* vt05 */
+ c = mstohz(100);
+ *colp = 0;
+ break;
+
+ case TAB:
+ ctype = (tp->t_flags >> 10) & 03;
+ if (ctype == 1) { /* tty 37 */
+ c = 1 - (*colp | ~07);
+ if (c < 5)
+ c = 0;
+ }
+ *colp |= 07;
+ (*colp)++;
+ break;
+
+ case VTAB:
+ if (tp->t_flags&VTDELAY) /* tty 37 */
+ c = 0177;
+ break;
+
+ case RETURN:
+ ctype = (tp->t_flags >> 12) & 03;
+ if (ctype == 1) /* tn 300 */
+ c = mstohz(83);
+ else if (ctype == 2) /* ti 700 */
+ c = mstohz(166);
+ else if (ctype == 3) { /* concept 100 */
+ int i;
+
+ if ((i = *colp) >= 0)
+ for (; i < 9; i++)
+ (void) putc(0177, &tp->t_outq);
+ }
+ *colp = 0;
+ }
+ if (c && (tp->t_lflag&FLUSHO) == 0)
+ (void) putc(c|TTY_QUOTE, &tp->t_outq);
+ return (-1);
+}
+#undef mstohz
+
+/*
+ * Called from device's read routine after it has
+ * calculated the tty-structure given as argument.
+ */
+ttread(tp, uio, flag)
+ register struct tty *tp;
+ struct uio *uio;
+{
+ register struct clist *qp;
+ register int c, t_flags;
+ register long lflag = tp->t_lflag;
+ register long iflag = tp->t_iflag;
+ register u_char *cc = tp->t_cc;
+ int s, first, error = 0;
+
+
+loop:
+ s = spltty();
+ /*
+ * take pending input first
+ */
+ if (tp->t_lflag&PENDIN)
+ ttypend(tp);
+ splx(s);
+
+ /*
+ * Hang process if it's in the background.
+ */
+ if (isbackground(u.u_procp, tp)) {
+ if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
+ (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
+ u.u_procp->p_flag&SVFORK || u.u_procp->p_pgrp->pg_jobc == 0)
+ return (EIO);
+ pgsignal(u.u_procp->p_pgrp, SIGTTIN);
+ if (error = tsleep((caddr_t)&lbolt, TTIPRI | PCATCH, ttybg, 0))
+ return (error);
+ goto loop;
+ }
+
+ /*
+ * If canonical, use the canonical queue,
+ * else use the raw queue.
+ */
+ qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq;
+
+ /*
+ * If there is no input, sleep on rawq
+ * awaiting hardware receipt and notification.
+ * If we have data, we don't need to check for carrier.
+ */
+ s = spltty();
+ if (qp->c_cc <= 0) {
+ int carrier;
+
+ carrier = (tp->t_state&TS_CARR_ON) || (tp->t_cflag&CLOCAL);
+ if (!carrier && tp->t_state&TS_ISOPEN) {
+ splx(s);
+ return (0); /* EOF */
+ }
+ if (flag & IO_NDELAY) {
+ splx(s);
+ return (EWOULDBLOCK);
+ }
+ error = tsleep((caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
+ carrier ? ttyin : ttopen, 0);
+ splx(s);
+ if (error)
+ return (error);
+ goto loop;
+ }
+ splx(s);
+
+ /*
+ * Input present, check for input mapping and processing.
+ */
+ first = 1;
+ while ((c = getc(qp)) >= 0) {
+ /*
+ * delayed suspend (^Y)
+ */
+ if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) {
+ pgsignal(tp->t_pgrp, SIGTSTP);
+ if (first) {
+ if (error = tsleep((caddr_t)&lbolt,
+ TTIPRI | PCATCH, ttybg, 0))
+ break;
+ goto loop;
+ }
+ break;
+ }
+ /*
+ * Interpret EOF only in canonical mode.
+ */
+ if (CCEQ(cc[VEOF], c) && lflag&ICANON)
+ break;
+ /*
+ * Give user character.
+ */
+ error = ureadc(iflag&ISTRIP ? c & 0177 : c , uio);
+ if (error)
+ break;
+ if (uio->uio_resid == 0)
+ break;
+ /*
+ * In canonical mode check for a "break character"
+ * marking the end of a "line of input".
+ */
+ if (lflag&ICANON && ttbreakc(c)) {
+ break;
+ }
+ first = 0;
+ }
+ /*
+ * Look to unblock output now that (presumably)
+ * the input queue has gone down.
+ */
+ if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
+ if (cc[VSTART] != POSIX_V_DISABLE
+ && putc(cc[VSTART], &tp->t_outq) == 0) {
+ tp->t_state &= ~TS_TBLOCK;
+ ttstart(tp);
+ }
+ }
+ }
+ return (error);
+}
+
+/*
+ * Check the output queue on tp for space for a kernel message
+ * (from uprintf/tprintf). Allow some space over the normal
+ * hiwater mark so we don't lose messages due to normal flow
+ * control, but don't let the tty run amok.
+ * Sleeps here are not interruptible, but we return prematurely
+ * if new signals come in.
+ */
+ttycheckoutq(tp, wait)
+ register struct tty *tp;
+ int wait;
+{
+ int hiwat, s, oldsig;
+
+ hiwat = tp->t_hiwat;
+ s = spltty();
+ oldsig = u.u_procp->p_sig;
+ if (tp->t_outq.c_cc > hiwat + 200)
+ while (tp->t_outq.c_cc > hiwat) {
+ ttstart(tp);
+ if (wait == 0 || u.u_procp->p_sig != oldsig) {
+ splx(s);
+ return (0);
+ }
+ timeout(wakeup, (caddr_t)&tp->t_outq, hz);
+ tp->t_state |= TS_ASLEEP;
+ sleep((caddr_t)&tp->t_outq, PZERO - 1);
+ }
+ splx(s);
+ return (1);
+}
+
+/*
+ * Called from the device's write routine after it has
+ * calculated the tty-structure given as argument.
+ */
+ttwrite(tp, uio, flag)
+ register struct tty *tp;
+ register struct uio *uio;
+{
+ register char *cp;
+ register int cc = 0, ce;
+ int i, hiwat, cnt, error, s;
+ char obuf[OBUFSIZ];
+
+ hiwat = tp->t_hiwat;
+ cnt = uio->uio_resid;
+ error = 0;
+loop:
+ s = spltty();
+ if ((tp->t_state&TS_CARR_ON) == 0 && (tp->t_cflag&CLOCAL) == 0) {
+ if (tp->t_state&TS_ISOPEN) {
+ splx(s);
+ return (EIO);
+ } else if (flag & IO_NDELAY) {
+ splx(s);
+ error = EWOULDBLOCK;
+ goto out;
+ } else {
+ /*
+ * sleep awaiting carrier
+ */
+ error = tsleep((caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
+ ttopen, 0);
+ splx(s);
+ if (error)
+ goto out;
+ goto loop;
+ }
+ }
+ splx(s);
+ /*
+ * Hang the process if it's in the background.
+ */
+ (tp->t_lflag&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
+ (u.u_procp->p_sigignore & sigmask(SIGTTOU)) == 0 &&
+ (u.u_procp->p_sigmask & sigmask(SIGTTOU)) == 0 &&
+ u.u_procp->p_pgrp->pg_jobc) {
+ pgsignal(u.u_procp->p_pgrp, SIGTTOU);
+ if (error = tsleep((caddr_t)&lbolt, TTIPRI | PCATCH, ttybg, 0))
+ goto out;
+ goto loop;
+ }
+ /*
+ * Process the user's data in at most OBUFSIZ
+ * chunks. Perform any output translation.
+ * Keep track of high water mark, sleep on overflow
+ * awaiting device aid in acquiring new space.
+ */
+ while (uio->uio_resid > 0 || cc > 0) {
+ if (tp->t_lflag&FLUSHO) {
+ uio->uio_resid = 0;
+ return (0);
+ }
+ if (tp->t_outq.c_cc > hiwat)
+ goto ovhiwat;
+ /*
+ * Grab a hunk of data from the user,
+ * unless we have some leftover from last time.
+ */
+ if (cc == 0) {
+ cc = min(uio->uio_resid, OBUFSIZ);
+ cp = obuf;
+ error = uiomove(cp, cc, uio);
+ if (error) {
+ cc = 0;
+ break;
+ }
+ }
+#ifdef notdef
+ /*
+ * If nothing fancy need be done, grab those characters we
+ * can handle without any of ttyoutput's processing and
+ * just transfer them to the output q. For those chars
+ * which require special processing (as indicated by the
+ * bits in partab), call ttyoutput. After processing
+ * a hunk of data, look for FLUSHO so ^O's will take effect
+ * immediately.
+ */
+ while (cc > 0) {
+ if (!(tp->t_oflag&OPOST))
+ ce = cc;
+ else {
+ ce = cc - scanc((unsigned)cc, (u_char *)cp,
+ (u_char *)partab, 077);
+ /*
+ * If ce is zero, then we're processing
+ * a special character through ttyoutput.
+ */
+ if (ce == 0) {
+ tp->t_rocount = 0;
+ if (ttyoutput(*cp, tp) >= 0) {
+ /* no c-lists, wait a bit */
+ ttstart(tp);
+ if (error = tsleep((caddr_t)&lbolt,
+ TTOPRI | PCATCH, ttybuf, 0))
+ break;
+ goto loop;
+ }
+ cp++, cc--;
+ if (tp->t_lflag&FLUSHO ||
+ tp->t_outq.c_cc > hiwat)
+ goto ovhiwat;
+ continue;
+ }
+ }
+ /*
+ * A bunch of normal characters have been found,
+ * transfer them en masse to the output queue and
+ * continue processing at the top of the loop.
+ * If there are any further characters in this
+ * <= OBUFSIZ chunk, the first should be a character
+ * requiring special handling by ttyoutput.
+ */
+ tp->t_rocount = 0;
+ i = b_to_q(cp, ce, &tp->t_outq);
+ ce -= i;
+ tp->t_col += ce;
+ cp += ce, cc -= ce, tk_nout += ce;
+ tp->t_outcc += ce;
+ if (i > 0) {
+ /* out of c-lists, wait a bit */
+ ttstart(tp);
+ if (error = tsleep((caddr_t)&lbolt,
+ TTOPRI | PCATCH, ttybuf, 0))
+ break;
+ goto loop;
+ }
+ if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat)
+ break;
+ }
+ ttstart(tp);
+ ttstart(tp);
+ }
+out:
+ /*
+ * If cc is nonzero, we leave the uio structure inconsistent,
+ * as the offset and iov pointers have moved forward,
+ * but it doesn't matter (the call will either return short
+ * or restart with a new uio).
+ */
+ uio->uio_resid += cc;
+ return (error);
+
+ovhiwat:
+ ttstart(tp);
+ s = spltty();
+ /*
+ * This can only occur if FLUSHO is set in t_lflag,
+ * or if ttstart/oproc is synchronous (or very fast).
+ */
+ if (tp->t_outq.c_cc <= hiwat) {
+ splx(s);
+ goto loop;
+ }
+ if (flag & IO_NDELAY) {
+ splx(s);
+ uio->uio_resid += cc;
+ if (uio->uio_resid == cnt)
+ return (EWOULDBLOCK);
+ return (0);
+ }
+ tp->t_state |= TS_ASLEEP;
+ error = tsleep((caddr_t)&tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
+ splx(s);
+ if (error)
+ goto out;
+ 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_lflag&ECHO) == 0)
+ return;
+ if (tp->t_lflag&ECHOE) {
+ if (tp->t_rocount == 0) {
+ /*
+ * Screwed by ttwrite; retype
+ */
+ ttyretype(tp);
+ return;
+ }
+ /* if tab or newline was escaped - XXX - not 8bit */
+ if (c == ('\t'|TTY_QUOTE) || c == ('\n'|TTY_QUOTE))
+ ttyrubo(tp, 2);
+ else switch (partab[c&=0377]&077) {
+
+ case ORDINARY:
+#ifdef notdef
+ ttyrubo(tp, 1);
+ break;
+
+ case VTAB:
+ case BACKSPACE:
+ case CONTROL:
+ case RETURN:
+ if (tp->t_lflag&ECHOCTL)
+ ttyrubo(tp, 2);
+ break;
+
+ case TAB: {
+ int c;
+
+ if (tp->t_rocount < tp->t_rawq.c_cc) {
+ ttyretype(tp);
+ return;
+ }
+ s = spltty();
+ savecol = tp->t_col;
+ tp->t_state |= TS_CNTTB;
+ tp->t_lflag |= FLUSHO;
+ tp->t_col = tp->t_rocol;
+ cp = tp->t_rawq.c_cf;
+ tp->t_lflag &= ~FLUSHO;
+ tp->t_state &= ~TS_CNTTB;
+ 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:
+ /* XXX */
+ printf("ttyrub: would panic c = %d, val = %d\n",
+ c, partab[c&=0377]&077);
+ /*panic("ttyrub");*/
+ }
+ } else if (tp->t_lflag&ECHOPRT) {
+ if ((tp->t_state&TS_ERASE) == 0) {
+ (void) ttyoutput('\\', tp);
+ tp->t_state |= TS_ERASE;
+ }
+ ttyecho(c, tp);
+ } else
+ ttyecho(tp->t_cc[VERASE], tp);
+ tp->t_rocount--;
+}
+
+/*
+ * Crt back over cnt chars perhaps
+ * erasing them.
+ */
+ttyrubo(tp, cnt)
+ register struct tty *tp;
+ int cnt;
+{
+ register char *rubostring = tp->t_lflag&ECHOE ? "\b \b" : "\b";
+
+ while (--cnt >= 0)
+ ttyoutstr("\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, c;
+
+ if (tp->t_cc[VREPRINT] != POSIX_V_DISABLE)
+ ttyecho(tp->t_cc[VREPRINT], tp);
+ (void) ttyoutput('\n', tp);
+ s = spltty();
+ /*** XXX *** FIX *** NEXTC IS BROKEN - DOESN'T CHECK QUOTE
+ BIT OF FIRST CHAR ****/
+ for (cp = tp->t_canq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_canq, cp, &c)) {
+ ttyecho(c, tp);
+ }
+ for (cp = tp->t_rawq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_rawq, cp, &c)) {
+ ttyecho(c, tp);
+ }
+ tp->t_state &= ~TS_ERASE;
+ 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;
+{
+ c &= 0377;
+ if ((tp->t_state&TS_CNTTB) == 0)
+ tp->t_lflag &= ~FLUSHO;
+ if ((tp->t_lflag&ECHO) == 0 && !(tp->t_lflag&ECHONL && c == '\n'))
+ return;
+ if (tp->t_lflag&ECHOCTL) {
+ if ((c&TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' ||
+ c == 0177) {
+ (void) ttyoutput('^', tp);
+ c &= TTY_CHARMASK;
+ if (c == 0177)
+ c = '?';
+#ifdef notdef
+#endif
+ else
+ c += 'A' - 1;
+ }
+ }
+ (void) ttyoutput(c, tp);
+ * send string cp to tp
+ */
+ttyoutstr(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;
+ }
+ if (tp->t_state & TS_ASYNC)
+ pgsignal(tp->t_pgrp, SIGIO);
+ wakeup((caddr_t)&tp->t_rawq);
+}
+
+/*
+ * set tty hi and low water marks
+ *
+ * Try to arrange the dynamics so there's about one second
+ * from hi to low water.
+ *
+ */
+ttsetwater(tp)
+ struct tty *tp;
+{
+ register cps = tp->t_ospeed / 10;
+ register x;
+
+#define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x))
+ tp->t_lowat = x = clamp(cps/2, TTMAXLOWAT, TTMINLOWAT);
+ x += cps;
+ x = clamp(x, TTMAXHIWAT, TTMINHIWAT);
+ tp->t_hiwat = roundup(x, CBSIZE);
+#undef clamp
+}
+
+ttspeedtab(speed, table)
+ struct speedtab table[];
+{
+ register int i;
+
+ for (i = 0; table[i].sp_speed != -1; i++)
+ if (table[i].sp_speed == speed)
+ return(table[i].sp_code);
+ return(-1);
+}
+
+/*
+ * (^T)
+ * Report on state of foreground process group.
+ */
+ttyinfo(tp)
+ struct tty *tp;
+{
+ register struct proc *p;
+
+ if (ttycheckoutq(tp,0) == 0)
+ return;
+ if (tp->t_session == NULL)
+ ttyprintf(tp, "kernel: not a controlling terminal\n");
+ else if (tp->t_pgrp == NULL ||
+ (p = tp->t_pgrp->pg_mem) == NULL)
+ ttyprintf(tp, "kernel: no foreground process group\n");
+ else {
+ int i = 0;
+
+ for (; p != NULL; p = p->p_pgrpnxt) {
+ ttyprintf(tp,
+ "kernel: pid: %d state: %x wchan: %x ticks: %d\n",
+ p->p_pid, p->p_stat, p->p_wchan, p->p_cpticks);
+ if (++i > 6) {
+ ttyprintf(tp, "kernel: more...\n");
+ break;
+ }
+ }
+ }
+}
+
+#define TOTTY 0x2 /* XXX should be in header */
+/*VARARGS2*/
+ttyprintf(tp, fmt, x1)
+ struct tty *tp;
+ char *fmt;
+ unsigned x1;
+{
+ prf(fmt, &x1, TOTTY, (caddr_t)tp);
+}
+
+/*
+ * Output char to tty; console putchar style.
+ */
+tputchar(c, tp)
+ int c;
+ struct tty *tp;
+{
+ register s = spltty();
+
+ if ((tp->t_state & (TS_CARR_ON | TS_ISOPEN))
+ == (TS_CARR_ON | TS_ISOPEN)) {
+ if (c == '\n')
+ (void) ttyoutput('\r', tp);
+ (void) ttyoutput(c, tp);
+ ttstart(tp);
+ splx(s);
+ return (0);
+ }
+ splx(s);
+ return (-1);