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

📄 v_ntext.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 4 页
字号:
/*- * Copyright (c) 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[] = "@(#)v_ntext.c	8.104 (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 <errno.h>#include <limits.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <termios.h>#include <unistd.h>#include "compat.h"#include <db.h>#include <regex.h>#include "vi.h"#include "seq.h"#include "vcmd.h"#include "excmd.h"static int	 txt_abbrev __P((SCR *, TEXT *, CHAR_T *, int, int *, int *));static void	 txt_ai_resolve __P((SCR *, TEXT *));static TEXT	*txt_backup __P((SCR *, EXF *, TEXTH *, TEXT *, u_int *));static void	 txt_err __P((SCR *, EXF *, TEXTH *));static int	 txt_hex __P((SCR *, TEXT *));static int	 txt_indent __P((SCR *, TEXT *));static int	 txt_margin __P((SCR *, TEXT *, int *, CHAR_T *));static int	 txt_outdent __P((SCR *, TEXT *));static void	 txt_Rcleanup __P((SCR *,		    TEXTH *, TEXT *, const char *, const size_t));static int	 txt_resolve __P((SCR *, EXF *, TEXTH *, u_int));static void	 txt_showmatch __P((SCR *, EXF *));static void	 txt_unmap __P((SCR *, TEXT *, u_int *));/* Cursor character (space is hard to track on the screen). */#if defined(DEBUG) && 0#undef	CH_CURSOR#define	CH_CURSOR	'+'#endif/* * v_ntext -- *	Read in text from the user. * * !!! * Historic vi did a special screen optimization for tab characters.  For * the keystrokes "iabcd<esc>0C<tab>", the tab would overwrite the rest of * the string when it was displayed.  Because this implementation redisplays * the entire line on each keystroke, the "bcd" gets pushed to the right as * we ignore that the user has "promised" to change the rest of the characters. * Users have noticed, but this isn't worth fixing, and, the way that the * historic vi did it results in an even worse bug.  Given the keystrokes * "iabcd<esc>0R<tab><esc>", the "bcd" disappears, and magically reappears * on the second <esc> key. */intv_ntext(sp, ep, tiqh, tm, lp, len, rp, prompt, ai_line, flags)	SCR *sp;	EXF *ep;	TEXTH *tiqh;	MARK *tm;		/* To MARK. */	const char *lp;		/* Input line. */	const size_t len;	/* Input line length. */	MARK *rp;		/* Return MARK. */	ARG_CHAR_T prompt;	/* Prompt to display. */	recno_t ai_line;	/* Line number to use for autoindent count. */	u_int flags;		/* TXT_ flags. */{				/* State of abbreviation checks. */	enum { A_NOTSET, A_NOTWORD, A_INWORD } abb;				/* State of the "[^0]^D" sequences. */	enum { C_NOTSET, C_CARATSET, C_NOCHANGE, C_ZEROSET } carat_st;				/* State of the hex input character. */	enum { H_NOTSET, H_NEXTCHAR, H_INHEX } hex;				/* State of quotation. */	enum { Q_NOTSET, Q_NEXTCHAR, Q_THISCHAR } quoted;	CH ikey;		/* Input character structure. */	CHAR_T ch;		/* Input character. */	TEXT *tp, *ntp, ait;	/* Input and autoindent text structures. */	size_t owrite, insert;	/* Temporary copies of TEXT fields. */	size_t rcol;		/* 0-N: insert offset in the replay buffer. */	size_t col;		/* Current column. */	u_long margin;		/* Wrapmargin value. */	u_int iflags;		/* Input flags. */	int ab_cnt, ab_turnoff;	/* Abbreviation count, if turned off. */	int eval;		/* Routine return value. */	int replay;		/* If replaying a set of input. */	int showmatch;		/* Showmatch set on this character. */	int testnr;		/* Test first character for nul replay. */	int max, tmp;	int unmap_tst;		/* Input map needs testing. */	char *p;	/*	 * Set the input flag, so tabs get displayed correctly	 * and everyone knows that the text buffer is in use.	 */	F_SET(sp, S_INPUT);	/* Local initialization. */	eval = 0;	/*	 * Get one 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 changing a line,	 * copy it into the TEXT buffer.	 */	if (tiqh->cqh_first != (void *)tiqh) {		tp = tiqh->cqh_first;		if (tp->q.cqe_next != (void *)tiqh || tp->lb_len < len + 32) {			text_lfree(tiqh);			goto newtp;		}		tp->ai = tp->insert = tp->offset = tp->owrite = 0;		if (lp != NULL) {			tp->len = len;			memmove(tp->lb, lp, len);		} else			tp->len = 0;	} else {newtp:		if ((tp = text_init(sp, lp, len, len + 32)) == NULL)			return (1);		CIRCLEQ_INSERT_HEAD(tiqh, tp, q);	}	/* Set the starting line number. */	tp->lno = sp->lno;	/*	 * Set the insert and overwrite counts.  If overwriting characters,	 * do insertion afterward.  If not overwriting characters, assume	 * doing insertion.  If change is to a mark, emphasize it with an	 * CH_ENDMARK	 */	if (len) {		if (LF_ISSET(TXT_OVERWRITE)) {			tp->owrite = (tm->cno - sp->cno) + 1;			tp->insert = (len - tm->cno) - 1;		} else			tp->insert = len - sp->cno;		if (LF_ISSET(TXT_EMARK))			tp->lb[tm->cno] = CH_ENDMARK;	}	/*	 * Many of the special cases in this routine are to handle autoindent	 * support.  Somebody decided that it would be a good idea if "^^D"	 * and "0^D" deleted all of the autoindented characters.  In an editor	 * that takes single character input from the user, this beggars the	 * imagination.  Note also, "^^D" resets the next lines' autoindent,	 * but "0^D" doesn't.	 *	 * We assume that autoindent only happens on empty lines, so insert	 * and overwrite will be zero.  If doing autoindent, figure out how	 * much indentation we need and fill it in.  Update input column and	 * screen cursor as necessary.	 */	if (LF_ISSET(TXT_AUTOINDENT) && ai_line != OOBLNO) {		if (txt_auto(sp, ep, ai_line, NULL, 0, tp))			return (1);		sp->cno = tp->ai;	} else {		/*		 * The cc and S commands have a special feature -- leading		 * <blank> characters are handled as autoindent characters.		 * Beauty!		 */		if (LF_ISSET(TXT_AICHARS)) {			tp->offset = 0;			tp->ai = sp->cno;		} else			tp->offset = sp->cno;	}	/* If getting a command buffer from the user, there may be a prompt. */	if (LF_ISSET(TXT_PROMPT)) {		tp->lb[sp->cno++] = prompt;		++tp->len;		++tp->offset;	}	/*	 * If appending after the end-of-line, add a space into the buffer	 * and move the cursor right.  This space is inserted, i.e. pushed	 * along, and then deleted when the line is resolved.  Assumes that	 * the cursor is already positioned at the end of the line.  This	 * avoids the nastiness of having the cursor reside on a magical	 * column, i.e. a column that doesn't really exist.  The only down	 * side is that we may wrap lines or scroll the screen before it's	 * strictly necessary.  Not a big deal.	 */	if (LF_ISSET(TXT_APPENDEOL)) {		tp->lb[sp->cno] = CH_CURSOR;		++tp->len;		++tp->insert;	}	/*	 * Historic practice is that the wrapmargin value was a distance	 * from the RIGHT-HAND column, not the left.  It's more useful to	 * us as a distance from the left-hand column.	 *	 * !!!	 * Replay commands are not affected by wrapmargin values.  What	 * I found surprising was that people actually depend on it, as	 * in this gem of a macro which centers lines:	 *	 *	map #c $mq81a ^V^[81^V|D`qld0:s/  / /g^V^M$p	 *	 * XXX	 * Setting margin causes a significant performance hit.  Normally	 * we don't update the screen if there are keys waiting, but we	 * have to if margin is set, otherwise the screen routines don't	 * know where the cursor is.	 */	if (LF_ISSET(TXT_REPLAY) || !LF_ISSET(TXT_WRAPMARGIN))		margin = 0;	else if ((margin = O_VAL(sp, O_WRAPMARGIN)) != 0)		margin = sp->cols - margin;	/* Initialize abbreviations checks. */	if (F_ISSET(sp->gp, G_ABBREV) && LF_ISSET(TXT_MAPINPUT)) {		abb = A_INWORD;		ab_cnt = ab_turnoff = 0;	} else		abb = A_NOTSET;	/*	 * Set up the dot command.  Dot commands are done by saving the	 * actual characters and replaying the input.  We have to push	 * the characters onto the key stack and then handle them normally,	 * otherwise things like wrapmargin will fail.	 *	 * XXX	 * It would be nice if we could swallow backspaces and such, but	 * it's not all that easy to do.  Another possibility would be to	 * recognize full line insertions, which could be performed quickly,	 * without replay.	 */nullreplay:	rcol = 0;	if (replay = LF_ISSET(TXT_REPLAY)) {		/*		 * !!!		 * Historically, it wasn't an error to replay non-existent		 * input.  This test is necessary, we get here by the user		 * doing an input command followed by a nul.		 *		 * !!!		 * Historically, vi did not remap or reabbreviate replayed		 * input.  It did, however, beep at you if you changed an		 * abbreviation and then replayed the input.  We're not that		 * compatible.		 */		if (VIP(sp)->rep == NULL)			return (0);		if (term_push(sp, VIP(sp)->rep, VIP(sp)->rep_cnt, 0, CH_NOMAP))			return (1);		testnr = 0;		abb = A_NOTSET;		LF_CLR(TXT_RECORD);	} else		testnr = 1;	unmap_tst = LF_ISSET(TXT_MAPINPUT) && LF_ISSET(TXT_INFOLINE);	iflags = LF_ISSET(TXT_MAPCOMMAND | TXT_MAPINPUT);	for (showmatch = 0,	    carat_st = C_NOTSET, hex = H_NOTSET, quoted = Q_NOTSET;;) {		/*		 * Reset the line and update the screen.  (The txt_showmatch()		 * code refreshes the screen for us.)  Don't refresh unless		 * we're about to wait on a character or we need to know where		 * the cursor really is.		 */		if (showmatch || margin || !KEYS_WAITING(sp)) {			if (sp->s_change(sp, ep, tp->lno, LINE_RESET))				goto err;			if (showmatch) {				showmatch = 0;				txt_showmatch(sp, ep);			} else if (sp->s_refresh(sp, ep))				goto err;		}		/* Get the next character. */next_ch:	if (term_key(sp, &ikey, quoted == Q_THISCHAR ?		    iflags & ~(TXT_MAPCOMMAND | TXT_MAPINPUT) :		    iflags) != INP_OK)			goto err;		ch = ikey.ch;		/* Abbreviation check.  See comment in txt_abbrev(). */#define	MAX_ABBREVIATION_EXPANSION	256		if (ikey.flags & CH_ABBREVIATED) {			if (++ab_cnt > MAX_ABBREVIATION_EXPANSION) {				term_ab_flush(sp,			"Abbreviation exceeded maximum number of characters");				ab_cnt = 0;				continue;			}		} else			ab_cnt = 0;		/*		 * !!!		 * Historic feature.  If the first character of the input is		 * a nul, replay the previous input.  This isn't documented		 * anywhere, and is a great test of vi clones.		 */		if (ch == '\0' && testnr) {			LF_SET(TXT_REPLAY);			goto nullreplay;		}		testnr = 0;		/*		 * Check to see if the character fits into the input (and		 * replay, if necessary) buffers.  It isn't necessary to		 * have tp->len bytes, since it doesn't consider overwrite		 * characters, but not worth fixing.		 */		if (LF_ISSET(TXT_RECORD)) {			BINC_GOTO(sp, VIP(sp)->rep, VIP(sp)->rep_len, rcol + 1);			VIP(sp)->rep[rcol++] = ch;		}		BINC_GOTO(sp, tp->lb, tp->lb_len, tp->len + 1);		/*		 * If the character was quoted, replace the last character		 * (the literal mark) with the new character.  If quoted		 * by someone else, simply insert the character.		 */		if (ikey.flags & CH_QUOTED)			goto insq_ch;		if (quoted == Q_THISCHAR) {			--sp->cno;			++tp->owrite;			quoted = Q_NOTSET;			goto insq_ch;		}		/*		 * !!!		 * Extension.  If the user enters "<CH_HEX>[isxdigit()]*" we		 * will try to use the value as a character.  Anything else		 * inserts the <CH_HEX> character, and resets hex mode.		 */		if (hex == H_INHEX && !isxdigit(ch)) {			if (txt_hex(sp, tp))				goto err;			hex = H_NOTSET;		}		switch (ikey.value) {		case K_CR:		case K_NL:				/* New line. */			/* CR returns from the vi command line. */			if (LF_ISSET(TXT_CR)) {				/*				 * If a script window and not the colon				 * line, push a <cr> so it gets executed.				 */				if (F_ISSET(sp, S_SCRIPT) &&				    !LF_ISSET(TXT_INFOLINE))					(void)term_push(sp,					    "\r", 1, 0, CH_NOMAP);				goto k_escape;			}#define	LINE_RESOLVE {							\			/*						\			 * Handle abbreviations.  If there was one,	\			 * discard the replay characters.		\			 */						\			if (abb == A_INWORD && !replay) {		\				if (txt_abbrev(sp, tp, &ch,		\				    LF_ISSET(TXT_INFOLINE), &tmp,	\				    &ab_turnoff))			\					goto err;			\				if (tmp) {				\					if (LF_ISSET(TXT_RECORD))	\						rcol -= tmp;		\					goto next_ch;			\				}					\			}						\			if (abb != A_NOTSET)				\				abb = A_NOTWORD;			\			if (unmap_tst)					\				txt_unmap(sp, tp, &iflags);		\			/* Delete any appended cursor. */		\			if (LF_ISSET(TXT_APPENDEOL)) {			\				--tp->len;				\				--tp->insert;				\			}						\}			LINE_RESOLVE;			/*			 * Save the current line information for restoration			 * in txt_backup().  Set the new line length.			 */			tp->sv_len = tp->len;			tp->sv_cno = sp->cno;			tp->len = sp->cno;

⌨️ 快捷键说明

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