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