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