⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tty.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
/*- * Copyright (c) 1982, 1986, 1990, 1991, 1993 *	The Regents of the University of California.  All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *	@(#)tty.c	8.8 (Berkeley) 1/21/94 */#include <sys/param.h>#include <sys/systm.h>#include <sys/ioctl.h>#include <sys/proc.h>#define	TTYDEFCHARS#include <sys/tty.h>#undef	TTYDEFCHARS#include <sys/file.h>#include <sys/conf.h>#include <sys/dkstat.h>#include <sys/uio.h>#include <sys/kernel.h>#include <sys/vnode.h>#include <sys/syslog.h>#include <vm/vm.h>static int	proc_compare __P((struct proc *p1, struct proc *p2));static int	ttnread __P((struct tty *));static void	ttyblock __P((struct tty *tp));static void	ttyecho __P((int, struct tty *tp));static void	ttyrubo __P((struct tty *, int));/* Symbolic sleep message strings. */char ttclos[]	= "ttycls";char ttopen[]	= "ttyopn";char ttybg[]	= "ttybg";char ttybuf[]	= "ttybuf";char ttyin[]	= "ttyin";char ttyout[]	= "ttyout";/* * Table with character classes and parity. The 8th bit indicates parity, * the 7th bit indicates the character is an alphameric or underscore (for * ALTWERASE), and the low 6 bits indicate delay type.  If the low 6 bits * are 0 then the character needs no special processing on output; classes * other than 0 might be translated or (not currently) require delays. */#define	E	0x00	/* Even parity. */#define	O	0x80	/* Odd parity. */#define	PARITY(c)	(char_type[c] & O)#define	ALPHA	0x40	/* Alpha or underscore. */#define	ISALPHA(c)	(char_type[(c) & TTY_CHARMASK] & ALPHA)#define	CCLASSMASK	0x3f#define	CCLASS(c)	(char_type[c] & CCLASSMASK)#define	BS	BACKSPACE#define	CC	CONTROL#define	CR	RETURN#define	NA	ORDINARY | ALPHA#define	NL	NEWLINE#define	NO	ORDINARY#define	TB	TAB#define	VT	VTABchar const char_type[] = {	E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC,	/* nul - bel */	O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */	O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */	E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */	O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */	E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */	O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */	O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */	O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */	E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */	O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */	O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */	E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */	/*	 * Meta chars; should be settable per character set;	 * for now, treat them all as normal characters.	 */	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,};#undef	BS#undef	CC#undef	CR#undef	NA#undef	NL#undef	NO#undef	TB#undef	VT/* Macros to clear/set/test flags. */#define	SET(t, f)	(t) |= (f)#define	CLR(t, f)	(t) &= ~(f)#define	ISSET(t, f)	((t) & (f))/* * Initial open of tty, or (re)entry to standard tty line discipline. */intttyopen(device, tp)	dev_t device;	register struct tty *tp;{	int s;	s = spltty();	tp->t_dev = device;	if (!ISSET(tp->t_state, TS_ISOPEN)) {		SET(tp->t_state, TS_ISOPEN);		bzero(&tp->t_winsize, sizeof(tp->t_winsize));	}	CLR(tp->t_state, TS_WOPEN);	splx(s);	return (0);}/* * Handle close() on a tty line: flush and set to initial state, * bumping generation number so that pending read/write calls * can detect recycling of the tty. */intttyclose(tp)	register struct tty *tp;{	extern struct tty *constty;	/* Temporary virtual console. */	if (constty == tp)		constty = NULL;	ttyflush(tp, FREAD | FWRITE);	tp->t_gen++;	tp->t_pgrp = NULL;	tp->t_session = NULL;	tp->t_state = 0;	return (0);}#define	FLUSHQ(q) {							\	if ((q)->c_cc)							\		ndflush(q, (q)->c_cc);					\}/* Is 'c' a line delimiter ("break" character)? */#define	TTBREAKC(c)							\	((c) == '\n' || ((c) == cc[VEOF] ||				\	(c) == cc[VEOL] || (c) == cc[VEOL2]) && (c) != _POSIX_VDISABLE)/* * Process input of a single character received on a tty. */intttyinput(c, tp)	register int c;	register struct tty *tp;{	register int iflag, lflag;	register u_char *cc;	int i, err;	/*	 * If input is pending take it first.	 */	lflag = tp->t_lflag;	if (ISSET(lflag, PENDIN))		ttypend(tp);	/*	 * Gather stats.	 */	if (ISSET(lflag, ICANON)) {		++tk_cancc;		++tp->t_cancc;	} else {		++tk_rawcc;		++tp->t_rawcc;	}	++tk_nin;	/* Handle exceptional conditions (break, parity, framing). */	cc = tp->t_cc;	iflag = tp->t_iflag;	if (err = (ISSET(c, TTY_ERRORMASK))) {		CLR(c, TTY_ERRORMASK);		if (ISSET(err, TTY_FE) && !c) {	/* Break. */			if (ISSET(iflag, IGNBRK))				goto endcase;			else if (ISSET(iflag, BRKINT) &&			    ISSET(lflag, ISIG) &&			    (cc[VINTR] != _POSIX_VDISABLE))				c = cc[VINTR];			else if (ISSET(iflag, PARMRK))				goto parmrk;		} else if (ISSET(err, TTY_PE) &&		    ISSET(iflag, INPCK) || ISSET(err, TTY_FE)) {			if (ISSET(iflag, IGNPAR))				goto endcase;			else if (ISSET(iflag, PARMRK)) {parmrk:				(void)putc(0377 | TTY_QUOTE, &tp->t_rawq);				(void)putc(0 | TTY_QUOTE, &tp->t_rawq);				(void)putc(c | TTY_QUOTE, &tp->t_rawq);				goto endcase;			} else				c = 0;		}	}	/*	 * In tandem mode, check high water mark.	 */	if (ISSET(iflag, IXOFF))		ttyblock(tp);	if (!ISSET(tp->t_state, TS_TYPEN) && ISSET(iflag, ISTRIP))		CLR(c, 0x80);	if (!ISSET(lflag, EXTPROC)) {		/*		 * Check for literal nexting very first		 */		if (ISSET(tp->t_state, TS_LNCH)) {			SET(c, TTY_QUOTE);			CLR(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.		 */		/*		 * Control chars which aren't controlled		 * by ICANON, ISIG, or IXON.		 */		if (ISSET(lflag, IEXTEN)) {			if (CCEQ(cc[VLNEXT], c)) {				if (ISSET(lflag, ECHO)) {					if (ISSET(lflag, ECHOE)) {						(void)ttyoutput('^', tp);						(void)ttyoutput('\b', tp);					} else						ttyecho(c, tp);				}				SET(tp->t_state, TS_LNCH);				goto endcase;			}			if (CCEQ(cc[VDISCARD], c)) {				if (ISSET(lflag, FLUSHO))					CLR(tp->t_lflag, FLUSHO);				else {					ttyflush(tp, FWRITE);					ttyecho(c, tp);					if (tp->t_rawq.c_cc + tp->t_canq.c_cc)						ttyretype(tp);					SET(tp->t_lflag, FLUSHO);				}				goto startoutput;			}		}		/*		 * Signals.		 */		if (ISSET(lflag, ISIG)) {			if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {				if (!ISSET(lflag, NOFLSH))					ttyflush(tp, FREAD | FWRITE);				ttyecho(c, tp);				pgsignal(tp->t_pgrp,				    CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1);				goto endcase;			}			if (CCEQ(cc[VSUSP], c)) {				if (!ISSET(lflag, NOFLSH))					ttyflush(tp, FREAD);				ttyecho(c, tp);				pgsignal(tp->t_pgrp, SIGTSTP, 1);				goto endcase;			}		}		/*		 * Handle start/stop characters.		 */		if (ISSET(iflag, IXON)) {			if (CCEQ(cc[VSTOP], c)) {				if (!ISSET(tp->t_state, TS_TTSTOP)) {					SET(tp->t_state, TS_TTSTOP);#ifdef sun4c						/* XXX */					(*tp->t_stop)(tp, 0);#else					(*cdevsw[major(tp->t_dev)].d_stop)(tp,					   0);#endif					return (0);				}				if (!CCEQ(cc[VSTART], c))					return (0);				/*				 * if VSTART == VSTOP then toggle				 */				goto endcase;			}			if (CCEQ(cc[VSTART], c))				goto restartoutput;		}		/*		 * IGNCR, ICRNL, & INLCR		 */		if (c == '\r') {			if (ISSET(iflag, IGNCR))				goto endcase;			else if (ISSET(iflag, ICRNL))				c = '\n';		} else if (c == '\n' && ISSET(iflag, INLCR))			c = '\r';	}	if (!ISSET(tp->t_lflag, EXTPROC) && ISSET(lflag, ICANON)) {		/*		 * From here on down canonical mode character		 * processing takes place.		 */		/*		 * erase (^H / ^?)		 */		if (CCEQ(cc[VERASE], c)) {			if (tp->t_rawq.c_cc)				ttyrub(unputc(&tp->t_rawq), tp);			goto endcase;		}		/*		 * kill (^U)		 */		if (CCEQ(cc[VKILL], c)) {			if (ISSET(lflag, ECHOKE) &&			    tp->t_rawq.c_cc == tp->t_rocount &&			    !ISSET(lflag, ECHOPRT))				while (tp->t_rawq.c_cc)					ttyrub(unputc(&tp->t_rawq), tp);			else {				ttyecho(c, tp);				if (ISSET(lflag, ECHOK) ||				    ISSET(lflag, ECHOKE))					ttyecho('\n', tp);				FLUSHQ(&tp->t_rawq);				tp->t_rocount = 0;			}			CLR(tp->t_state, TS_LOCAL);			goto endcase;		}		/*		 * word erase (^W)		 */		if (CCEQ(cc[VWERASE], c)) {			int alt = ISSET(lflag, ALTWERASE);			int ctype;			/*			 * erase whitespace			 */			while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t')				ttyrub(c, tp);			if (c == -1)				goto endcase;			/*			 * erase last char of word and remember the			 * next chars type (for ALTWERASE)			 */			ttyrub(c, tp);			c = unputc(&tp->t_rawq);			if (c == -1)				goto endcase;			if (c == ' ' || c == '\t') {				(void)putc(c, &tp->t_rawq);				goto endcase;			}			ctype = ISALPHA(c);			/*			 * erase rest of word			 */			do {				ttyrub(c, tp);				c = unputc(&tp->t_rawq);				if (c == -1)					goto endcase;			} while (c != ' ' && c != '\t' &&			    (alt == 0 || ISALPHA(c) == ctype));			(void)putc(c, &tp->t_rawq);			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)) {			if (ISSET(lflag, ISIG))				pgsignal(tp->t_pgrp, SIGINFO, 1);			if (!ISSET(lflag, NOKERNINFO))				ttyinfo(tp);			goto endcase;		}	}	/*	 * Check for input buffer overflow	 */	if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) {		if (ISSET(iflag, IMAXBEL)) {			if (tp->t_outq.c_cc < tp->t_hiwat)				(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 (!ISSET(lflag, ICANON)) {			ttwakeup(tp);			ttyecho(c, tp);			goto endcase;		}		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_column;		if (ISSET(tp->t_state, TS_ERASE)) {			/*			 * end of prterase \.../			 */			CLR(tp->t_state, TS_ERASE);			(void)ttyoutput('/', tp);		}		i = tp->t_column;		ttyecho(c, tp);		if (CCEQ(cc[VEOF], c) && ISSET(lflag, ECHO)) {			/*			 * Place the cursor over the '^' of the ^D.			 */			i = min(2, tp->t_column - i);			while (i > 0) {				(void)ttyoutput('\b', tp);				i--;			}		}	}endcase:	/*	 * IXANY means allow any character to restart output.	 */	if (ISSET(tp->t_state, TS_TTSTOP) &&	    !ISSET(iflag, IXANY) && cc[VSTART] != cc[VSTOP])		return (0);restartoutput:	CLR(tp->t_lflag, FLUSHO);	CLR(tp->t_state, TS_TTSTOP);startoutput:	return (ttstart(tp));}/* * Output a single character on a tty, doing output processing * as needed (expanding tabs, newline processing, etc.). * Returns < 0 if succeeds, otherwise returns char to resend. * Must be recursive. */intttyoutput(c, tp)	register int c;	register struct tty *tp;{	register long oflag;	register int col, s;	oflag = tp->t_oflag;	if (!ISSET(oflag, OPOST)) {		if (ISSET(tp->t_lflag, FLUSHO))			return (-1);		if (putc(c, &tp->t_outq))			return (c);		tk_nout++;		tp->t_outcc++;		return (-1);	}	/*	 * Do tab expansion if OXTABS is set.  Special case if we external	 * processing, we don't do the tab expansion because we'll probably	 * get it wrong.  If tab expansion needs to be done, let it happen	 * externally.	 */	CLR(c, ~TTY_CHARMASK);	if (c == '\t' &&	    ISSET(oflag, OXTABS) && !ISSET(tp->t_lflag, EXTPROC)) {		c = 8 - (tp->t_column & 7);		if (!ISSET(tp->t_lflag, FLUSHO)) {			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_column += c;		return (c ? -1 : '\t');	}	if (c == CEOT && ISSET(oflag, ONOEOT))		return (-1);	/*	 * Newline translation: if ONLCR is set,	 * translate newline into "\r\n".	 */	if (c == '\n' && ISSET(tp->t_oflag, ONLCR)) {		tk_nout++;		tp->t_outcc++;		if (putc('\r', &tp->t_outq))			return (c);	}	tk_nout++;	tp->t_outcc++;	if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq))		return (c);	col = tp->t_column;	switch (CCLASS(c)) {	case BACKSPACE:		if (col > 0)			--col;		break;	case CONTROL:		break;	case NEWLINE:	case RETURN:		col = 0;		break;	case ORDINARY:		++col;		break;	case TAB:		col = (col + 8) & ~7;		break;	}	tp->t_column = col;	return (-1);}/* * Ioctls for all tty devices.  Called after line-discipline specific ioctl * has been called to do discipline-specific functions and/or reject any * of these ioctl commands. *//* ARGSUSED */intttioctl(tp, cmd, data, flag)	register struct tty *tp;	int cmd, flag;	void *data;{	extern struct tty *constty;	/* Temporary virtual console. */	extern int nlinesw;	register struct proc *p;	int s, error;	p = curproc;			/* XXX */	/* If the ioctl involves modification, hang if in the background. */	switch (cmd) {	case  TIOCFLUSH:	case  TIOCSETA:	case  TIOCSETD:	case  TIOCSETAF:	case  TIOCSETAW:#ifdef notdef	case  TIOCSPGRP:#endif	case  TIOCSTI:	case  TIOCSWINSZ:#if defined(COMPAT_43) || defined(COMPAT_SUNOS)	case  TIOCLBIC:	case  TIOCLBIS:	case  TIOCLSET:	case  TIOCSETC:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -