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