- /*
- * If input is pending take it first.
- */
- if (lflag&PENDIN)
- ttypend(tp);
- /*
- * Gather stats.
- */
-
- tk_nin++;
- if (lflag&ICANON) {
- tk_cancc++;
- tp->t_cancc++;
- } else {
- tk_rawcc++;
- tp->t_rawcc++;
- }
- /*
- * Handle exceptional conditions (break, parity, framing).
- */
- if (err = (c&TTY_ERRORMASK)) {
- c &= TTY_CHARMASK;
- if (err&TTY_FE && !c) { /* break */
- if (iflag&IGNBRK)
- goto endcase;
- else if (iflag&BRKINT && lflag&ISIG &&
- (cc[VINTR] != POSIX_V_DISABLE))
- c = cc[VINTR];
- else
- c = 0;
- } else if ((err&TTY_PE && iflag&INPCK) || err&TTY_FE) {
- if (iflag&IGNPAR)
- goto endcase;
- else if (iflag&PARMRK) {
- ttyinput(0377, tp);
- ttyinput(0, tp);
- } else
- c = 0;
- }
- }
- dprintf("<%o>\n", c);
-
- /*
- * In tandem mode, check high water mark.
- */
- if (iflag&IXOFF)
- ttyblock(tp);
-
- /*
- * In tandem mode, check high water mark.
- */
- if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP))
- c &= 0177;
- if ((tp->t_lflag&EXTPROC) == 0) {
- /*
- * Check for literal nexting very first
- */
- if (tp->t_state&TS_LNCH) {
- c |= TTY_QUOTE;
- tp->t_state &= ~TS_LNCH;
- }
- /*
- * Scan for special characters. This code
- * is really just a big case statement with
- * non-constant cases. The bottom of the
- * case statement is labeled ``endcase'', so goto
- * it after a case match, or similar.
- */
-
- /*
- * Extensions to POSIX input modes which aren't controlled
- * by ICANON, ISIG, or IXON.
- */
- if (iflag&IEXTEN) {
- if (CCEQ(cc[VLNEXT],c) && (iflag&ISTRIP)) {
- if (lflag&ECHO)
- ttyout("^\b", tp); /*XXX - presumes too much */
- tp->t_state |= TS_LNCH;
- goto endcase;
- }
- if (CCEQ(cc[VFLUSHO],c)) {
- if (lflag&FLUSHO)
- tp->t_lflag &= ~FLUSHO;
- else {
- ttyflush(tp, FWRITE);
- ttyecho(c, tp);
- if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
- ttyretype(tp);
- tp->t_lflag |= FLUSHO;
- }
- goto startoutput;
- }
- }
-
- /*
- * 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, 1);
- 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;
- }
- if ((tp->t_lflag&EXTPROC) == 0) {
- /*
- * 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;
- }
- /*
- * ^T - kernel info and generate SIGINFO
- */
- if (CCEQ(cc[VSTATUS], c)) {
- pgsignal(tp->t_pgrp, SIGINFO, 1);
- if ((lflag&NOKERNINFO) == 0)
- ttyinfo(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);