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, ¬used, 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