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

📄 sex_get.c

📁 早期freebsd实现
💻 C
字号:
/*- * Copyright (c) 1992, 1993, 1994 *	The Regents of the University of California.  All rights reserved. * * 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. */#ifndef lintstatic char sccsid[] = "@(#)sex_get.c	8.27 (Berkeley) 4/14/94";#endif /* not lint */#include <sys/types.h>#include <sys/queue.h>#include <sys/time.h>#include <bitstring.h>#include <ctype.h>#include <limits.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <termios.h>#include "compat.h"#include <db.h>#include <regex.h>#include "vi.h"#include "excmd.h"#include "vcmd.h"#include "sex_screen.h"/* * !!! * The ex input didn't have escape characters like ^V.  The only special * character was the backslash character, and that only when it preceded * a newline as part of a substitution replacement pattern.  For example, * the command input ":a\<cr>" failed immediately with an error, as the * <cr> wasn't part of a substitution replacement pattern.  This implies * a frightening integration of the editor and the RE engine.  There's no * way we're going to reproduce those semantics.  So, if backslashes are * special, this code inserts the backslash and the next character into the * string, without regard for the character or the command being entered. * Since "\<cr>" was illegal historically (except for the one special case), * and the command will fail eventually, historical scripts shouldn't break * (presuming they didn't depend on the failure mode itself or the characters * remaining when failure occurred. */static void	txt_display __P((SCR *, TEXT *, size_t, size_t *));static int	txt_outdent __P((SCR *, TEXT *));#define	ERASECH {							\	for (cnt = tp->wd[tp->len]; cnt-- > 0; --col)			\		(void)printf("\b \b");					\}/* * sex_get -- *	Get lines from the terminal for ex. */enum inputsex_get(sp, ep, tiqh, prompt, flags)	SCR *sp;	EXF *ep;	TEXTH *tiqh;	ARG_CHAR_T prompt;	u_int flags;{				/* State of the "[^0]^D" sequences. */	enum { C_NOTSET, C_CARATSET, C_NOCHANGE, C_ZEROSET } carat_st;	TEXT *ntp, *tp, ait;	/* Input and autoindent text structures. */	CH ikey;		/* Input character. */	size_t col;		/* 0-N: screen column. */	size_t cnt;	int rval, istty;	/*	 * !!!	 * Most of the special capabilities (like autoindent, erase,	 * etc.) are turned off if ex isn't talking to a terminal.	 */	istty = F_ISSET(sp->gp, G_STDIN_TTY);	/*	 * Get a TEXT structure with some initial buffer space, reusing	 * the last one if it's big enough.  (All TEXT bookkeeping fields	 * default to 0 -- text_init() handles this.)	 */	if (tiqh->cqh_first != (void *)tiqh) {		tp = tiqh->cqh_first;		if (tp->q.cqe_next != (void *)tiqh || tp->lb_len < 32) {			text_lfree(tiqh);			goto newtp;		}		tp->len = 0;	} else {newtp:		if ((tp = text_init(sp, NULL, 0, 32)) == NULL)			return (INP_ERR);		CIRCLEQ_INSERT_HEAD(tiqh, tp, q);	}	if (istty) {		/* Display the prompt. */		if (LF_ISSET(TXT_PROMPT)) {			col = KEY_LEN(sp, prompt);			(void)printf("%s", KEY_NAME(sp, prompt));		}		/* Initialize autoindent value and print it out. */		if (LF_ISSET(TXT_AUTOINDENT)) {			if (txt_auto(sp, ep, sp->lno, NULL, 0, tp))				return (INP_ERR);			BINC_GOTO(sp, tp->wd, tp->wd_len, tp->len + 1);			for (cnt = 0; cnt < tp->ai; ++cnt)				txt_display(sp, tp, cnt, &col);		}	} else {		col = 0;		/* Turn off autoindent here, less special casing below. */		LF_CLR(TXT_AUTOINDENT);	}	for (carat_st = C_NOTSET;;) {		if (istty)			(void)fflush(stdout);		/*		 * !!!		 * Historically, ex never mapped commands or keys.		 */		if (rval = term_key(sp, &ikey, 0))			return (rval);		BINC_GOTO(sp, tp->lb, tp->lb_len, tp->len + 1);		BINC_GOTO(sp, tp->wd, tp->wd_len, tp->len + 1);		switch (ikey.value) {		case K_CR:		case K_NL:			/* '\' can escape <carriage-return>/<newline>. */			if (LF_ISSET(TXT_BACKSLASH) &&			    tp->len != 0 && tp->lb[tp->len - 1] == '\\')				goto ins_ch;			/* Echo the newline if requested. */k_cr:			if (istty && LF_ISSET(TXT_NLECHO)) {				(void)putc('\r', stdout);				(void)putc('\n', stdout);				(void)fflush(stdout);			}			/*			 * CR returns from the ex command line, interrupt			 * always returns.			 */			if (LF_ISSET(TXT_CR) || F_ISSET(sp, S_INTERRUPTED)) {				/* Terminate with a nul, needed by filter. */				tp->lb[tp->len] = '\0';				return (INP_OK);			}			/* '.' terminates ex input modes. */			if (LF_ISSET(TXT_DOTTERM) &&			    tp->len == tp->ai + 1 &&			    tp->lb[tp->len - 1] == '.') {				/* Release the current TEXT. */				ntp = tp->q.cqe_prev;				CIRCLEQ_REMOVE(tiqh, tp, q);				text_free(tp);				tp = ntp;				return (INP_OK);			}			/*			 * If we echoed the newline, display any accumulated			 * error messages.			 */			if (LF_ISSET(TXT_NLECHO) && sp->s_refresh(sp, ep))				return (INP_ERR);			/* Set up bookkeeping for the new line. */			if ((ntp = text_init(sp, NULL, 0, 32)) == NULL)				return (INP_ERR);			ntp->lno = tp->lno + 1;			/*			 * Reset the autoindent line value.  0^D keeps the ai			 * line from changing, ^D changes the level, even if			 * there are no characters in the old line.  Note,			 * if using the current tp structure, use the cursor			 * as the length, the user may have erased autoindent			 * characters.			 */			col = 0;			if (LF_ISSET(TXT_AUTOINDENT)) {				if (carat_st == C_NOCHANGE) {					if (txt_auto(sp, ep,					    OOBLNO, &ait, ait.ai, ntp))						return (INP_ERR);					FREE_SPACE(sp, ait.lb, ait.lb_len);				} else					if (txt_auto(sp, ep,					    OOBLNO, tp, tp->len, ntp))						return (INP_ERR);				carat_st = C_NOTSET;				if (ntp->ai) {					BINC_GOTO(sp,					    ntp->wd, ntp->wd_len, ntp->len + 1);					for (cnt = 0; cnt < ntp->ai; ++cnt)						txt_display(sp, ntp, cnt, &col);				}			}			/*			 * Swap old and new TEXT's, and insert the new TEXT			 * into the queue.			 */			tp = ntp;			CIRCLEQ_INSERT_TAIL(tiqh, tp, q);			break;		case K_CARAT:			/* Delete autoindent chars. */			if (LF_ISSET(TXT_AUTOINDENT) && tp->len <= tp->ai)				carat_st = C_CARATSET;			goto ins_ch;		case K_ZERO:			/* Delete autoindent chars. */			if (LF_ISSET(TXT_AUTOINDENT) && tp->len <= tp->ai)				carat_st = C_ZEROSET;			goto ins_ch;		case K_CNTRLD:			/* Delete autoindent char. */			/*			 * !!!			 * Historically, the ^D command took (but then ignored)			 * a count.  For simplicity, we don't return it unless			 * it's the first character entered.  The check for len			 * equal to 0 is okay, TXT_AUTOINDENT won't be set.			 */			if (LF_ISSET(TXT_CNTRLD) && tp->len == 0) {				tp->len = 1;				tp->lb[0] = '\004';				tp->lb[1] = '\0';				return (INP_OK);			}			/*			 * If in the first column or no characters to erase,			 * ignore the ^D (this matches historic practice).  If			 * not doing autoindent or already inserted non-ai			 * characters, it's a literal.  The latter test is done			 * in the switch, as the CARAT forms are N + 1, not N.			 */			if (!LF_ISSET(TXT_AUTOINDENT))				goto ins_ch;			if (tp->len == 0)				break;			switch (carat_st) {			case C_CARATSET:	/* ^^D */				if (tp->len > tp->ai + 1)					goto ins_ch;				/* Save the ai string for later. */				ait.lb = NULL;				ait.lb_len = 0;				BINC_GOTO(sp, ait.lb, ait.lb_len, tp->ai);				memmove(ait.lb, tp->lb, tp->ai);				ait.ai = ait.len = tp->ai;				carat_st = C_NOCHANGE;				goto leftmargin;			case C_ZEROSET:		/* 0^D */				if (tp->len > tp->ai + 1)					goto ins_ch;				carat_st = C_NOTSET;leftmargin:			(void)printf("\b \r");				tp->ai = tp->len = 0;				break;			case C_NOTSET:		/* ^D */				if (tp->len > tp->ai)					goto ins_ch;				if (txt_outdent(sp, tp))					return (INP_ERR);				break;			default:				abort();			}			break;		case K_VERASE:			if (!istty)				goto ins_ch;			if (tp->len) {				--tp->len;				if (tp->lb[tp->len] == '\n' ||				    tp->lb[tp->len] == '\r')					goto repaint;				ERASECH;			}			break;		case K_VINTR:			if (!istty)				goto ins_ch;			if (F_ISSET(sp, S_INTERRUPTIBLE)) {				F_SET(sp, S_INTERRUPTED);				msgq(sp, M_ERR, "Interrupted.");				goto k_cr;			}			goto ins_ch;		case K_VWERASE:			if (!istty)				goto ins_ch;			/* Move to the last non-space character. */			while (tp->len) {				--tp->len;				if (tp->lb[tp->len] == '\n' ||				    tp->lb[tp->len] == '\r')					goto repaint;				if (!isblank(tp->lb[tp->len])) {					++tp->len;					break;				} else					ERASECH;			}			/* Move to the last space character. */			while (tp->len) {				--tp->len;				if (tp->lb[tp->len] == '\n' ||				    tp->lb[tp->len] == '\r')					goto repaint;				if (isblank(tp->lb[tp->len])) {					++tp->len;					break;				} else					ERASECH;			}			break;		case K_VKILL:			if (!istty)				goto ins_ch;			while (tp->len) {				--tp->len;				if (tp->lb[tp->len] == '\n' ||				    tp->lb[tp->len] == '\r') {					tp->len = 0;					goto repaint;				}				ERASECH;			}			break;		case K_CNTRLZ:			if (!istty)				goto ins_ch;			sex_suspend(sp);			/* FALLTHROUGH */		case K_CNTRLR:			if (!istty)				goto ins_ch;repaint:		if (LF_ISSET(TXT_PROMPT)) {				col = KEY_LEN(sp, prompt);				(void)printf("\r%s", KEY_NAME(sp, prompt));			} else {				col = 0;				(void)putc('\r', stdout);			}			for (cnt = 0; cnt < tp->len; ++cnt)				txt_display(sp, tp, cnt, &col);			break;		default:			/*			 * See the TXT_BEAUTIFY comment in vi/v_ntext.c.			 *			 * Eliminate any unquoted, iscntrl() character from a			 * script that wasn't handled specially, except for			 * <tab> or <ff>.			 */ins_ch:			if (!istty && LF_ISSET(TXT_BEAUTIFY) &&			    iscntrl(ikey.ch) && ikey.value != K_FORMFEED &&			    ikey.value != K_TAB) {				msgq(sp, M_BERR,				    "Illegal character; quote to enter.");				break;			}			tp->lb[tp->len] = ikey.ch;			if (istty)				txt_display(sp, tp, tp->len, &col);			++tp->len;			break;		}	}	/* NOTREACHED */binc_err:	return (INP_ERR);}/* * txt_display -- *	Display the character. */static voidtxt_display(sp, tp, off, colp)	SCR *sp;	TEXT *tp;	size_t off, *colp;{	CHAR_T ch;	size_t width;	switch (ch = tp->lb[off]) {	case '\t':		*colp += tp->wd[off] = width =		    O_VAL(sp, O_TABSTOP) - *colp % O_VAL(sp, O_TABSTOP);		while (width--)			putc(' ', stdout);		break;	case '\n':	case '\r':		(void)putc('\r', stdout);		(void)putc('\n', stdout);		break;	default:		*colp += tp->wd[off] = KEY_LEN(sp, ch);		(void)printf("%s", KEY_NAME(sp, ch));	}}/* * txt_outdent -- *	Handle ^D outdents. * * Ex version of vi/v_ntext.c:txt_outdent().  See that code for the * usual ranting and raving. */static inttxt_outdent(sp, tp)	SCR *sp;	TEXT *tp;{	u_long sw, ts;	size_t cno, cnt, off, scno, spaces;	ts = O_VAL(sp, O_TABSTOP);	sw = O_VAL(sp, O_SHIFTWIDTH);	/* Get the current screen column. */	for (off = scno = 0; off < tp->len; ++off)		if (tp->lb[off] == '\t')			scno += STOP_OFF(scno, ts);		else			++scno;	/* Get the previous shiftwidth column. */	for (cno = scno; --scno % sw != 0;);	/* Decrement characters until less than or equal to that slot. */	for (; cno > scno; --tp->ai) {		for (cnt = tp->wd[--tp->len]; cnt-- > 0;)			(void)printf("\b \b");		if (tp->lb[--off] == '\t')			cno -= STOP_OFF(cno, ts);		else			--cno;	}	/* Spaces needed to get to the target. */	spaces = scno - cno;	/* Maybe just a delete. */	if (spaces == 0)		return (0);	/* Make sure there's enough room. */	BINC_RET(sp, tp->lb, tp->lb_len, tp->len + spaces);	/* Maybe that was enough. */	if (spaces == 0)		return (0);	/* Add new space characters. */	for (; spaces--; ++tp->ai)		tp->lb[tp->len++] = ' ';	return (0);}

⌨️ 快捷键说明

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