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