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