GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/vi/build/../vi/vi.c Lines: 0 394 0.0 %
Date: 2017-11-13 Branches: 0 418 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: vi.c,v 1.21 2017/04/18 01:45:35 deraadt 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
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
			(void)sp->gp->scr_rename(sp, sp->frp->name, 1);
399
		}
400
401
		/* If leaving vi, return to the main editor loop. */
402
		if (F_ISSET(gp, G_SRESTART) || F_ISSET(sp, SC_EX)) {
403
			*spp = sp;
404
			v_dtoh(sp);
405
			break;
406
		}
407
	}
408
	if (0)
409
ret:		rval = 1;
410
	return (rval);
411
}
412
413
#define	KEY(key, ec_flags) {						\
414
	if ((gcret = v_key(sp, 0, &ev, (ec_flags))) != GC_OK)		\
415
		return (gcret);						\
416
	if (ev.e_value == K_ESCAPE)					\
417
		goto esc;						\
418
	if (F_ISSET(&ev.e_ch, CH_MAPPED))				\
419
		*mappedp = 1;						\
420
	(key) = ev.e_c;							\
421
}
422
423
/*
424
 * The O_TILDEOP option makes the ~ command take a motion instead
425
 * of a straight count.  This is the replacement structure we use
426
 * instead of the one currently in the VIKEYS table.
427
 *
428
 * XXX
429
 * This should probably be deleted -- it's not all that useful, and
430
 * we get help messages wrong.
431
 */
432
VIKEYS const tmotion = {
433
	v_mulcase,	V_CNT|V_DOT|V_MOTION|VM_RCM_SET,
434
	"[count]~[count]motion",
435
	" ~ change case to motion"
436
};
437
438
/*
439
 * v_cmd --
440
 *
441
 * The command structure for vi is less complex than ex (and don't think
442
 * I'm not grateful!)  The command syntax is:
443
 *
444
 *	[count] [buffer] [count] key [[motion] | [buffer] [character]]
445
 *
446
 * and there are several special cases.  The motion value is itself a vi
447
 * command, with the syntax:
448
 *
449
 *	[count] key [character]
450
 */
451
static gcret_t
452
v_cmd(SCR *sp, VICMD *dp, VICMD *vp, VICMD *ismotion, int *comcountp,
453
    int *mappedp)
454
{
455
	enum { COMMANDMODE, ISPARTIAL, NOTPARTIAL } cpart;
456
	EVENT ev;
457
	VIKEYS const *kp;
458
	gcret_t gcret;
459
	u_int flags;
460
	CHAR_T key;
461
	char *s;
462
463
	/*
464
	 * Get a key.
465
	 *
466
	 * <escape> cancels partial commands, i.e. a command where at least
467
	 * one non-numeric character has been entered.  Otherwise, it beeps
468
	 * the terminal.
469
	 *
470
	 * !!!
471
	 * POSIX 1003.2-1992 explicitly disallows cancelling commands where
472
	 * all that's been entered is a number, requiring that the terminal
473
	 * be alerted.
474
	 */
475
	cpart = ismotion == NULL ? COMMANDMODE : ISPARTIAL;
476
	if ((gcret =
477
	    v_key(sp, ismotion == NULL, &ev, EC_MAPCOMMAND)) != GC_OK) {
478
		if (gcret == GC_EVENT)
479
			vp->ev = ev;
480
		return (gcret);
481
	}
482
	if (ev.e_value == K_ESCAPE)
483
		goto esc;
484
	if (F_ISSET(&ev.e_ch, CH_MAPPED))
485
		*mappedp = 1;
486
	key = ev.e_c;
487
488
	if (ismotion == NULL)
489
		cpart = NOTPARTIAL;
490
491
	/* Pick up optional buffer. */
492
	if (key == '"') {
493
		cpart = ISPARTIAL;
494
		if (ismotion != NULL) {
495
			v_emsg(sp, NULL, VIM_COMBUF);
496
			return (GC_ERR);
497
		}
498
		KEY(vp->buffer, 0);
499
		F_SET(vp, VC_BUFFER);
500
501
		KEY(key, EC_MAPCOMMAND);
502
	}
503
504
	/*
505
	 * Pick up optional count, where a leading 0 is not a count,
506
	 * it's a command.
507
	 */
508
	if (isdigit(key) && key != '0') {
509
		if (v_count(sp, key, &vp->count))
510
			return (GC_ERR);
511
		F_SET(vp, VC_C1SET);
512
		*comcountp = 1;
513
514
		KEY(key, EC_MAPCOMMAND);
515
	} else
516
		*comcountp = 0;
517
518
	/* Pick up optional buffer. */
519
	if (key == '"') {
520
		cpart = ISPARTIAL;
521
		if (F_ISSET(vp, VC_BUFFER)) {
522
			msgq(sp, M_ERR, "Only one buffer may be specified");
523
			return (GC_ERR);
524
		}
525
		if (ismotion != NULL) {
526
			v_emsg(sp, NULL, VIM_COMBUF);
527
			return (GC_ERR);
528
		}
529
		KEY(vp->buffer, 0);
530
		F_SET(vp, VC_BUFFER);
531
532
		KEY(key, EC_MAPCOMMAND);
533
	}
534
535
	/* Check for an OOB command key. */
536
	cpart = ISPARTIAL;
537
	if (key > MAXVIKEY) {
538
		v_emsg(sp, KEY_NAME(sp, key), VIM_NOCOM);
539
		return (GC_ERR);
540
	}
541
	kp = &vikeys[vp->key = key];
542
543
	/*
544
	 * !!!
545
	 * Historically, D accepted and then ignored a count.  Match it.
546
	 */
547
	if (vp->key == 'D' && F_ISSET(vp, VC_C1SET)) {
548
		*comcountp = 0;
549
		vp->count = 0;
550
		F_CLR(vp, VC_C1SET);
551
	}
552
553
	/* Check for command aliases. */
554
	if (kp->func == NULL && (kp = v_alias(sp, vp, kp)) == NULL)
555
		return (GC_ERR);
556
557
	/* The tildeop option makes the ~ command take a motion. */
558
	if (key == '~' && O_ISSET(sp, O_TILDEOP))
559
		kp = &tmotion;
560
561
	vp->kp = kp;
562
563
	/*
564
	 * Find the command.  The only legal command with no underlying
565
	 * function is dot.  It's historic practice that <escape> doesn't
566
	 * just erase the preceding number, it beeps the terminal as well.
567
	 * It's a common problem, so just beep the terminal unless verbose
568
	 * was set.
569
	 */
570
	if (kp->func == NULL) {
571
		if (key != '.') {
572
			v_emsg(sp, KEY_NAME(sp, key),
573
			    ev.e_value == K_ESCAPE ? VIM_NOCOM_B : VIM_NOCOM);
574
			return (GC_ERR);
575
		}
576
577
		/* If called for a motion command, stop now. */
578
		if (dp == NULL)
579
			goto usage;
580
581
		/*
582
		 * !!!
583
		 * If a '.' is immediately entered after an undo command, we
584
		 * replay the log instead of redoing the last command.  This
585
		 * is necessary because 'u' can't set the dot command -- see
586
		 * vi/v_undo.c:v_undo for details.
587
		 */
588
		if (VIP(sp)->u_ccnt == sp->ccnt) {
589
			vp->kp = &vikeys['u'];
590
			F_SET(vp, VC_ISDOT);
591
			return (GC_OK);
592
		}
593
594
		/* Otherwise, a repeatable command must have been executed. */
595
		if (!F_ISSET(dp, VC_ISDOT)) {
596
			msgq(sp, M_ERR, "No command to repeat");
597
			return (GC_ERR);
598
		}
599
600
		/* Set new count/buffer, if any, and return. */
601
		if (F_ISSET(vp, VC_C1SET)) {
602
			F_SET(dp, VC_C1SET);
603
			dp->count = vp->count;
604
		}
605
		if (F_ISSET(vp, VC_BUFFER))
606
			dp->buffer = vp->buffer;
607
608
		*vp = *dp;
609
		return (GC_OK);
610
	}
611
612
	/* Set the flags based on the command flags. */
613
	flags = kp->flags;
614
615
	/* Check for illegal count. */
616
	if (F_ISSET(vp, VC_C1SET) && !LF_ISSET(V_CNT))
617
		goto usage;
618
619
	/* Illegal motion command. */
620
	if (ismotion == NULL) {
621
		/* Illegal buffer. */
622
		if (!LF_ISSET(V_OBUF) && F_ISSET(vp, VC_BUFFER))
623
			goto usage;
624
625
		/* Required buffer. */
626
		if (LF_ISSET(V_RBUF)) {
627
			KEY(vp->buffer, 0);
628
			F_SET(vp, VC_BUFFER);
629
		}
630
	}
631
632
	/*
633
	 * Special case: '[', ']' and 'Z' commands.  Doesn't the fact that
634
	 * the *single* characters don't mean anything but the *doubled*
635
	 * characters do, just frost your shorts?
636
	 */
637
	if (vp->key == '[' || vp->key == ']' || vp->key == 'Z') {
638
		/*
639
		 * Historically, half entered [[, ]] or Z commands weren't
640
		 * cancelled by <escape>, the terminal was beeped instead.
641
		 * POSIX.2-1992 probably didn't notice, and requires that
642
		 * they be cancelled instead of beeping.  Seems fine to me.
643
		 *
644
		 * Don't set the EC_MAPCOMMAND flag, apparently ] is a popular
645
		 * vi meta-character, and we don't want the user to wait while
646
		 * we time out a possible mapping.  This *appears* to match
647
		 * historic vi practice, but with mapping characters, you Just
648
		 * Never Know.
649
		 */
650
		KEY(key, 0);
651
652
		if (vp->key != key) {
653
usage:			if (ismotion == NULL)
654
				s = kp->usage;
655
			else if (ismotion->key == '~' && O_ISSET(sp, O_TILDEOP))
656
				s = tmotion.usage;
657
			else
658
				s = vikeys[ismotion->key].usage;
659
			v_emsg(sp, s, VIM_USAGE);
660
			return (GC_ERR);
661
		}
662
	}
663
	/* Special case: 'z' command. */
664
	if (vp->key == 'z') {
665
		KEY(vp->character, 0);
666
		if (isdigit(vp->character)) {
667
			if (v_count(sp, vp->character, &vp->count2))
668
				return (GC_ERR);
669
			F_SET(vp, VC_C2SET);
670
			KEY(vp->character, 0);
671
		}
672
	}
673
674
	/*
675
	 * Commands that have motion components can be doubled to
676
	 * imply the current line.
677
	 */
678
	if (ismotion != NULL && ismotion->key != key && !LF_ISSET(V_MOVE)) {
679
		msgq(sp, M_ERR, "%s may not be used as a motion command",
680
		    KEY_NAME(sp, key));
681
		return (GC_ERR);
682
	}
683
684
	/* Required character. */
685
	if (LF_ISSET(V_CHAR))
686
		KEY(vp->character, 0);
687
688
	/* Get any associated cursor word. */
689
	if (F_ISSET(kp, V_KEYW) && v_keyword(sp))
690
		return (GC_ERR);
691
692
	return (GC_OK);
693
694
esc:	switch (cpart) {
695
	case COMMANDMODE:
696
		msgq(sp, M_BERR, "Already in command mode");
697
		return (GC_ERR_NOFLUSH);
698
	case ISPARTIAL:
699
		break;
700
	case NOTPARTIAL:
701
		(void)sp->gp->scr_bell(sp);
702
		break;
703
	}
704
	return (GC_ERR);
705
}
706
707
/*
708
 * v_motion --
709
 *
710
 * Get resulting motion mark.
711
 */
712
static int
713
v_motion(SCR *sp, VICMD *dm, VICMD *vp, int *mappedp)
714
{
715
	VICMD motion;
716
	size_t len;
717
	u_long cnt;
718
	u_int flags;
719
	int tilde_reset, notused;
720
721
	/*
722
	 * If '.' command, use the dot motion, else get the motion command.
723
	 * Clear any line motion flags, the subsequent motion isn't always
724
	 * the same, i.e. "/aaa" may or may not be a line motion.
725
	 */
726
	if (F_ISSET(vp, VC_ISDOT)) {
727
		motion = *dm;
728
		F_SET(&motion, VC_ISDOT);
729
		F_CLR(&motion, VM_COMMASK);
730
	} else {
731
		memset(&motion, 0, sizeof(VICMD));
732
		if (v_cmd(sp, NULL, &motion, vp, &notused, mappedp) != GC_OK)
733
			return (1);
734
	}
735
736
	/*
737
	 * A count may be provided both to the command and to the motion, in
738
	 * which case the count is multiplicative.  For example, "3y4y" is the
739
	 * same as "12yy".  This count is provided to the motion command and
740
	 * not to the regular function.
741
	 */
742
	cnt = motion.count = F_ISSET(&motion, VC_C1SET) ? motion.count : 1;
743
	if (F_ISSET(vp, VC_C1SET)) {
744
		motion.count *= vp->count;
745
		F_SET(&motion, VC_C1SET);
746
747
		/*
748
		 * Set flags to restore the original values of the command
749
		 * structure so dot commands can change the count values,
750
		 * e.g. "2dw" "3." deletes a total of five words.
751
		 */
752
		F_CLR(vp, VC_C1SET);
753
		F_SET(vp, VC_C1RESET);
754
	}
755
756
	/*
757
	 * Some commands can be repeated to indicate the current line.  In
758
	 * this case, or if the command is a "line command", set the flags
759
	 * appropriately.  If not a doubled command, run the function to get
760
	 * the resulting mark.
761
 	 */
762
	if (vp->key == motion.key) {
763
		F_SET(vp, VM_LDOUBLE | VM_LMODE);
764
765
		/* Set the origin of the command. */
766
		vp->m_start.lno = sp->lno;
767
		vp->m_start.cno = 0;
768
769
		/*
770
		 * Set the end of the command.
771
		 *
772
		 * If the current line is missing, i.e. the file is empty,
773
		 * historic vi permitted a "cc" or "!!" command to insert
774
		 * text.
775
		 */
776
		vp->m_stop.lno = sp->lno + motion.count - 1;
777
		if (db_get(sp, vp->m_stop.lno, 0, NULL, &len)) {
778
			if (vp->m_stop.lno != 1 ||
779
			    (vp->key != 'c' && vp->key != '!')) {
780
				v_emsg(sp, NULL, VIM_EMPTY);
781
				return (1);
782
			}
783
			vp->m_stop.cno = 0;
784
		} else
785
			vp->m_stop.cno = len ? len - 1 : 0;
786
	} else {
787
		/*
788
		 * Motion commands change the underlying movement (*snarl*).
789
		 * For example, "l" is illegal at the end of a line, but "dl"
790
		 * is not.  Set flags so the function knows the situation.
791
		 */
792
		motion.rkp = vp->kp;
793
794
		/*
795
		 * XXX
796
		 * Use yank instead of creating a new motion command, it's a
797
		 * lot easier for now.
798
		 */
799
		if (vp->kp == &tmotion) {
800
			tilde_reset = 1;
801
			vp->kp = &vikeys['y'];
802
		} else
803
			tilde_reset = 0;
804
805
		/*
806
		 * Copy the key flags into the local structure, except for the
807
		 * RCM flags -- the motion command will set the RCM flags in
808
		 * the vp structure if necessary.  This means that the motion
809
		 * command is expected to determine where the cursor ends up!
810
		 * However, we save off the current RCM mask and restore it if
811
		 * it no RCM flags are set by the motion command, with a small
812
		 * modification.
813
		 *
814
		 * We replace the VM_RCM_SET flag with the VM_RCM flag.  This
815
		 * is so that cursor movement doesn't set the relative position
816
		 * unless the motion command explicitly specified it.  This
817
		 * appears to match historic practice, but I've never been able
818
		 * to develop a hard-and-fast rule.
819
		 */
820
		flags = F_ISSET(vp, VM_RCM_MASK);
821
		if (LF_ISSET(VM_RCM_SET)) {
822
			LF_SET(VM_RCM);
823
			LF_CLR(VM_RCM_SET);
824
		}
825
		F_CLR(vp, VM_RCM_MASK);
826
		F_SET(&motion, motion.kp->flags & ~VM_RCM_MASK);
827
828
		/*
829
		 * Set the three cursor locations to the current cursor.  This
830
		 * permits commands like 'j' and 'k', that are line oriented
831
		 * motions and have special cursor suck semantics when they are
832
		 * used as standalone commands, to ignore column positioning.
833
		 */
834
		motion.m_final.lno =
835
		    motion.m_stop.lno = motion.m_start.lno = sp->lno;
836
		motion.m_final.cno =
837
		    motion.m_stop.cno = motion.m_start.cno = sp->cno;
838
839
		/* Run the function. */
840
		if ((motion.kp->func)(sp, &motion))
841
			return (1);
842
843
		/*
844
		 * If the current line is missing, i.e. the file is empty,
845
		 * historic vi allowed "c<motion>" or "!<motion>" to insert
846
		 * text.  Otherwise fail -- most motion commands will have
847
		 * already failed, but some, e.g. G, succeed in empty files.
848
		 */
849
		if (!db_exist(sp, vp->m_stop.lno)) {
850
			if (vp->m_stop.lno != 1 ||
851
			    (vp->key != 'c' && vp->key != '!')) {
852
				v_emsg(sp, NULL, VIM_EMPTY);
853
				return (1);
854
			}
855
			vp->m_stop.cno = 0;
856
		}
857
858
		/*
859
		 * XXX
860
		 * See above.
861
		 */
862
		if (tilde_reset)
863
			vp->kp = &tmotion;
864
865
		/*
866
		 * Copy cut buffer, line mode and cursor position information
867
		 * from the motion command structure, i.e. anything that the
868
		 * motion command can set for us.  The commands can flag the
869
		 * movement as a line motion (see v_sentence) as well as set
870
		 * the VM_RCM_* flags explicitly.
871
		 */
872
		F_SET(vp, F_ISSET(&motion, VM_COMMASK | VM_RCM_MASK));
873
874
		/*
875
		 * If the motion command set no relative motion flags, use
876
		 * the (slightly) modified previous values.
877
		 */
878
		if (!F_ISSET(vp, VM_RCM_MASK))
879
			F_SET(vp, flags);
880
881
		/*
882
		 * Commands can change behaviors based on the motion command
883
		 * used, for example, the ! command repeated the last bang
884
		 * command if N or n was used as the motion.
885
		 */
886
		vp->rkp = motion.kp;
887
888
		/*
889
		 * Motion commands can reset all of the cursor information.
890
		 * If the motion is in the reverse direction, switch the
891
		 * from and to MARK's so that it's in a forward direction.
892
		 * Motions are from the from MARK to the to MARK (inclusive).
893
		 */
894
		if (motion.m_start.lno > motion.m_stop.lno ||
895
		    (motion.m_start.lno == motion.m_stop.lno &&
896
		    motion.m_start.cno > motion.m_stop.cno)) {
897
			vp->m_start = motion.m_stop;
898
			vp->m_stop = motion.m_start;
899
		} else {
900
			vp->m_start = motion.m_start;
901
			vp->m_stop = motion.m_stop;
902
		}
903
		vp->m_final = motion.m_final;
904
	}
905
906
	/*
907
	 * If the command sets dot, save the motion structure.  The motion
908
	 * count was changed above and needs to be reset, that's why this
909
	 * is done here, and not in the calling routine.
910
	 */
911
	if (F_ISSET(vp->kp, V_DOT)) {
912
		*dm = motion;
913
		dm->count = cnt;
914
	}
915
	return (0);
916
}
917
918
/*
919
 * v_init --
920
 *	Initialize the vi screen.
921
 */
922
static int
923
v_init(SCR *sp)
924
{
925
	GS *gp;
926
	VI_PRIVATE *vip;
927
928
	gp = sp->gp;
929
	vip = VIP(sp);
930
931
	/* Switch into vi. */
932
	if (gp->scr_screen(sp, SC_VI))
933
		return (1);
934
	(void)gp->scr_attr(sp, SA_ALTERNATE, 1);
935
936
	F_CLR(sp, SC_EX | SC_SCR_EX);
937
	F_SET(sp, SC_VI);
938
939
	/*
940
	 * Initialize screen values.
941
	 *
942
	 * Small windows: see vs_refresh(), section 6a.
943
	 *
944
	 * Setup:
945
	 *	t_minrows is the minimum rows to display
946
	 *	t_maxrows is the maximum rows to display (rows - 1)
947
	 *	t_rows is the rows currently being displayed
948
	 */
949
	sp->rows = vip->srows = O_VAL(sp, O_LINES);
950
	sp->cols = O_VAL(sp, O_COLUMNS);
951
	sp->t_rows = sp->t_minrows = O_VAL(sp, O_WINDOW);
952
	if (sp->rows != 1) {
953
		if (sp->t_rows > sp->rows - 1) {
954
			sp->t_minrows = sp->t_rows = sp->rows - 1;
955
			msgq(sp, M_INFO,
956
			    "Windows option value is too large, max is %u",
957
			    sp->t_rows);
958
		}
959
		sp->t_maxrows = sp->rows - 1;
960
	} else
961
		sp->t_maxrows = 1;
962
	sp->woff = 0;
963
964
	/* Create a screen map. */
965
	CALLOC_RET(sp, HMAP, SIZE_HMAP(sp), sizeof(SMAP));
966
	TMAP = HMAP + (sp->t_rows - 1);
967
	HMAP->lno = sp->lno;
968
	HMAP->coff = 0;
969
	HMAP->soff = 1;
970
971
	/*
972
	 * Fill the screen map from scratch -- try and center the line.  That
973
	 * way if we're starting with a file we've seen before, we'll put the
974
	 * line in the middle, otherwise, it won't work and we'll end up with
975
	 * the line at the top.
976
	 */
977
	F_CLR(sp, SC_SCR_TOP);
978
	F_SET(sp, SC_SCR_REFORMAT | SC_SCR_CENTER);
979
980
	/* Invalidate the cursor. */
981
	F_SET(vip, VIP_CUR_INVALID);
982
983
	/* Paint the screen image from scratch. */
984
	F_SET(vip, VIP_N_EX_PAINT);
985
986
	return (0);
987
}
988
989
/*
990
 * v_dtoh --
991
 *	Move all but the current screen to the hidden queue.
992
 */
993
static void
994
v_dtoh(SCR *sp)
995
{
996
	GS *gp;
997
	SCR *tsp;
998
	int hidden;
999
1000
	/* Move all screens to the hidden queue, tossing screen maps. */
1001
	hidden = 0;
1002
	gp = sp->gp;
1003
	while ((tsp = TAILQ_FIRST(&gp->dq))) {
1004
		free(_HMAP(tsp));
1005
		_HMAP(tsp) = NULL;
1006
		TAILQ_REMOVE(&gp->dq, tsp, q);
1007
		TAILQ_INSERT_TAIL(&gp->hq, tsp, q);
1008
		++hidden;
1009
	}
1010
1011
	/* Move current screen back to the display queue. */
1012
	TAILQ_REMOVE(&gp->hq, sp, q);
1013
	TAILQ_INSERT_TAIL(&gp->dq, sp, q);
1014
1015
	/*
1016
	 * XXX
1017
	 * Don't bother internationalizing this message, it's going to
1018
	 * go away as soon as we have one-line screens.  --TK
1019
	 */
1020
	if (hidden > 1)
1021
		msgq(sp, M_INFO,
1022
		    "%d screens backgrounded; use :display to list them",
1023
		    hidden - 1);
1024
}
1025
1026
/*
1027
 * v_keyword --
1028
 *	Get the word (or non-word) the cursor is on.
1029
 */
1030
static int
1031
v_keyword(SCR *sp)
1032
{
1033
	VI_PRIVATE *vip;
1034
	size_t beg, end, len;
1035
	int moved, state;
1036
	char *p;
1037
1038
	if (db_get(sp, sp->lno, DBG_FATAL, &p, &len))
1039
		return (1);
1040
1041
	/*
1042
	 * !!!
1043
	 * Historically, tag commands skipped over any leading whitespace
1044
	 * characters.  Make this true in general when using cursor words.
1045
	 * If movement, getting a cursor word implies moving the cursor to
1046
	 * its beginning.  Refresh now.
1047
	 *
1048
	 * !!!
1049
	 * Find the beginning/end of the keyword.  Keywords are currently
1050
	 * used for cursor-word searching and for tags.  Historical vi
1051
	 * only used the word in a tag search from the cursor to the end
1052
	 * of the word, i.e. if the cursor was on the 'b' in " abc ", the
1053
	 * tag was "bc".  For consistency, we make cursor word searches
1054
	 * follow the same rule.
1055
	 */
1056
	for (moved = 0,
1057
	    beg = sp->cno; beg < len && isspace(p[beg]); moved = 1, ++beg);
1058
	if (beg >= len) {
1059
		msgq(sp, M_BERR, "Cursor not in a word");
1060
		return (1);
1061
	}
1062
	if (moved) {
1063
		sp->cno = beg;
1064
		(void)vs_refresh(sp, 0);
1065
	}
1066
1067
	/* Find the end of the word. */
1068
	for (state = inword(p[beg]),
1069
	    end = beg; ++end < len && state == inword(p[end]););
1070
1071
	vip = VIP(sp);
1072
	len = (end - beg);
1073
	BINC_RET(sp, vip->keyw, vip->klen, len);
1074
	memmove(vip->keyw, p + beg, len);
1075
	vip->keyw[len] = '\0';				/* XXX */
1076
	return (0);
1077
}
1078
1079
/*
1080
 * v_alias --
1081
 *	Check for a command alias.
1082
 */
1083
static VIKEYS const *
1084
v_alias(SCR *sp, VICMD *vp, VIKEYS const *kp)
1085
{
1086
	CHAR_T push;
1087
1088
	switch (vp->key) {
1089
	case 'C':			/* C -> c$ */
1090
		push = '$';
1091
		vp->key = 'c';
1092
		break;
1093
	case 'D':			/* D -> d$ */
1094
		push = '$';
1095
		vp->key = 'd';
1096
		break;
1097
	case 'S':			/* S -> c_ */
1098
		push = '_';
1099
		vp->key = 'c';
1100
		break;
1101
	case 'Y':			/* Y -> y_ */
1102
		push = '_';
1103
		vp->key = 'y';
1104
		break;
1105
	default:
1106
		return (kp);
1107
	}
1108
	return (v_event_push(sp,
1109
	    NULL, &push, 1, CH_NOMAP | CH_QUOTED) ? NULL : &vikeys[vp->key]);
1110
}
1111
1112
/*
1113
 * v_count --
1114
 *	Return the next count.
1115
 */
1116
static int
1117
v_count(SCR *sp, CHAR_T fkey, u_long *countp)
1118
{
1119
	EVENT ev;
1120
	u_long count, tc;
1121
1122
	ev.e_c = fkey;
1123
	count = tc = 0;
1124
	do {
1125
		/*
1126
		 * XXX
1127
		 * Assume that overflow results in a smaller number.
1128
		 */
1129
		tc = count * 10 + ev.e_c - '0';
1130
		if (count > tc) {
1131
			/* Toss to the next non-digit. */
1132
			do {
1133
				if (v_key(sp, 0, &ev,
1134
				    EC_MAPCOMMAND | EC_MAPNODIGIT) != GC_OK)
1135
					return (1);
1136
			} while (isdigit(ev.e_c));
1137
			msgq(sp, M_ERR,
1138
			    "Number larger than %lu", ULONG_MAX);
1139
			return (1);
1140
		}
1141
		count = tc;
1142
		if (v_key(sp, 0, &ev, EC_MAPCOMMAND | EC_MAPNODIGIT) != GC_OK)
1143
			return (1);
1144
	} while (isdigit(ev.e_c));
1145
	*countp = count;
1146
	return (0);
1147
}
1148
1149
/*
1150
 * v_key --
1151
 *	Return the next event.
1152
 */
1153
static gcret_t
1154
v_key(SCR *sp, int command_events, EVENT *evp, u_int32_t ec_flags)
1155
{
1156
	u_int32_t quote;
1157
1158
	for (quote = 0;;) {
1159
		if (v_event_get(sp, evp, 0, ec_flags | quote))
1160
			return (GC_FATAL);
1161
		quote = 0;
1162
1163
		switch (evp->e_event) {
1164
		case E_CHARACTER:
1165
			/*
1166
			 * !!!
1167
			 * Historically, ^V was ignored in the command stream,
1168
			 * although it had a useful side-effect of interrupting
1169
			 * mappings.  Adding a quoting bit to the call probably
1170
			 * extends historic practice, but it feels right.
1171
			 */
1172
			if (evp->e_value == K_VLNEXT) {
1173
				quote = EC_QUOTED;
1174
				break;
1175
			}
1176
			return (GC_OK);
1177
		case E_ERR:
1178
		case E_EOF:
1179
			return (GC_FATAL);
1180
		case E_INTERRUPT:
1181
			/*
1182
			 * !!!
1183
			 * Historically, vi beeped on command level interrupts.
1184
			 *
1185
			 * Historically, vi exited to ex mode if no file was
1186
			 * named on the command line, and two interrupts were
1187
			 * generated in a row.  (Just figured you might want
1188
			 * to know that.)
1189
			 */
1190
			(void)sp->gp->scr_bell(sp);
1191
			return (GC_INTERRUPT);
1192
		case E_REPAINT:
1193
			if (vs_repaint(sp, evp))
1194
				return (GC_FATAL);
1195
			break;
1196
		case E_WRESIZE:
1197
			return (GC_ERR);
1198
		case E_QUIT:
1199
		case E_WRITE:
1200
			if (command_events)
1201
				return (GC_EVENT);
1202
			/* FALLTHROUGH */
1203
		default:
1204
			v_event_err(sp, evp);
1205
			return (GC_ERR);
1206
		}
1207
	}
1208
	/* NOTREACHED */
1209
}
1210
1211
#if defined(DEBUG) && defined(COMLOG)
1212
/*
1213
 * v_comlog --
1214
 *	Log the contents of the command structure.
1215
 */
1216
static void
1217
v_comlog(SCR *sp, VICMD *vp)
1218
{
1219
	TRACE(sp, "vcmd: %c", vp->key);
1220
	if (F_ISSET(vp, VC_BUFFER))
1221
		TRACE(sp, " buffer: %c", vp->buffer);
1222
	if (F_ISSET(vp, VC_C1SET))
1223
		TRACE(sp, " c1: %lu", vp->count);
1224
	if (F_ISSET(vp, VC_C2SET))
1225
		TRACE(sp, " c2: %lu", vp->count2);
1226
	TRACE(sp, " flags: 0x%x\n", vp->flags);
1227
}
1228
#endif