Home | History | Annotate | Line # | Download | only in vi
      1 /*	$NetBSD: vi.c,v 1.8 2019/01/27 02:08:34 pgoyette Exp $ */
      2 /*-
      3  * Copyright (c) 1992, 1993, 1994
      4  *	The Regents of the University of California.  All rights reserved.
      5  * Copyright (c) 1992, 1993, 1994, 1995, 1996
      6  *	Keith Bostic.  All rights reserved.
      7  *
      8  * See the LICENSE file for redistribution information.
      9  */
     10 
     11 #include "config.h"
     12 
     13 #include <sys/cdefs.h>
     14 #if 0
     15 #ifndef lint
     16 static const char sccsid[] = "Id: vi.c,v 10.73 2002/04/11 19:49:30 skimo Exp  (Berkeley) Date: 2002/04/11 19:49:30 ";
     17 #endif /* not lint */
     18 #else
     19 __RCSID("$NetBSD: vi.c,v 1.8 2019/01/27 02:08:34 pgoyette Exp $");
     20 #endif
     21 
     22 #include <sys/types.h>
     23 #include <sys/queue.h>
     24 #include <sys/time.h>
     25 
     26 #include <bitstring.h>
     27 #include <ctype.h>
     28 #include <errno.h>
     29 #include <limits.h>
     30 #include <stdio.h>
     31 #include <stdlib.h>
     32 #include <string.h>
     33 #include <unistd.h>
     34 
     35 #include "../common/common.h"
     36 #include "vi.h"
     37 
     38 typedef enum {
     39 	GC_ERR, GC_ERR_NOFLUSH, GC_EVENT, GC_FATAL, GC_INTERRUPT, GC_OK
     40 } gcret_t;
     41 
     42 static VIKEYS const
     43 	       *v_alias __P((SCR *, VICMD *, VIKEYS const *));
     44 static gcret_t	v_cmd __P((SCR *, VICMD *, VICMD *, VICMD *, int *, int *));
     45 static int	v_count __P((SCR *, VICMD *, ARG_CHAR_T, u_long *));
     46 static void	v_dtoh __P((SCR *));
     47 static int	v_init __P((SCR *));
     48 static gcret_t	v_key __P((SCR *, VICMD *, int, u_int32_t));
     49 static int	v_motion __P((SCR *, VICMD *, VICMD *, int *));
     50 
     51 #if defined(DEBUG) && defined(COMLOG)
     52 static void	v_comlog __P((SCR *, VICMD *));
     53 #endif
     54 
     55 /*
     56  * Side-effect:
     57  *	The dot structure can be set by the underlying vi functions,
     58  *	see v_Put() and v_put().
     59  */
     60 #define	DOT		(&VIP(sp)->sdot)
     61 #define	DOTMOTION	(&VIP(sp)->sdotmotion)
     62 
     63 /*
     64  * vi --
     65  * 	Main vi command loop.
     66  *
     67  * PUBLIC: int vi __P((SCR **));
     68  */
     69 int
     70 vi(SCR **spp)
     71 {
     72 	GS *gp;
     73 	WIN *wp;
     74 	MARK abst;
     75 	SCR *next, *sp;
     76 	VICMD cmd, *vp;
     77 	VI_PRIVATE *vip;
     78 	int comcount, mapped, rval;
     79 #ifdef IMCTRL
     80 	int ret;
     81 #endif
     82 
     83 	/* Get the first screen. */
     84 	sp = *spp;
     85 	wp = sp->wp;
     86 	gp = sp->gp;
     87 
     88 	/* Initialize the command structure. */
     89 	vp = &cmd;
     90 	memset(vp, 0, sizeof(VICMD));
     91 
     92 	/* Reset strange attraction. */
     93 	F_SET(vp, VM_RCM_SET);
     94 
     95 	/* Initialize the vi screen. */
     96 	if (v_init(sp))
     97 		return (1);
     98 
     99 	/* Set the focus. */
    100 	(void)sp->gp->scr_rename(sp, sp->frp->name, 1);
    101 
    102 	for (vip = VIP(sp), rval = 0;;) {
    103 		/* Resolve messages. */
    104 		if (!MAPPED_KEYS_WAITING(sp) && vs_resolve(sp, NULL, 0))
    105 			goto ret;
    106 
    107 		/*
    108 		 * If not skipping a refresh, return to command mode and
    109 		 * refresh the screen.
    110 		 */
    111 		if (F_ISSET(vip, VIP_S_REFRESH))
    112 			F_CLR(vip, VIP_S_REFRESH);
    113 		else {
    114 			sp->showmode = SM_COMMAND;
    115 			if (vs_refresh(sp, 0))
    116 				goto ret;
    117 		}
    118 
    119 		/* Set the new favorite position. */
    120 		if (F_ISSET(vp, VM_RCM_SET | VM_RCM_SETFNB | VM_RCM_SETNNB)) {
    121 			F_CLR(vip, VIP_RCM_LAST);
    122 			(void)vs_column(sp, &sp->rcm);
    123 		}
    124 
    125 		/*
    126 		 * If not currently in a map, log the cursor position,
    127 		 * and set a flag so that this command can become the
    128 		 * DOT command.
    129 		 */
    130 		if (MAPPED_KEYS_WAITING(sp))
    131 			mapped = 1;
    132 		else {
    133 			if (log_cursor(sp))
    134 				goto err;
    135 			mapped = 0;
    136 		}
    137 
    138 		/*
    139 		 * There may be an ex command waiting, and we returned here
    140 		 * only because we exited a screen or file.  In this case,
    141 		 * we simply go back into the ex parser.
    142 		 */
    143 		if (EXCMD_RUNNING(wp)) {
    144 			vp->kp = &vikeys[':'];
    145 			goto ex_continue;
    146 		}
    147 
    148 		/* Refresh the command structure. */
    149 		memset(vp, 0, sizeof(VICMD));
    150 
    151 		/*
    152 		 * We get a command, which may or may not have an associated
    153 		 * motion.  If it does, we get it too, calling its underlying
    154 		 * function to get the resulting mark.  We then call the
    155 		 * command setting the cursor to the resulting mark.
    156 		 *
    157 		 * !!!
    158 		 * Vi historically flushed mapped characters on error, but
    159 		 * entering extra <escape> characters at the beginning of
    160 		 * a map wasn't considered an error -- in fact, users would
    161 		 * put leading <escape> characters in maps to clean up vi
    162 		 * state before the map was interpreted.  Beauty!
    163 		 */
    164 		switch (v_cmd(sp, DOT, vp, NULL, &comcount, &mapped)) {
    165 		case GC_ERR:
    166 			goto err;
    167 		case GC_ERR_NOFLUSH:
    168 			goto gc_err_noflush;
    169 		case GC_FATAL:
    170 			goto ret;
    171 		case GC_INTERRUPT:
    172 			goto intr;
    173 		case GC_EVENT:
    174 		case GC_OK:
    175 			break;
    176 		}
    177 
    178 		/* Check for security setting. */
    179 		if (F_ISSET(vp->kp, V_SECURE) && O_ISSET(sp, O_SECURE)) {
    180 			ex_emsg(sp, (const char *)KEY_NAME(sp, vp->key),
    181 			    EXM_SECURE);
    182 			goto err;
    183 		}
    184 
    185 		/*
    186 		 * Historical practice: if a dot command gets a new count,
    187 		 * any motion component goes away, i.e. "d3w2." deletes a
    188 		 * total of 5 words.
    189 		 */
    190 		if (F_ISSET(vp, VC_ISDOT) && comcount)
    191 			DOTMOTION->count = 1;
    192 
    193 		/* Copy the key flags into the local structure. */
    194 		F_SET(vp, vp->kp->flags);
    195 
    196 		/* Prepare to set the previous context. */
    197 		if (F_ISSET(vp, V_ABS | V_ABS_C | V_ABS_L)) {
    198 			abst.lno = sp->lno;
    199 			abst.cno = sp->cno;
    200 		}
    201 
    202 		/*
    203 		 * Set the three cursor locations to the current cursor.  The
    204 		 * underlying routines don't bother if the cursor doesn't move.
    205 		 * This also handles line commands (e.g. Y) defaulting to the
    206 		 * current line.
    207 		 */
    208 		vp->m_start.lno = vp->m_stop.lno = vp->m_final.lno = sp->lno;
    209 		vp->m_start.cno = vp->m_stop.cno = vp->m_final.cno = sp->cno;
    210 
    211 		/*
    212 		 * Do any required motion; v_motion sets the from MARK and the
    213 		 * line mode flag, as well as the VM_RCM flags.
    214 		 */
    215 		if (F_ISSET(vp, V_MOTION) &&
    216 		    v_motion(sp, DOTMOTION, vp, &mapped)) {
    217 			if (INTERRUPTED(sp))
    218 				goto intr;
    219 			goto err;
    220 		}
    221 
    222 		/*
    223 		 * If a count is set and the command is line oriented, set the
    224 		 * to MARK here relative to the cursor/from MARK.  This is for
    225 		 * commands that take both counts and motions, i.e. "4yy" and
    226 		 * "y%".  As there's no way the command can know which the user
    227 		 * did, we have to do it here.  (There are commands that are
    228 		 * line oriented and that take counts ("#G", "#H"), for which
    229 		 * this calculation is either completely meaningless or wrong.
    230 		 * Each command must validate the value for itself.
    231 		 */
    232 		if (F_ISSET(vp, VC_C1SET) && F_ISSET(vp, VM_LMODE))
    233 			vp->m_stop.lno += vp->count - 1;
    234 
    235 		/* Increment the command count. */
    236 		++sp->ccnt;
    237 
    238 #if defined(DEBUG) && defined(COMLOG)
    239 		v_comlog(sp, vp);
    240 #endif
    241 		/* Call the function. */
    242 #ifndef IMCTRL
    243 ex_continue:	if (vp->kp->func(sp, vp))
    244 			goto err;
    245 #else
    246 ex_continue:	if (strchr(O_STR(sp, O_IMKEY), vp->key))
    247 			sp->gp->scr_imctrl(sp, IMCTRL_ON);
    248 		ret = vp->kp->func(sp, vp);
    249 		if (strchr(O_STR(sp, O_IMKEY), vp->key))
    250 			sp->gp->scr_imctrl(sp, IMCTRL_OFF);
    251 		if (ret)
    252 			goto err;
    253 #endif
    254 #ifdef DEBUG
    255 		/* Make sure no function left the temporary space locked. */
    256 		if (F_ISSET(wp, W_TMP_INUSE)) {
    257 			F_CLR(wp, W_TMP_INUSE);
    258 			msgq(sp, M_ERR,
    259 			    "232|vi: temporary buffer not released");
    260 		}
    261 #endif
    262 		/*
    263 		 * If we're exiting this screen, move to the next one, or, if
    264 		 * there aren't any more, return to the main editor loop.  The
    265 		 * ordering is careful, don't discard the contents of sp until
    266 		 * the end.
    267 		 */
    268 		if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) {
    269 			if (file_end(sp, NULL, F_ISSET(sp, SC_EXIT_FORCE)))
    270 				goto ret;
    271 			if (vs_discard(sp, &next))
    272 				goto ret;
    273 			if (next == NULL && vs_swap(sp, &next, NULL))
    274 				goto ret;
    275 			*spp = next;
    276 			if (screen_end(sp))
    277 				goto ret;
    278 			if (next == NULL)
    279 				break;
    280 
    281 			/* Switch screens, change focus. */
    282 			sp = next;
    283 			vip = VIP(sp);
    284 			(void)sp->gp->scr_rename(sp, sp->frp->name, 1);
    285 
    286 			/* Don't trust the cursor. */
    287 			F_SET(vip, VIP_CUR_INVALID);
    288 
    289 			continue;
    290 		}
    291 
    292 		/*
    293 		 * Set the dot command structure.
    294 		 *
    295 		 * !!!
    296 		 * Historically, commands which used mapped keys did not
    297 		 * set the dot command, with the exception of the text
    298 		 * input commands.
    299 		 */
    300 		if (F_ISSET(vp, V_DOT) && !mapped) {
    301 			*DOT = cmd;
    302 			F_SET(DOT, VC_ISDOT);
    303 
    304 			/*
    305 			 * If a count was supplied for both the command and
    306 			 * its motion, the count was used only for the motion.
    307 			 * Turn the count back on for the dot structure.
    308 			 */
    309 			if (F_ISSET(vp, VC_C1RESET))
    310 				F_SET(DOT, VC_C1SET);
    311 
    312 			/* VM flags aren't retained. */
    313 			F_CLR(DOT, VM_COMMASK | VM_RCM_MASK);
    314 		}
    315 
    316 		/*
    317 		 * Some vi row movements are "attracted" to the last position
    318 		 * set, i.e. the VM_RCM commands are moths to the VM_RCM_SET
    319 		 * commands' candle.  If the movement is to the EOL the vi
    320 		 * command handles it.  If it's to the beginning, we handle it
    321 		 * here.
    322 		 *
    323 		 * Note, some commands (e.g. _, ^) don't set the VM_RCM_SETFNB
    324 		 * flag, but do the work themselves.  The reason is that they
    325 		 * have to modify the column in case they're being used as a
    326 		 * motion component.  Other similar commands (e.g. +, -) don't
    327 		 * have to modify the column because they are always line mode
    328 		 * operations when used as motions, so the column number isn't
    329 		 * of any interest.
    330 		 *
    331 		 * Does this totally violate the screen and editor layering?
    332 		 * You betcha.  As they say, if you think you understand it,
    333 		 * you don't.
    334 		 */
    335 		switch (F_ISSET(vp, VM_RCM_MASK)) {
    336 		case 0:
    337 		case VM_RCM_SET:
    338 			break;
    339 		case VM_RCM:
    340 			vp->m_final.cno = vs_rcm(sp,
    341 			    vp->m_final.lno, F_ISSET(vip, VIP_RCM_LAST));
    342 			break;
    343 		case VM_RCM_SETLAST:
    344 			F_SET(vip, VIP_RCM_LAST);
    345 			break;
    346 		case VM_RCM_SETFNB:
    347 			vp->m_final.cno = 0;
    348 			/* FALLTHROUGH */
    349 		case VM_RCM_SETNNB:
    350 			if (nonblank(sp, vp->m_final.lno, &vp->m_final.cno))
    351 				goto err;
    352 			break;
    353 		default:
    354 			abort();
    355 		}
    356 
    357 		/* Update the cursor. */
    358 		sp->lno = vp->m_final.lno;
    359 		sp->cno = vp->m_final.cno;
    360 
    361 		/*
    362 		 * Set the absolute mark -- set even if a tags or similar
    363 		 * command, since the tag may be moving to the same file.
    364 		 */
    365 		if ((F_ISSET(vp, V_ABS) ||
    366 		    (F_ISSET(vp, V_ABS_L) && sp->lno != abst.lno) ||
    367 		    (F_ISSET(vp, V_ABS_C) &&
    368 		    (sp->lno != abst.lno || sp->cno != abst.cno))) &&
    369 		    mark_set(sp, ABSMARK1, &abst, 1))
    370 			goto err;
    371 
    372 		if (0) {
    373 err:			if (v_event_flush(sp, CH_MAPPED))
    374 				msgq(sp, M_BERR,
    375 			    "110|Vi command failed: mapped keys discarded");
    376 		}
    377 
    378 		/*
    379 		 * Check and clear interrupts.  There's an obvious race, but
    380 		 * it's not worth fixing.
    381 		 */
    382 gc_err_noflush:	if (INTERRUPTED(sp)) {
    383 intr:			CLR_INTERRUPT(sp);
    384 			if (v_event_flush(sp, CH_MAPPED))
    385 				msgq(sp, M_ERR,
    386 				    "231|Interrupted: mapped keys discarded");
    387 			else
    388 				msgq(sp, M_ERR, "236|Interrupted");
    389 		}
    390 
    391 		/* If the last command switched screens, update. */
    392 		if (F_ISSET(sp, SC_SSWITCH)) {
    393 			F_CLR(sp, SC_SSWITCH);
    394 
    395 			/*
    396 			 * If the current screen is still displayed, it will
    397 			 * need a new status line.
    398 			 */
    399 			F_SET(sp, SC_STATUS);
    400 
    401 			/* Switch screens, change focus. */
    402 			sp = sp->nextdisp;
    403 			vip = VIP(sp);
    404 			(void)sp->gp->scr_rename(sp, sp->frp->name, 1);
    405 
    406 			/* Don't trust the cursor. */
    407 			F_SET(vip, VIP_CUR_INVALID);
    408 
    409 			/* Refresh so we can display messages. */
    410 			if (vs_refresh(sp, 1))
    411 				return (1);
    412 		}
    413 
    414 		/* If the last command switched files, change focus. */
    415 		if (F_ISSET(sp, SC_FSWITCH)) {
    416 			F_CLR(sp, SC_FSWITCH);
    417 			(void)sp->gp->scr_rename(sp, sp->frp->name, 1);
    418 		}
    419 
    420 		/* If leaving vi, return to the main editor loop. */
    421 		if (F_ISSET(gp, G_SRESTART) || F_ISSET(sp, SC_EX)) {
    422 			*spp = sp;
    423 			v_dtoh(sp);
    424 			gp->scr_discard(sp, NULL);
    425 			break;
    426 		}
    427 	}
    428 	if (0)
    429 ret:		rval = 1;
    430 	return (rval);
    431 }
    432 
    433 #define	KEY(key, ec_flags) {						\
    434 	if ((gcret = v_key(sp, vp, 0, ec_flags)) != GC_OK)		\
    435 		return (gcret);						\
    436 	if (vp->ev.e_value == K_ESCAPE)					\
    437 		goto esc;						\
    438 	if (FL_ISSET(vp->ev.e_flags, CH_MAPPED))			\
    439 		*mappedp = 1;						\
    440 	key = vp->ev.e_c;						\
    441 }
    442 
    443 /*
    444  * The O_TILDEOP option makes the ~ command take a motion instead
    445  * of a straight count.  This is the replacement structure we use
    446  * instead of the one currently in the VIKEYS table.
    447  *
    448  * XXX
    449  * This should probably be deleted -- it's not all that useful, and
    450  * we get help messages wrong.
    451  */
    452 VIKEYS const tmotion = {
    453 	v_mulcase,	V_CNT|V_DOT|V_MOTION|VM_RCM_SET,
    454 	"[count]~[count]motion",
    455 	" ~ change case to motion"
    456 };
    457 
    458 /*
    459  * v_cmd --
    460  *	Get a vi command.
    461  */
    462 static gcret_t
    463 v_cmd(SCR *sp, VICMD *dp, VICMD *vp, VICMD *ismotion, int *comcountp, int *mappedp)
    464 
    465 
    466 	                	/* Previous key if getting motion component. */
    467 
    468 {
    469 	enum { COMMANDMODE, ISPARTIAL, NOTPARTIAL } cpart;
    470 	ARG_CHAR_T key;
    471 	VIKEYS const *kp;
    472 	gcret_t gcret;
    473 	u_int flags;
    474 	const char *s;
    475 
    476 	/*
    477 	 * Get an event command or a key.  Event commands are simple, and
    478 	 * don't have any additional information.
    479 	 */
    480 	cpart = ismotion == NULL ? COMMANDMODE : ISPARTIAL;
    481 	gcret = v_key(sp, vp, 1, EC_MAPCOMMAND);
    482 	if (gcret != GC_OK) {
    483 		if (gcret != GC_EVENT)
    484 			return (gcret);
    485 		if (v_event(sp, vp))
    486 			return (GC_ERR);
    487 		if (ismotion != NULL && !F_ISSET(vp->kp, V_MOVE))
    488 			v_event_err(sp, &vp->ev);
    489 		return (GC_EVENT);
    490 	}
    491 
    492 	/*
    493 	 * Keys are not simple.  (Although vi's command structure less complex
    494 	 * than ex (and don't think I'm not grateful!)  The command syntax is:
    495 	 *
    496 	 *	[count] [buffer] [count] key [[motion] | [buffer] [character]]
    497 	 *
    498 	 * and there are, of course, several special cases.  The motion value
    499 	 * is itself a vi command, with the syntax:
    500 	 *
    501 	 *	[count] key [character]
    502 	 *
    503 	 * <escape> cancels partial commands, i.e. a command where at least
    504 	 * one non-numeric character has been entered.  Otherwise, it beeps
    505 	 * the terminal.
    506 	 *
    507 	 * !!!
    508 	 * POSIX 1003.2-1992 explicitly disallows cancelling commands where
    509 	 * all that's been entered is a number, requiring that the terminal
    510 	 * be alerted.
    511 	 */
    512 	if (vp->ev.e_value == K_ESCAPE)
    513 		goto esc;
    514 
    515 	/*
    516 	 * Commands that are mapped are treated differently (e.g., they
    517 	 * don't set the dot command.  Pass that information back.
    518 	 */
    519 	if (FL_ISSET(vp->ev.e_flags, CH_MAPPED))
    520 		*mappedp = 1;
    521 	key = vp->ev.e_c;
    522 
    523 	if (ismotion == NULL)
    524 		cpart = NOTPARTIAL;
    525 
    526 	/* Pick up an optional buffer. */
    527 	if (key == '"') {
    528 		cpart = ISPARTIAL;
    529 		if (ismotion != NULL) {
    530 			v_emsg(sp, NULL, VIM_COMBUF);
    531 			return (GC_ERR);
    532 		}
    533 		KEY(vp->buffer, 0);
    534 		F_SET(vp, VC_BUFFER);
    535 
    536 		KEY(key, EC_MAPCOMMAND);
    537 	}
    538 
    539 	/*
    540 	 * Pick up an optional count, where a leading 0 isn't a count, it's
    541 	 * a command.  When a count is specified, the dot command behaves
    542 	 * differently, pass the information back.
    543 	 */
    544 	if (ISDIGIT(key) && key != '0') {
    545 		if (v_count(sp, vp, key, &vp->count))
    546 			return (GC_ERR);
    547 
    548 		F_SET(vp, VC_C1SET);
    549 		*comcountp = 1;
    550 
    551 		KEY(key, EC_MAPCOMMAND);
    552 	} else
    553 		*comcountp = 0;
    554 
    555 	/* Pick up optional buffer. */
    556 	if (key == '"') {
    557 		cpart = ISPARTIAL;
    558 		if (F_ISSET(vp, VC_BUFFER)) {
    559 			msgq(sp, M_ERR, "234|Only one buffer may be specified");
    560 			return (GC_ERR);
    561 		}
    562 		if (ismotion != NULL) {
    563 			v_emsg(sp, NULL, VIM_COMBUF);
    564 			return (GC_ERR);
    565 		}
    566 		KEY(vp->buffer, 0);
    567 		F_SET(vp, VC_BUFFER);
    568 
    569 		KEY(key, EC_MAPCOMMAND);
    570 	}
    571 
    572 	/* Check for an OOB command key. */
    573 	cpart = ISPARTIAL;
    574 	if (key > MAXVIKEY) {
    575 		v_emsg(sp, (const char *)KEY_NAME(sp, key), VIM_NOCOM);
    576 		return (GC_ERR);
    577 	}
    578 	kp = &vikeys[vp->key = key];
    579 
    580 	/*
    581 	 * !!!
    582 	 * Historically, D accepted and then ignored a count.  Match it.
    583 	 */
    584 	if (vp->key == 'D' && F_ISSET(vp, VC_C1SET)) {
    585 		*comcountp = 0;
    586 		vp->count = 0;
    587 		F_CLR(vp, VC_C1SET);
    588 	}
    589 
    590 	/*
    591 	 * There are several commands that we implement as aliases, both
    592 	 * to match historic practice and to ensure consistency.  Check
    593 	 * for command aliases.
    594 	 */
    595 	if (kp->func == NULL && (kp = v_alias(sp, vp, kp)) == NULL)
    596 		return (GC_ERR);
    597 
    598 	/* The tildeop option makes the ~ command take a motion. */
    599 	if (key == '~' && O_ISSET(sp, O_TILDEOP))
    600 		kp = &tmotion;
    601 
    602 	vp->kp = kp;
    603 
    604 	/*
    605 	 * Find the command.  The only legal command with no underlying
    606 	 * function is dot.  It's historic practice that <escape> doesn't
    607 	 * just erase the preceding number, it beeps the terminal as well.
    608 	 * It's a common problem, so just beep the terminal unless verbose
    609 	 * was set.
    610 	 */
    611 	if (kp->func == NULL) {
    612 		if (key != '.') {
    613 			v_emsg(sp, (const char *)KEY_NAME(sp, key),
    614 			    vp->ev.e_value == K_ESCAPE ?
    615 			    VIM_NOCOM_B : VIM_NOCOM);
    616 			return (GC_ERR);
    617 		}
    618 
    619 		/* If called for a motion command, stop now. */
    620 		if (dp == NULL)
    621 			goto usage;
    622 
    623 		/*
    624 		 * !!!
    625 		 * If a '.' is immediately entered after an undo command, we
    626 		 * replay the log instead of redoing the last command.  This
    627 		 * is necessary because 'u' can't set the dot command -- see
    628 		 * vi/v_undo.c:v_undo for details.
    629 		 */
    630 		if (VIP(sp)->u_ccnt == sp->ccnt) {
    631 			vp->kp = &vikeys['u'];
    632 			F_SET(vp, VC_ISDOT);
    633 			return (GC_OK);
    634 		}
    635 
    636 		/* Otherwise, a repeatable command must have been executed. */
    637 		if (!F_ISSET(dp, VC_ISDOT)) {
    638 			msgq(sp, M_ERR, "208|No command to repeat");
    639 			return (GC_ERR);
    640 		}
    641 
    642 		/* Set new count/buffer, if any, and return. */
    643 		if (F_ISSET(vp, VC_C1SET)) {
    644 			F_SET(dp, VC_C1SET);
    645 			dp->count = vp->count;
    646 		}
    647 		if (F_ISSET(vp, VC_BUFFER))
    648 			dp->buffer = vp->buffer;
    649 
    650 		*vp = *dp;
    651 		return (GC_OK);
    652 	}
    653 
    654 	/* Set the flags based on the command flags. */
    655 	flags = kp->flags;
    656 
    657 	/* Check for illegal count. */
    658 	if (F_ISSET(vp, VC_C1SET) && !LF_ISSET(V_CNT))
    659 		goto usage;
    660 
    661 	/* Illegal motion command. */
    662 	if (ismotion == NULL) {
    663 		/* Illegal buffer. */
    664 		if (!LF_ISSET(V_OBUF) && F_ISSET(vp, VC_BUFFER))
    665 			goto usage;
    666 
    667 		/* Required buffer. */
    668 		if (LF_ISSET(V_RBUF)) {
    669 			KEY(vp->buffer, 0);
    670 			F_SET(vp, VC_BUFFER);
    671 		}
    672 	}
    673 
    674 	/*
    675 	 * Special case: '[', ']' and 'Z' commands.  Doesn't the fact that
    676 	 * the *single* characters don't mean anything but the *doubled*
    677 	 * characters do, just frost your shorts?
    678 	 */
    679 	if (vp->key == '[' || vp->key == ']' || vp->key == 'Z') {
    680 		/*
    681 		 * Historically, half entered [[, ]] or Z commands weren't
    682 		 * cancelled by <escape>, the terminal was beeped instead.
    683 		 * POSIX.2-1992 probably didn't notice, and requires that
    684 		 * they be cancelled instead of beeping.  Seems fine to me.
    685 		 *
    686 		 * Don't set the EC_MAPCOMMAND flag, apparently ] is a popular
    687 		 * vi meta-character, and we don't want the user to wait while
    688 		 * we time out a possible mapping.  This *appears* to match
    689 		 * historic vi practice, but with mapping characters, You Just
    690 		 * Never Know.
    691 		 */
    692 		KEY(key, 0);
    693 
    694 		if (vp->key != key) {
    695 usage:			if (ismotion == NULL)
    696 				s = kp->usage;
    697 			else if (ismotion->key == '~' && O_ISSET(sp, O_TILDEOP))
    698 				s = tmotion.usage;
    699 			else
    700 				s = vikeys[ismotion->key].usage;
    701 			v_emsg(sp, s, VIM_USAGE);
    702 			return (GC_ERR);
    703 		}
    704 	}
    705 	/* Special case: 'z' command. */
    706 	if (vp->key == 'z') {
    707 		KEY(vp->character, 0);
    708 		if (ISDIGIT(vp->character)) {
    709 			if (v_count(sp, vp, vp->character, &vp->count2))
    710 				return (GC_ERR);
    711 			F_SET(vp, VC_C2SET);
    712 			KEY(vp->character, 0);
    713 		}
    714 	}
    715 
    716 	/*
    717 	 * Commands that have motion components can be doubled to imply the
    718 	 * current line.
    719 	 */
    720 	if (ismotion != NULL && ismotion->key != key && !LF_ISSET(V_MOVE)) {
    721 		msgq(sp, M_ERR, "210|%s may not be used as a motion command",
    722 		    KEY_NAME(sp, key));
    723 		return (GC_ERR);
    724 	}
    725 
    726 	/* Pick up required trailing character. */
    727 	if (LF_ISSET(V_CHAR))
    728 #ifndef IMCTRL
    729 		KEY(vp->character, 0);
    730 #else
    731 	{
    732 		if (strchr(O_STR(sp, O_IMKEY), vp->key))
    733 			sp->gp->scr_imctrl(sp, IMCTRL_ON);
    734 		KEY(vp->character, 0);
    735 		if (strchr(O_STR(sp, O_IMKEY), vp->key))
    736 			sp->gp->scr_imctrl(sp, IMCTRL_OFF);
    737 	}
    738 #endif
    739 
    740 	/* Get any associated cursor word. */
    741 	if (F_ISSET(kp, V_KEYW) && v_curword(sp))
    742 		return (GC_ERR);
    743 
    744 	return (GC_OK);
    745 
    746 esc:	switch (cpart) {
    747 	case COMMANDMODE:
    748 		msgq(sp, M_BERR, "211|Already in command mode");
    749 		return (GC_ERR_NOFLUSH);
    750 	case ISPARTIAL:
    751 		break;
    752 	case NOTPARTIAL:
    753 		(void)sp->gp->scr_bell(sp);
    754 		break;
    755 	}
    756 	return (GC_ERR);
    757 }
    758 
    759 /*
    760  * v_motion --
    761  *
    762  * Get resulting motion mark.
    763  */
    764 static int
    765 v_motion(SCR *sp, VICMD *dm, VICMD *vp, int *mappedp)
    766 {
    767 	VICMD motion;
    768 	gcret_t gcret;
    769 	size_t len;
    770 	u_long cnt;
    771 	u_int flags;
    772 	int tilde_reset, notused;
    773 #ifdef IMKEY
    774 	int rval;
    775 #endif
    776 
    777 	/*
    778 	 * If '.' command, use the dot motion, else get the motion command.
    779 	 * Clear any line motion flags, the subsequent motion isn't always
    780 	 * the same, i.e. "/aaa" may or may not be a line motion.
    781 	 */
    782 	if (F_ISSET(vp, VC_ISDOT)) {
    783 		motion = *dm;
    784 		F_SET(&motion, VC_ISDOT);
    785 		F_CLR(&motion, VM_COMMASK);
    786 		gcret = GC_OK;
    787 	} else {
    788 		memset(&motion, 0, sizeof(VICMD));
    789 		gcret = v_cmd(sp, NULL, &motion, vp, &notused, mappedp);
    790 		if (gcret != GC_OK && gcret != GC_EVENT)
    791 			return (1);
    792 	}
    793 
    794 	/*
    795 	 * A count may be provided both to the command and to the motion, in
    796 	 * which case the count is multiplicative.  For example, "3y4y" is the
    797 	 * same as "12yy".  This count is provided to the motion command and
    798 	 * not to the regular function.
    799 	 */
    800 	cnt = motion.count = F_ISSET(&motion, VC_C1SET) ? motion.count : 1;
    801 	if (F_ISSET(vp, VC_C1SET)) {
    802 		motion.count *= vp->count;
    803 		F_SET(&motion, VC_C1SET);
    804 
    805 		/*
    806 		 * Set flags to restore the original values of the command
    807 		 * structure so dot commands can change the count values,
    808 		 * e.g. "2dw" "3." deletes a total of five words.
    809 		 */
    810 		F_CLR(vp, VC_C1SET);
    811 		F_SET(vp, VC_C1RESET);
    812 	}
    813 
    814 	/*
    815 	 * Some commands can be repeated to indicate the current line.  In
    816 	 * this case, or if the command is a "line command", set the flags
    817 	 * appropriately.  If not a doubled command, run the function to get
    818 	 * the resulting mark.
    819  	 */
    820 	if (gcret != GC_EVENT && vp->key == motion.key) {
    821 		F_SET(vp, VM_LDOUBLE | VM_LMODE);
    822 
    823 		/* Set the origin of the command. */
    824 		vp->m_start.lno = sp->lno;
    825 		vp->m_start.cno = 0;
    826 
    827 		/*
    828 		 * Set the end of the command.
    829 		 *
    830 		 * If the current line is missing, i.e. the file is empty,
    831 		 * historic vi permitted a "cc" or "!!" command to insert
    832 		 * text.
    833 		 */
    834 		vp->m_stop.lno = sp->lno + motion.count - 1;
    835 		if (db_get(sp, vp->m_stop.lno, 0, NULL, &len)) {
    836 			if (vp->m_stop.lno != 1 ||
    837 			   (vp->key != 'c' && vp->key != '!')) {
    838 				v_emsg(sp, NULL, VIM_EMPTY);
    839 				return (1);
    840 			}
    841 			vp->m_stop.cno = 0;
    842 		} else
    843 			vp->m_stop.cno = len ? len - 1 : 0;
    844 	} else {
    845 		/*
    846 		 * Motion commands change the underlying movement (*snarl*).
    847 		 * For example, "l" is illegal at the end of a line, but "dl"
    848 		 * is not.  Set flags so the function knows the situation.
    849 		 */
    850 		motion.rkp = vp->kp;
    851 
    852 		/*
    853 		 * XXX
    854 		 * Use yank instead of creating a new motion command, it's a
    855 		 * lot easier for now.
    856 		 */
    857 		if (vp->kp == &tmotion) {
    858 			tilde_reset = 1;
    859 			vp->kp = &vikeys['y'];
    860 		} else
    861 			tilde_reset = 0;
    862 
    863 		/*
    864 		 * Copy the key flags into the local structure, except for the
    865 		 * RCM flags -- the motion command will set the RCM flags in
    866 		 * the vp structure if necessary.  This means that the motion
    867 		 * command is expected to determine where the cursor ends up!
    868 		 * However, we save off the current RCM mask and restore it if
    869 		 * it no RCM flags are set by the motion command, with a small
    870 		 * modification.
    871 		 *
    872 		 * We replace the VM_RCM_SET flag with the VM_RCM flag.  This
    873 		 * is so that cursor movement doesn't set the relative position
    874 		 * unless the motion command explicitly specified it.  This
    875 		 * appears to match historic practice, but I've never been able
    876 		 * to develop a hard-and-fast rule.
    877 		 */
    878 		flags = F_ISSET(vp, VM_RCM_MASK);
    879 		if (LF_ISSET(VM_RCM_SET)) {
    880 			LF_SET(VM_RCM);
    881 			LF_CLR(VM_RCM_SET);
    882 		}
    883 		F_CLR(vp, VM_RCM_MASK);
    884 		F_SET(&motion, motion.kp->flags & ~VM_RCM_MASK);
    885 
    886 		/*
    887 		 * Set the three cursor locations to the current cursor.  This
    888 		 * permits commands like 'j' and 'k', that are line oriented
    889 		 * motions and have special cursor suck semantics when they are
    890 		 * used as standalone commands, to ignore column positioning.
    891 		 */
    892 		motion.m_final.lno =
    893 		    motion.m_stop.lno = motion.m_start.lno = sp->lno;
    894 		motion.m_final.cno =
    895 		    motion.m_stop.cno = motion.m_start.cno = sp->cno;
    896 
    897 		/* Run the function. */
    898 #ifndef IMKEY
    899 		if ((motion.kp->func)(sp, &motion))
    900 			return (1);
    901 #else
    902 		if (strchr(O_STR(sp, O_IMKEY), motion.key))
    903 			imreset(sp);
    904 		rval = (motion.kp->func)(sp, &motion);
    905 		if (strchr(O_STR(sp, O_IMKEY), motion.key))
    906 			imoff(sp);
    907 		if (rval)
    908 			return (1);
    909 #endif
    910 
    911 		/*
    912 		 * If the current line is missing, i.e. the file is empty,
    913 		 * historic vi allowed "c<motion>" or "!<motion>" to insert
    914 		 * text.  Otherwise fail -- most motion commands will have
    915 		 * already failed, but some, e.g. G, succeed in empty files.
    916 		 */
    917 		if (!db_exist(sp, vp->m_stop.lno)) {
    918 			if (vp->m_stop.lno != 1 ||
    919 			   (vp->key != 'c' && vp->key != '!')) {
    920 				v_emsg(sp, NULL, VIM_EMPTY);
    921 				return (1);
    922 			}
    923 			vp->m_stop.cno = 0;
    924 		}
    925 
    926 		/*
    927 		 * XXX
    928 		 * See above.
    929 		 */
    930 		if (tilde_reset)
    931 			vp->kp = &tmotion;
    932 
    933 		/*
    934 		 * Copy cut buffer, line mode and cursor position information
    935 		 * from the motion command structure, i.e. anything that the
    936 		 * motion command can set for us.  The commands can flag the
    937 		 * movement as a line motion (see v_sentence) as well as set
    938 		 * the VM_RCM_* flags explicitly.
    939 		 */
    940 		F_SET(vp, F_ISSET(&motion, VM_COMMASK | VM_RCM_MASK));
    941 
    942 		/*
    943 		 * If the motion command set no relative motion flags, use
    944 		 * the (slightly) modified previous values.
    945 		 */
    946 		if (!F_ISSET(vp, VM_RCM_MASK))
    947 			F_SET(vp, flags);
    948 
    949 		/*
    950 		 * Commands can change behaviors based on the motion command
    951 		 * used, for example, the ! command repeated the last bang
    952 		 * command if N or n was used as the motion.
    953 		 */
    954 		vp->rkp = motion.kp;
    955 
    956 		/*
    957 		 * Motion commands can reset all of the cursor information.
    958 		 * If the motion is in the reverse direction, switch the
    959 		 * from and to MARK's so that it's in a forward direction.
    960 		 * Motions are from the from MARK to the to MARK (inclusive).
    961 		 */
    962 		if (motion.m_start.lno > motion.m_stop.lno ||
    963 		    (motion.m_start.lno == motion.m_stop.lno &&
    964 		    motion.m_start.cno > motion.m_stop.cno)) {
    965 			vp->m_start = motion.m_stop;
    966 			vp->m_stop = motion.m_start;
    967 		} else {
    968 			vp->m_start = motion.m_start;
    969 			vp->m_stop = motion.m_stop;
    970 		}
    971 		vp->m_final = motion.m_final;
    972 	}
    973 
    974 	/*
    975 	 * If the command sets dot, save the motion structure.  The motion
    976 	 * count was changed above and needs to be reset, that's why this
    977 	 * is done here, and not in the calling routine.
    978 	 */
    979 	if (F_ISSET(vp->kp, V_DOT)) {
    980 		*dm = motion;
    981 		dm->count = cnt;
    982 	}
    983 	return (0);
    984 }
    985 
    986 /*
    987  * v_init --
    988  *	Initialize the vi screen.
    989  */
    990 static int
    991 v_init(SCR *sp)
    992 {
    993 	GS *gp;
    994 	VI_PRIVATE *vip;
    995 
    996 	gp = sp->gp;
    997 	vip = VIP(sp);
    998 
    999 	/* Switch into vi. */
   1000 	if (gp->scr_screen(sp, SC_VI))
   1001 		return (1);
   1002 	(void)gp->scr_attr(sp, SA_ALTERNATE, 1);
   1003 
   1004 	F_CLR(sp, SC_EX | SC_SCR_EX);
   1005 	F_SET(sp, SC_VI);
   1006 
   1007 	/*
   1008 	 * Initialize screen values.
   1009 	 *
   1010 	 * Small windows: see vs_refresh(), section 6a.
   1011 	 *
   1012 	 * Setup:
   1013 	 *	t_minrows is the minimum rows to display
   1014 	 *	t_maxrows is the maximum rows to display (rows - 1)
   1015 	 *	t_rows is the rows currently being displayed
   1016 	 */
   1017 	sp->rows = vip->srows = O_VAL(sp, O_LINES);
   1018 	sp->cols = O_VAL(sp, O_COLUMNS);
   1019 	sp->t_rows = sp->t_minrows = O_VAL(sp, O_WINDOW);
   1020 	if (sp->rows != 1) {
   1021 		if (sp->t_rows > sp->rows - 1) {
   1022 			sp->t_minrows = sp->t_rows = sp->rows - 1;
   1023 			msgq(sp, M_INFO,
   1024 			    "214|Windows option value is too large, max is %zu",
   1025 			    sp->t_rows);
   1026 		}
   1027 		sp->t_maxrows = sp->rows - 1;
   1028 	} else
   1029 		sp->t_maxrows = 1;
   1030 	sp->roff = sp->coff = 0;
   1031 
   1032 	/* Create a screen map. */
   1033 	CALLOC_RET(sp, HMAP, SMAP *, SIZE_HMAP(sp), sizeof(SMAP));
   1034 	TMAP = HMAP + (sp->t_rows - 1);
   1035 	HMAP->lno = sp->lno;
   1036 	HMAP->coff = 0;
   1037 	HMAP->soff = 1;
   1038 
   1039 	/*
   1040 	 * Fill the screen map from scratch -- try and center the line.  That
   1041 	 * way if we're starting with a file we've seen before, we'll put the
   1042 	 * line in the middle, otherwise, it won't work and we'll end up with
   1043 	 * the line at the top.
   1044 	 */
   1045 	F_CLR(sp, SC_SCR_TOP);
   1046 	F_SET(sp, SC_SCR_REFORMAT | SC_SCR_CENTER);
   1047 
   1048 	/* Invalidate the cursor. */
   1049 	F_SET(vip, VIP_CUR_INVALID);
   1050 
   1051 	/* Paint the screen image from scratch. */
   1052 	F_SET(vip, VIP_N_EX_PAINT);
   1053 
   1054 	return (0);
   1055 }
   1056 
   1057 /*
   1058  * v_dtoh --
   1059  *	Move all but the current screen to the hidden queue.
   1060  */
   1061 static void
   1062 v_dtoh(SCR *sp)
   1063 {
   1064 	GS *gp;
   1065 	SCR *tsp;
   1066 	WIN *wp;
   1067 	int hidden;
   1068 
   1069 	/* Move all screens to the hidden queue, tossing screen maps. */
   1070 	for (hidden = 0, gp = sp->gp, wp = sp->wp;
   1071 	    (tsp = TAILQ_FIRST(&wp->scrq)) != NULL; ++hidden) {
   1072 		if (_HMAP(tsp) != NULL) {
   1073 			free(_HMAP(tsp));
   1074 			_HMAP(tsp) = NULL;
   1075 		}
   1076 		TAILQ_REMOVE(&wp->scrq, tsp, q);
   1077 		TAILQ_INSERT_TAIL(&gp->hq, tsp, q);
   1078 		/* XXXX Change if hidden screens per window */
   1079 		tsp->wp = 0;
   1080 		gp->scr_discard(tsp, NULL);
   1081 	}
   1082 
   1083 	/* Move current screen back to the display queue. */
   1084 	TAILQ_REMOVE(&gp->hq, sp, q);
   1085 	TAILQ_INSERT_TAIL(&wp->scrq, sp, q);
   1086 	sp->wp = wp;
   1087 
   1088 	if (hidden > 1)
   1089 		msgq(sp, M_INFO,
   1090 		    "319|%d screens backgrounded; use :display to list them",
   1091 		    hidden - 1);
   1092 }
   1093 
   1094 /*
   1095  * v_curword --
   1096  *	Get the word (tagstring, actually) the cursor is on.
   1097  *
   1098  * PUBLIC: int v_curword __P((SCR *));
   1099  */
   1100 int
   1101 v_curword(SCR *sp)
   1102 {
   1103 	VI_PRIVATE *vip;
   1104 	size_t beg, end, len;
   1105 	int moved;
   1106 	CHAR_T *p;
   1107 
   1108 	if (db_get(sp, sp->lno, DBG_FATAL, &p, &len))
   1109 		return (1);
   1110 
   1111 	/*
   1112 	 * !!!
   1113 	 * Historically, tag commands skipped over any leading whitespace
   1114 	 * characters.  Make this true in general when using cursor words.
   1115 	 * If movement, getting a cursor word implies moving the cursor to
   1116 	 * its beginning.  Refresh now.
   1117 	 *
   1118 	 * !!!
   1119 	 * Find the beginning/end of the keyword.  Keywords are currently
   1120 	 * used for cursor-word searching and for tags.  Historical vi
   1121 	 * only used the word in a tag search from the cursor to the end
   1122 	 * of the word, i.e. if the cursor was on the 'b' in " abc ", the
   1123 	 * tag was "bc".  For consistency, we make cursor word searches
   1124 	 * follow the same rule.
   1125 	 */
   1126 	for (moved = 0,
   1127 	    beg = sp->cno; beg < len && ISSPACE((UCHAR_T)p[beg]); moved = 1, ++beg);
   1128 	if (beg >= len) {
   1129 		msgq(sp, M_BERR, "212|Cursor not in a word");
   1130 		return (1);
   1131 	}
   1132 	if (moved) {
   1133 		sp->cno = beg;
   1134 		(void)vs_refresh(sp, 0);
   1135 	}
   1136 
   1137 	/*
   1138 	 * Find the end of the word.
   1139 	 *
   1140 	 * !!!
   1141 	 * Historically, vi accepted any non-blank as initial character
   1142 	 * when building up a tagstring.  Required by IEEE 1003.1-2001.
   1143 	 */
   1144 	for (end = beg; ++end < len && inword(p[end]););
   1145 
   1146 	vip = VIP(sp);
   1147 	vip->klen = len = end - beg;
   1148 	BINC_RETW(sp, vip->keyw, vip->keywlen, len+1);
   1149 	MEMMOVEW(vip->keyw, p + beg, len);
   1150 	vip->keyw[len] = L('\0');				/* XXX */
   1151 	return (0);
   1152 }
   1153 
   1154 /*
   1155  * v_alias --
   1156  *	Check for a command alias.
   1157  */
   1158 static VIKEYS const *
   1159 v_alias(SCR *sp, VICMD *vp, const VIKEYS *kp)
   1160 {
   1161 	CHAR_T push;
   1162 
   1163 	switch (vp->key) {
   1164 	case 'C':			/* C -> c$ */
   1165 		push = '$';
   1166 		vp->key = 'c';
   1167 		break;
   1168 	case 'D':			/* D -> d$ */
   1169 		push = '$';
   1170 		vp->key = 'd';
   1171 		break;
   1172 	case 'S':			/* S -> c_ */
   1173 		push = '_';
   1174 		vp->key = 'c';
   1175 		break;
   1176 	case 'Y':			/* Y -> y_ */
   1177 		push = '_';
   1178 		vp->key = 'y';
   1179 		break;
   1180 	default:
   1181 		return (kp);
   1182 	}
   1183 	return (v_event_push(sp,
   1184 	    NULL, &push, 1, CH_NOMAP | CH_QUOTED) ? NULL : &vikeys[vp->key]);
   1185 }
   1186 
   1187 /*
   1188  * v_count --
   1189  *	Return the next count.
   1190  */
   1191 static int
   1192 v_count(SCR *sp, VICMD *vp, ARG_CHAR_T fkey, u_long *countp)
   1193 {
   1194 	u_long count, tc;
   1195 
   1196 	vp->ev.e_c = fkey;
   1197 	count = tc = 0;
   1198 	do {
   1199 		/*
   1200 		 * XXX
   1201 		 * Assume that overflow results in a smaller number.
   1202 		 */
   1203 		tc = count * 10 + vp->ev.e_c - '0';
   1204 		if (count > tc) {
   1205 			/* Toss to the next non-digit. */
   1206 			do {
   1207 				if (v_key(sp, vp, 0,
   1208 				    EC_MAPCOMMAND | EC_MAPNODIGIT) != GC_OK)
   1209 					return (1);
   1210 			} while (ISDIGIT(vp->ev.e_c));
   1211 			msgq(sp, M_ERR,
   1212 			    "235|Number larger than %lu", ULONG_MAX);
   1213 			return (1);
   1214 		}
   1215 		count = tc;
   1216 		if (v_key(sp, vp, 0, EC_MAPCOMMAND | EC_MAPNODIGIT) != GC_OK)
   1217 			return (1);
   1218 	} while (ISDIGIT(vp->ev.e_c));
   1219 	*countp = count;
   1220 	return (0);
   1221 }
   1222 
   1223 /*
   1224  * v_key --
   1225  *	Return the next event.
   1226  */
   1227 static gcret_t
   1228 v_key(SCR *sp, VICMD *vp, int events_ok, u_int32_t ec_flags)
   1229 {
   1230 	EVENT *evp;
   1231 	u_int32_t quote;
   1232 
   1233 	for (evp = &vp->ev, quote = 0;;) {
   1234 		if (v_event_get(sp, evp, 0, ec_flags | quote))
   1235 			return (GC_FATAL);
   1236 		quote = 0;
   1237 
   1238 		switch (evp->e_event) {
   1239 		case E_CHARACTER:
   1240 			/*
   1241 			 * !!!
   1242 			 * Historically, ^V was ignored in the command stream,
   1243 			 * although it had a useful side-effect of interrupting
   1244 			 * mappings.  Adding a quoting bit to the call probably
   1245 			 * extends historic practice, but it feels right.
   1246 			 */
   1247 			if (evp->e_value == K_VLNEXT) {
   1248 				quote = EC_QUOTED;
   1249 				break;
   1250 			}
   1251 			return (GC_OK);
   1252 		case E_ERR:
   1253 		case E_EOF:
   1254 			return (GC_FATAL);
   1255 		case E_INTERRUPT:
   1256 			/*
   1257 			 * !!!
   1258 			 * Historically, vi beeped on command level interrupts.
   1259 			 *
   1260 			 * Historically, vi exited to ex mode if no file was
   1261 			 * named on the command line, and two interrupts were
   1262 			 * generated in a row.  (I figured you might want to
   1263 			 * know that, just in case there's a quiz later.)
   1264 			 */
   1265 			(void)sp->gp->scr_bell(sp);
   1266 			return (GC_INTERRUPT);
   1267 		case E_REPAINT:
   1268 			if (v_erepaint(sp, evp))
   1269 				return (GC_FATAL);
   1270 			break;
   1271 		case E_WRESIZE:
   1272 			/*
   1273 			 * !!!
   1274 			 * We don't do anything here, just return an error.
   1275 			 * The vi loop will return because of this, and then
   1276 			 * the main loop will realize that we had to restart
   1277 			 * the world and will call the vi loop again.
   1278 			 */
   1279 			return (GC_ERR);
   1280 		case E_IPCOMMAND:
   1281 			if (events_ok)
   1282 				return (GC_EVENT);
   1283 			/* FALLTHROUGH */
   1284 		default:
   1285 			v_event_err(sp, evp);
   1286 			return (GC_ERR);
   1287 		}
   1288 	}
   1289 	/* NOTREACHED */
   1290 }
   1291 
   1292 #if defined(DEBUG) && defined(COMLOG)
   1293 /*
   1294  * v_comlog --
   1295  *	Log the contents of the command structure.
   1296  */
   1297 static void
   1298 v_comlog(sp, vp)
   1299 	SCR *sp;
   1300 	VICMD *vp;
   1301 {
   1302 	vtrace(sp, "vcmd: "WC, vp->key);
   1303 	if (F_ISSET(vp, VC_BUFFER))
   1304 		vtrace(sp, " buffer: "WC, vp->buffer);
   1305 	if (F_ISSET(vp, VC_C1SET))
   1306 		vtrace(sp, " c1: %lu", vp->count);
   1307 	if (F_ISSET(vp, VC_C2SET))
   1308 		vtrace(sp, " c2: %lu", vp->count2);
   1309 	vtrace(sp, " flags: 0x%x\n", vp->flags);
   1310 }
   1311 #endif
   1312