📄 tty.c
字号:
/* Previous character was a character escape? */ if (tp->tty_escaped) { tp->tty_escaped = NOT_ESCAPED; ch |= IN_ESC; /* protect character */ } /* LNEXT (^V) to escape the next character? */ if (ch == tp->tty_termios.c_cc[VLNEXT]) { tp->tty_escaped = ESCAPED; rawecho(tp, '^'); rawecho(tp, '\b'); continue; /* do not store the escape */ } /* REPRINT (^R) to reprint echoed characters? */ if (ch == tp->tty_termios.c_cc[VREPRINT]) { reprint(tp); continue; } } /* _POSIX_VDISABLE is a normal character value, so better escape it. */ if (ch == _POSIX_VDISABLE) ch |= IN_ESC; /* Map CR to LF, ignore CR, or map LF to CR. */ if (ch == '\r') { if (tp->tty_termios.c_iflag & IGNCR) continue; if (tp->tty_termios.c_iflag & ICRNL) ch = '\n'; } else if (ch == '\n') { if (tp->tty_termios.c_iflag & INLCR) ch = '\r'; } /* Canonical mode? */ if (tp->tty_termios.c_lflag & ICANON) { /* Erase processing (rub out of last character). */ if (ch == tp->tty_termios.c_cc[VERASE]) { (void) back_over(tp); if (!(tp->tty_termios.c_lflag & ECHOE)) { (void) tty_echo(tp, ch); } continue; } /* Kill processing (remove current line). */ if (ch == tp->tty_termios.c_cc[VKILL]) { while (back_over(tp)) {} if (!(tp->tty_termios.c_lflag & ECHOE)) { (void) tty_echo(tp, ch); if (tp->tty_termios.c_lflag & ECHOK) rawecho(tp, '\n'); } continue; } /* EOF (^D) means end-of-file, an invisible "line break". */ if (ch == tp->tty_termios.c_cc[VEOF]) ch |= IN_EOT | IN_EOF; /* The line may be returned to the user after an LF. */ if (ch == '\n') ch |= IN_EOT; /* Same thing with EOL, whatever it may be. */ if (ch == tp->tty_termios.c_cc[VEOL]) ch |= IN_EOT; } /* Start/stop input control? */ if (tp->tty_termios.c_iflag & IXON) { /* Output stops on STOP (^S). */ if (ch == tp->tty_termios.c_cc[VSTOP]) { tp->tty_inhibited = STOPPED; tp->tty_events = 1; continue; } /* Output restarts on START (^Q) or any character if IXANY. */ if (tp->tty_inhibited) { if (ch == tp->tty_termios.c_cc[VSTART] || (tp->tty_termios.c_iflag & IXANY)) { tp->tty_inhibited = RUNNING; tp->tty_events = 1; if (ch == tp->tty_termios.c_cc[VSTART]) continue; } } } if (tp->tty_termios.c_lflag & ISIG) { /* Check for INTR (^?) and QUIT (^\) characters. */ if (ch == tp->tty_termios.c_cc[VINTR] || ch == tp->tty_termios.c_cc[VQUIT]) { sig = SIGINT; if (ch == tp->tty_termios.c_cc[VQUIT]) sig = SIGQUIT; sigchar(tp, sig); (void) tty_echo(tp, ch); continue; } } /* Is there space in the input buffer? */ if (tp->tty_incount == buflen(tp->tty_inbuf)) { /* No space; discard in canonical mode, keep in raw mode. */ if (tp->tty_termios.c_lflag & ICANON) continue; break; } if (!(tp->tty_termios.c_lflag & ICANON)) { /* In raw mode all characters are "line breaks". */ ch |= IN_EOT; /* Start an inter-byte timer? */ if (!timeset && tp->tty_termios.c_cc[VMIN] > 0 && tp->tty_termios.c_cc[VTIME] > 0) { settimer(tp, TRUE); timeset = TRUE; } } /* Perform the intricate function of echoing. */ if (tp->tty_termios.c_lflag & (ECHO|ECHONL)) ch = tty_echo(tp, ch); /* Save the character in the input queue. */ *tp->tty_inhead++ = ch; if (tp->tty_inhead == bufend(tp->tty_inbuf)) tp->tty_inhead = tp->tty_inbuf; tp->tty_incount++; if (ch & IN_EOT) tp->tty_eotct++; /* Try to finish input if the queue threatens to overflow. */ if (tp->tty_incount == buflen(tp->tty_inbuf)) in_transfer(tp); } return ct;}/*===========================================================================* * echo * *===========================================================================*/PRIVATE int tty_echo(tp, ch)register tty_t *tp; /* terminal on which to echo */register int ch; /* pointer to character to echo */{/* Echo the character if echoing is on. Some control characters are echoed * with their normal effect, other control characters are echoed as "^X", * normal characters are echoed normally. EOF (^D) is echoed, but immediately * backspaced over. Return the character with the echoed length added to its * attributes. */ int len, rp; ch &= ~IN_LEN; if (!(tp->tty_termios.c_lflag & ECHO)) { if (ch == ('\n' | IN_EOT) && (tp->tty_termios.c_lflag & (ICANON|ECHONL)) == (ICANON|ECHONL)) (*tp->tty_echo)(tp, '\n'); return(ch); } /* "Reprint" tells if the echo output has been messed up by other output. */ rp = tp->tty_incount == 0 ? FALSE : tp->tty_reprint; if ((ch & IN_CHAR) < ' ') { switch (ch & (IN_ESC|IN_EOF|IN_EOT|IN_CHAR)) { case '\t': len = 0; do { (*tp->tty_echo)(tp, ' '); len++; } while (len < TAB_SIZE && (tp->tty_position & TAB_MASK) != 0); break; case '\r' | IN_EOT: case '\n' | IN_EOT: (*tp->tty_echo)(tp, ch & IN_CHAR); len = 0; break; default: (*tp->tty_echo)(tp, '^'); (*tp->tty_echo)(tp, '@' + (ch & IN_CHAR)); len = 2; } } else if ((ch & IN_CHAR) == '\177') { /* A DEL prints as "^?". */ (*tp->tty_echo)(tp, '^'); (*tp->tty_echo)(tp, '?'); len = 2; } else { (*tp->tty_echo)(tp, ch & IN_CHAR); len = 1; } if (ch & IN_EOF) while (len > 0) { (*tp->tty_echo)(tp, '\b'); len--; } tp->tty_reprint = rp; return(ch | (len << IN_LSHIFT));}/*===========================================================================* * rawecho * *===========================================================================*/PRIVATE void rawecho(tp, ch)register tty_t *tp;int ch;{/* Echo without interpretation if ECHO is set. */ int rp = tp->tty_reprint; if (tp->tty_termios.c_lflag & ECHO) (*tp->tty_echo)(tp, ch); tp->tty_reprint = rp;}/*===========================================================================* * back_over * *===========================================================================*/PRIVATE int back_over(tp)register tty_t *tp;{/* Backspace to previous character on screen and erase it. */ u16_t *head; int len; if (tp->tty_incount == 0) return(0); /* queue empty */ head = tp->tty_inhead; if (head == tp->tty_inbuf) head = bufend(tp->tty_inbuf); if (*--head & IN_EOT) return(0); /* can't erase "line breaks" */ if (tp->tty_reprint) reprint(tp); /* reprint if messed up */ tp->tty_inhead = head; tp->tty_incount--; if (tp->tty_termios.c_lflag & ECHOE) { len = (*head & IN_LEN) >> IN_LSHIFT; while (len > 0) { rawecho(tp, '\b'); rawecho(tp, ' '); rawecho(tp, '\b'); len--; } } return(1); /* one character erased */}/*===========================================================================* * reprint * *===========================================================================*/PRIVATE void reprint(tp)register tty_t *tp; /* pointer to tty struct */{/* Restore what has been echoed to screen before if the user input has been * messed up by output, or if REPRINT (^R) is typed. */ int count; u16_t *head; tp->tty_reprint = FALSE; /* Find the last line break in the input. */ head = tp->tty_inhead; count = tp->tty_incount; while (count > 0) { if (head == tp->tty_inbuf) head = bufend(tp->tty_inbuf); if (head[-1] & IN_EOT) break; head--; count--; } if (count == tp->tty_incount) return; /* no reason to reprint */ /* Show REPRINT (^R) and move to a new line. */ (void) tty_echo(tp, tp->tty_termios.c_cc[VREPRINT] | IN_ESC); rawecho(tp, '\r'); rawecho(tp, '\n'); /* Reprint from the last break onwards. */ do { if (head == bufend(tp->tty_inbuf)) head = tp->tty_inbuf; *head = tty_echo(tp, *head); head++; count++; } while (count < tp->tty_incount);}/*===========================================================================* * out_process * *===========================================================================*/PUBLIC void out_process(tp, bstart, bpos, bend, icount, ocount)tty_t *tp;char *bstart, *bpos, *bend; /* start/pos/end of circular buffer */int *icount; /* # input chars / input chars used */int *ocount; /* max output chars / output chars used */{/* Perform output processing on a circular buffer. *icount is the number of * bytes to process, and the number of bytes actually processed on return. * *ocount is the space available on input and the space used on output. * (Naturally *icount < *ocount.) The column position is updated modulo * the TAB size, because we really only need it for tabs. */ int tablen; int ict = *icount; int oct = *ocount; int pos = tp->tty_position; while (ict > 0) { switch (*bpos) { case '\7': break; case '\b': pos--; break; case '\r': pos = 0; break; case '\n': if ((tp->tty_termios.c_oflag & (OPOST|ONLCR)) == (OPOST|ONLCR)) { /* Map LF to CR+LF if there is space. Note that the * next character in the buffer is overwritten, so * we stop at this point. */ if (oct >= 2) { *bpos = '\r'; if (++bpos == bend) bpos = bstart; *bpos = '\n'; pos = 0; ict--; oct -= 2; } goto out_done; /* no space or buffer got changed */ } break; case '\t': /* Best guess for the tab length. */ tablen = TAB_SIZE - (pos & TAB_MASK); if ((tp->tty_termios.c_oflag & (OPOST|XTABS)) == (OPOST|XTABS)) { /* Tabs must be expanded. */ if (oct >= tablen) { pos += tablen; ict--; oct -= tablen; do { *bpos = ' '; if (++bpos == bend) bpos = bstart; } while (--tablen != 0); } goto out_done; } /* Tabs are output directly. */ pos += tablen; break; default: /* Assume any other character prints as one character. */ pos++; } if (++bpos == bend) bpos = bstart; ict--; oct--; }out_done: tp->tty_position = pos & TAB_MASK; *icount -= ict; /* [io]ct are the number of chars not used */ *ocount -= oct; /* *[io]count are the number of chars that are used */}/*===========================================================================* * dev_ioctl * *===========================================================================*/PRIVATE void dev_ioctl(tp)tty_t *tp;{/* The ioctl's TCSETSW, TCSETSF and TCDRAIN wait for output to finish to make * sure that an attribute change doesn't affect the processing of current * output. Once output finishes the ioctl is executed as in do_ioctl(). */ int result; if (tp->tty_outleft > 0) return; /* output not finished */ if (tp->tty_ioreq != TCDRAIN) { if (tp->tty_ioreq == TCSETSF) tty_icancel(tp); result = sys_vircopy(tp->tty_ioproc, D, tp->tty_iovir, SELF, D, (vir_bytes) &tp->tty_termios, (vir_bytes) sizeof(tp->tty_termios)); setattr(tp); } tp->tty_ioreq = 0; tty_reply(REVIVE, tp->tty_iocaller, tp->tty_ioproc, result);}/*===========================================================================* * setattr * *===========================================================================*/PRIVATE void setattr(tp)tty_t *tp;{/* Apply the new line attributes (raw/canonical, line speed, etc.) */ u16_t *inp; int count; if (!(tp->tty_termios.c_lflag & ICANON)) { /* Raw mode; put a "line break" on all characters in the input queue. * It is undefined what happens to the input queue when ICANON is * switched off, a process should use TCSAFLUSH to flush the queue. * Keeping the queue to preserve typeahead is the Right Thing, however * when a process does use TCSANOW to switch to raw mode. */ count = tp->tty_eotct = tp->tty_incount; inp = tp->tty_intail; while (count > 0) { *inp |= IN_EOT; if (++inp == bufend(tp->tty_inbuf)) inp = tp->tty_inbuf; --count; } } /* Inspect MIN and TIME. */ settimer(tp, FALSE); if (tp->tty_termios.c_lflag & ICANON) { /* No MIN & TIME in canonical mode. */ tp->tty_min = 1; } else { /* In raw mode MIN is the number of chars wanted, and TIME how long * to wait for them. With interesting exceptions if either is zero. */ tp->tty_min = tp->tty_termios.c_cc[VMIN]; if (tp->tty_min == 0 && tp->tty_termios.c_cc[VTIME] > 0) tp->tty_min = 1; } if (!(tp->tty_termios.c_iflag & IXON)) { /* No start/stop output control, so don't leave output inhibited. */ tp->tty_inhibited = RUNNING; tp->tty_events = 1; } /* Setting the output speed to zero hangs up the phone. */ if (tp->tty_termios.c_ospeed == B0) sigchar(tp, SIGHUP); /* Set new line speed, character size, etc at the device level. */ (*tp->tty_ioctl)(tp, 0);}/*===========================================================================* * tty_reply * *===========================================================================*/PUBLIC void tty_reply(code, replyee, proc_nr, status)int code; /* TASK_REPLY or REVIVE */int replyee; /* destination address for the reply */int proc_nr; /* to whom should the reply go? */int status; /* reply code */{/* Send a reply to a process that wanted to read or write data. */ message tty_mess; tty_mess.m_type = code; tty_mess.REP_PROC_NR = proc_nr; tty_mess.REP_STATUS = status; if ((status = send(replyee, &tty_mess)) != OK) { panic("TTY","tty_reply failed, status\n", status); }}/*===========================================================================* * sigchar * *===========================================================================*/PUBLIC void sigchar(tp, sig)register tty_t *tp;int sig; /* SIGINT, SIGQUIT, SIGKILL or SIGHUP */{/* Process a SIGINT, SIGQUIT or SIGKILL char from the keyboard or SIGHUP from * a tty close, "stty 0", or a real RS-232 hangup. MM will send the signal to * the process group (INT, QUIT), all processes (KILL), or the session leader * (HUP). */ int status; if (tp->tty_pgrp != 0) if (OK != (status = sys_kill(tp->tty_pgrp, sig))) panic("TTY","Error, call to sys_kill failed", status); if (!(tp->tty_termios.c_lflag & NOFLSH)) { tp->tty_incount = tp->tty_eotct = 0; /* kill earlier input */ tp->tty_intail = tp->tty_inhead; (*tp->tty_ocancel)(tp, 0); /* kill all output */ tp->tty_inhibited = RUNNING; tp->tty_events = 1; }}/*===========================================================================* * tty_icancel * *===========================================================================*/PRIVATE void tty_icancel(tp)register tty_t *tp;{/* Discard all pending input, tty buffer or device. */ tp->tty_incount = tp->tty_eotct = 0; tp->tty_intail = tp->tty_inhead; (*tp->tty_icancel)(tp, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -