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

📄 vi.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * 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[] = "@(#)vi.c	8.61 (Berkeley) 4/10/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 "compat.h"#include <db.h>#include <regex.h>#include "vi.h"#include "vcmd.h"static int getcmd __P((SCR *, EXF *,		VICMDARG *, VICMDARG *, VICMDARG *, int *));static inline int	   getcount __P((SCR *, ARG_CHAR_T, u_long *));static inline int	   getkey __P((SCR *, CH *, u_int));static int getkeyword __P((SCR *, EXF *, VICMDARG *, u_int));static int getmotion __P((SCR *, EXF *, VICMDARG *, VICMDARG *));/* * Side-effect: *	The dot structure can be set by the underlying vi functions, *	see v_Put() and v_put(). */#define	DOT		(&VIP(sp)->sdot)#define	DOTMOTION	(&VIP(sp)->sdotmotion)/* * vi -- * 	Main vi command loop. */intvi(sp, ep)	SCR *sp;	EXF *ep;{	MARK abs;	VICMDARG cmd, *vp;	u_int flags, saved_mode;	int comcount, eval;	/* Start vi and paint the screen. */	if (v_init(sp, ep))		return (1);	if (sp->s_refresh(sp, ep)) {		(void)v_end(sp);		return (1);	}	/* Command initialization. */	memset(&cmd, 0, sizeof(VICMDARG));	for (eval = 0, vp = &cmd;;) {		if (!MAPPED_KEYS_WAITING(sp) && log_cursor(sp, ep))			goto err;		/*		 * We get a command, which may or may not have an associated		 * motion.  If it does, we get it too, calling its underlying		 * function to get the resulting mark.  We then call the		 * command setting the cursor to the resulting mark.		 */		if (getcmd(sp, ep, DOT, vp, NULL, &comcount))			goto err;		/*		 * Historical practice: if a dot command gets a new count,		 * any motion component goes away, i.e. "d3w2." deletes a		 * total of 5 words.		 */		if (F_ISSET(vp, VC_ISDOT) && comcount)			DOTMOTION->count = 1;		/* Copy the key flags into the local structure. */		F_SET(vp, vp->kp->flags);		/* Get any associated keyword. */		if (F_ISSET(vp, V_KEYNUM | V_KEYW) &&		    getkeyword(sp, ep, vp, vp->flags))			goto err;		/* If a non-relative movement, copy the future absolute mark. */		if (F_ISSET(vp, V_ABS)) {			abs.lno = sp->lno;			abs.cno = sp->cno;		}		/*		 * Set the three cursor locations to the current cursor.  The		 * underlying routines don't bother if the cursor doesn't move.		 * This also handles line commands (e.g. Y) defaulting to the		 * current line.		 */		vp->m_start.lno = vp->m_stop.lno = vp->m_final.lno = sp->lno;		vp->m_start.cno = vp->m_stop.cno = vp->m_final.cno = sp->cno;		/*		 * Do any required motion; getmotion sets the from MARK and the		 * line mode flag.  We save off the RCM mask and only restore		 * it if it no RCM flags are set by the motion command.  This		 * means that the motion command is expected to determine where		 * the cursor ends up!		 */		if (F_ISSET(vp, V_MOTION)) {			flags = F_ISSET(vp, VM_RCM_MASK);			F_CLR(vp, VM_RCM_MASK);			if (getmotion(sp, ep, DOTMOTION, vp))				goto err;			if (F_ISSET(vp, VM_NOMOTION))				goto err;			if (!F_ISSET(vp, VM_RCM_MASK))				F_SET(vp, flags);		}		/*		 * If a count is set and the command is line oriented, set the		 * to MARK here relative to the cursor/from MARK.  This is for		 * commands that take both counts and motions, i.e. "4yy" and		 * "y%".  As there's no way the command can know which the user		 * did, we have to do it here.  (There are commands that are		 * line oriented and that take counts ("#G", "#H"), for which		 * this calculation is either completely meaningless or wrong.		 * Each command must validate the value for itself.		 */		if (F_ISSET(vp, VC_C1SET) && F_ISSET(vp, VM_LMODE))			vp->m_stop.lno += vp->count - 1;		/* Increment the command count. */		++sp->ccnt;		/* Clear interrupt bits, save the mode and call the function. */		F_CLR(sp, S_INTERRUPTED | S_INTERRUPTIBLE);		saved_mode = F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE);		if ((vp->kp->func)(sp, ep, vp))			goto err;#ifdef DEBUG		/* Make sure no function left the temporary space locked. */		if (F_ISSET(sp->gp, G_TMP_INUSE)) {			msgq(sp, M_ERR,			    "Error: vi: temporary buffer not released.");			return (1);		}#endif		/*		 * If that command took us out of vi or changed the screen,		 * then exit the loop without further action.		 */		 if (saved_mode != F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE))			break;		/* Set the absolute mark. */		if (F_ISSET(vp, V_ABS) && mark_set(sp, ep, ABSMARK1, &abs, 1))			goto err;		/* Set the dot command structure. */		if (F_ISSET(vp, V_DOT)) {			*DOT = cmd;			F_SET(DOT, VC_ISDOT);			/*			 * If a count was supplied for both the command and			 * its motion, the count was used only for the motion.			 * Turn the count back on for the dot structure.			 */			if (F_ISSET(vp, VC_C1RESET))				F_SET(DOT, VC_C1SET);		}		/*		 * Some vi row movements are "attracted" to the last position		 * set, i.e. the VM_RCM commands are moths to the VM_RCM_SET		 * commands' candle.  It's broken into two parts.  Here we deal		 * with the command flags.  In sp->relative(), we deal with the		 * screen flags.  If the movement is to the EOL the vi command		 * handles it.  If it's to the beginning, we handle it here.		 *		 * Note, some commands (e.g. _, ^) don't set the VM_RCM_SETFNB		 * flag, but do the work themselves.  The reason is that they		 * have to modify the column in case they're being used as a		 * motion component.  Other similar commands (e.g. +, -) don't		 * have to modify the column because they are always line mode		 * operations when used as motions, so the column number isn't		 * of any interest.		 *		 * Does this totally violate the screen and editor layering?		 * You betcha.  As they say, if you think you understand it,		 * you don't.		 */		switch (F_ISSET(vp, VM_RCM_MASK)) {		case 0:		case VM_RCM_SET:			break;		case VM_RCM:			vp->m_final.cno = sp->s_rcm(sp, ep, vp->m_final.lno);			break;		case VM_RCM_SETLAST:			sp->rcm_last = 1;			break;		case VM_RCM_SETLFNB:			/*			 * If we changed lines, move to the first non-blank.			 * This is the hack that makes logical scrolling on			 * really long lines work.			 */			if (vp->m_start.lno != vp->m_final.lno) {				vp->m_final.cno = 0;				if (nonblank(sp, ep,				    vp->m_final.lno, &vp->m_final.cno))					goto err;				F_SET(vp, VM_RCM_SET);			}			break;		case VM_RCM_SETFNB:			vp->m_final.cno = 0;			/* FALLTHROUGH */		case VM_RCM_SETNNB:			if (nonblank(sp, ep, vp->m_final.lno, &vp->m_final.cno))				goto err;			F_SET(vp, VM_RCM_SET);			break;		default:			abort();		}		/* Update the cursor. */		sp->lno = vp->m_final.lno;		sp->cno = vp->m_final.cno;		if (!MAPPED_KEYS_WAITING(sp)) {			(void)msg_rpt(sp, 1);			if (0)err:				term_map_flush(sp, "Vi error");		}		/* Refresh the screen. */		if (sp->s_refresh(sp, ep)) {			eval = 1;			break;		}		/* Set the new favorite position. */		if (F_ISSET(vp, VM_RCM_SET)) {			sp->rcm_last = 0;			(void)sp->s_column(sp, ep, &sp->rcm);		}	}	return (v_end(sp) || eval);}#define	KEY(key, map) {							\	if (getkey(sp, &ikey, map))					\		return (1);						\	key = ikey.ch;							\}/* * getcmd -- * * The command structure for vi is less complex than ex (and don't think * I'm not grateful!)  The command syntax is: * *	[count] [buffer] [count] key [[motion] | [buffer] [character]] * * and there are several special cases.  The motion value is itself a vi * command, with the syntax: * *	[count] key [character] */static intgetcmd(sp, ep, dp, vp, ismotion, comcountp)	SCR *sp;	EXF *ep;	VICMDARG *dp, *vp;	VICMDARG *ismotion;	/* Previous key if getting motion component. */	int *comcountp;{	VIKEYS const *kp;	u_int flags;	CH ikey;	CHAR_T key;	/* Refresh the command structure. */	memset(&vp->vp_startzero, 0,	    (char *)&vp->vp_endzero - (char *)&vp->vp_startzero);	/* An escape bells the user if in command mode. */	if (getkey(sp, &ikey, TXT_MAPCOMMAND)) {		if (ikey.value == K_ESCAPE && ismotion == NULL)			msgq(sp, M_BERR, "Already in command mode");		return (1);	}	/* Get the next key. */	key = ikey.ch;	/* Pick up optional buffer. */	if (key == '"') {		KEY(vp->buffer, 0);		F_SET(vp, VC_BUFFER);		KEY(key, TXT_MAPCOMMAND);	}	/*	 * Pick up optional count, where a leading 0 is not a count,	 * it's a command.	 */	if (isdigit(key) && key != '0') {		if (getcount(sp, key, &vp->count))			return (1);		F_SET(vp, VC_C1SET);		*comcountp = 1;		KEY(key, TXT_MAPCOMMAND);	} else		*comcountp = 0;	/* Pick up optional buffer. */	if (key == '"') {		if (F_ISSET(vp, VC_BUFFER)) {			msgq(sp, M_ERR, "Only one buffer can be specified.");			return (1);		}		KEY(vp->buffer, 0);		F_SET(vp, VC_BUFFER);		KEY(key, TXT_MAPCOMMAND);	}	/* Check for an OOB command key. */	if (key > MAXVIKEY) {		msgq(sp, M_BERR, "%s isn't a vi command", KEY_NAME(sp, key));		return (1);	}	/*	 * Find the command.  The only legal command with no underlying	 * function is dot.	 */	kp = vp->kp = &vikeys[vp->key = key];	if (kp->func == NULL) {		if (key != '.') {			msgq(sp, M_ERR,			    "%s isn't a command", KEY_NAME(sp, key));			return (1);		}		/* If called for a motion command, stop now. */		if (dp == NULL)			goto usage;		/* A repeatable command must have been executed. */		if (!F_ISSET(dp, VC_ISDOT)) {			msgq(sp, M_ERR, "No command to repeat.");			return (1);		}		/*

⌨️ 快捷键说明

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