1 /*-
2 * Copyright (c) 1992, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 1992, 1993, 1994, 1995, 1996
5 * Keith Bostic. All rights reserved.
6 *
7 * See the LICENSE file for redistribution information.
8 */
9
10 #include "config.h"
11
12 #include <sys/types.h>
13 #include <sys/queue.h>
14 #include <sys/time.h>
15
16 #include <bitstring.h>
17 #include <ctype.h>
18 #include <errno.h>
19 #include <limits.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24
25 #include "../common/common.h"
26 #include "vi.h"
27
28 typedef enum {
29 GC_ERR, GC_ERR_NOFLUSH, GC_EVENT, GC_FATAL, GC_INTERRUPT, GC_OK
30 } gcret_t;
31
32 static VIKEYS const
33 *v_alias(SCR *, VICMD *, VIKEYS const *);
34 static gcret_t v_cmd(SCR *, VICMD *, VICMD *, VICMD *, int *, int *);
35 static int v_count(SCR *, ARG_CHAR_T, u_long *);
36 static void v_dtoh(SCR *);
37 static int v_init(SCR *);
38 static gcret_t v_key(SCR *, int, EVENT *, u_int32_t);
39 static int v_motion(SCR *, VICMD *, VICMD *, int *);
40
41 #if defined(DEBUG) && defined(COMLOG)
42 static void v_comlog(SCR *, VICMD *);
43 #endif
44
45 /*
46 * Side-effect:
47 * The dot structure can be set by the underlying vi functions,
48 * see v_Put() and v_put().
49 */
50 #define DOT (&VIP(sp)->sdot)
51 #define DOTMOTION (&VIP(sp)->sdotmotion)
52
53 /*
54 * vi --
55 * Main vi command loop.
56 *
57 * PUBLIC: int vi(SCR **);
58 */
59 int
vi(SCR ** spp)60 vi(SCR **spp)
61 {
62 GS *gp;
63 MARK abs;
64 SCR *next, *sp;
65 VICMD cmd = { 0 }, *vp;
66 VI_PRIVATE *vip;
67 int comcount, mapped, rval;
68
69 /* Get the first screen. */
70 sp = *spp;
71 gp = sp->gp;
72
73 /* Point to the command structure. */
74 vp = &cmd;
75
76 /* Reset strange attraction. */
77 F_SET(vp, VM_RCM_SET);
78
79 /* Initialize the vi screen. */
80 if (v_init(sp))
81 return (1);
82
83 /* Set the focus. */
84 (void)sp->gp->scr_rename(sp, sp->frp->name, 1);
85
86 for (vip = VIP(sp), rval = 0;;) {
87 /* Resolve messages. */
88 if (!MAPPED_KEYS_WAITING(sp) && vs_resolve(sp, NULL, 0))
89 goto ret;
90
91 /*
92 * If not skipping a refresh, return to command mode and
93 * refresh the screen.
94 */
95 if (F_ISSET(vip, VIP_S_REFRESH))
96 F_CLR(vip, VIP_S_REFRESH);
97 else {
98 sp->showmode = SM_COMMAND;
99 if (vs_refresh(sp, 0))
100 goto ret;
101 }
102
103 /* Set the new favorite position. */
104 if (F_ISSET(vp, VM_RCM_SET | VM_RCM_SETFNB | VM_RCM_SETNNB)) {
105 F_CLR(vip, VIP_RCM_LAST);
106 (void)vs_column(sp, &sp->rcm);
107 }
108
109 /*
110 * If not currently in a map, log the cursor position,
111 * and set a flag so that this command can become the
112 * DOT command.
113 */
114 if (MAPPED_KEYS_WAITING(sp))
115 mapped = 1;
116 else {
117 if (log_cursor(sp))
118 goto err;
119 mapped = 0;
120 }
121
122 /*
123 * There may be an ex command waiting, and we returned here
124 * only because we exited a screen or file. In this case,
125 * we simply go back into the ex parser.
126 */
127 if (EXCMD_RUNNING(gp)) {
128 vp->kp = &vikeys[':'];
129 goto ex_continue;
130 }
131
132 /* Refresh the command structure. */
133 memset(vp, 0, sizeof(VICMD));
134
135 /*
136 * We get a command, which may or may not have an associated
137 * motion. If it does, we get it too, calling its underlying
138 * function to get the resulting mark. We then call the
139 * command setting the cursor to the resulting mark.
140 *
141 * !!!
142 * Vi historically flushed mapped characters on error, but
143 * entering extra <escape> characters at the beginning of
144 * a map wasn't considered an error -- in fact, users would
145 * put leading <escape> characters in maps to clean up vi
146 * state before the map was interpreted. Beauty!
147 */
148 switch (v_cmd(sp, DOT, vp, NULL, &comcount, &mapped)) {
149 case GC_ERR:
150 goto err;
151 case GC_ERR_NOFLUSH:
152 goto gc_err_noflush;
153 case GC_EVENT:
154 goto gc_event;
155 case GC_FATAL:
156 goto ret;
157 case GC_INTERRUPT:
158 goto intr;
159 case GC_OK:
160 break;
161 }
162
163 /* Check for security setting. */
164 if (F_ISSET(vp->kp, V_SECURE) && O_ISSET(sp, O_SECURE)) {
165 ex_emsg(sp, KEY_NAME(sp, vp->key), EXM_SECURE);
166 goto err;
167 }
168
169 /*
170 * Historical practice: if a dot command gets a new count,
171 * any motion component goes away, i.e. "d3w2." deletes a
172 * total of 5 words.
173 */
174 if (F_ISSET(vp, VC_ISDOT) && comcount)
175 DOTMOTION->count = 1;
176
177 /* Copy the key flags into the local structure. */
178 F_SET(vp, vp->kp->flags);
179
180 /* Prepare to set the previous context. */
181 if (F_ISSET(vp, V_ABS | V_ABS_C | V_ABS_L)) {
182 abs.lno = sp->lno;
183 abs.cno = sp->cno;
184 }
185
186 /*
187 * Set the three cursor locations to the current cursor. The
188 * underlying routines don't bother if the cursor doesn't move.
189 * This also handles line commands (e.g. Y) defaulting to the
190 * current line.
191 */
192 vp->m_start.lno = vp->m_stop.lno = vp->m_final.lno = sp->lno;
193 vp->m_start.cno = vp->m_stop.cno = vp->m_final.cno = sp->cno;
194
195 /*
196 * Do any required motion; v_motion sets the from MARK and the
197 * line mode flag, as well as the VM_RCM flags.
198 */
199 if (F_ISSET(vp, V_MOTION) &&
200 v_motion(sp, DOTMOTION, vp, &mapped)) {
201 if (INTERRUPTED(sp))
202 goto intr;
203 goto err;
204 }
205
206 /*
207 * If a count is set and the command is line oriented, set the
208 * to MARK here relative to the cursor/from MARK. This is for
209 * commands that take both counts and motions, i.e. "4yy" and
210 * "y%". As there's no way the command can know which the user
211 * did, we have to do it here. (There are commands that are
212 * line oriented and that take counts ("#G", "#H"), for which
213 * this calculation is either completely meaningless or wrong.
214 * Each command must validate the value for itself.
215 */
216 if (F_ISSET(vp, VC_C1SET) && F_ISSET(vp, VM_LMODE))
217 vp->m_stop.lno += vp->count - 1;
218
219 /* Increment the command count. */
220 ++sp->ccnt;
221
222 #if defined(DEBUG) && defined(COMLOG)
223 v_comlog(sp, vp);
224 #endif
225 /* Call the function. */
226 ex_continue: if (vp->kp->func(sp, vp))
227 goto err;
228 gc_event:
229 #ifdef DEBUG
230 /* Make sure no function left the temporary space locked. */
231 if (F_ISSET(gp, G_TMP_INUSE)) {
232 F_CLR(gp, G_TMP_INUSE);
233 msgq(sp, M_ERR,
234 "232|vi: temporary buffer not released");
235 }
236 #endif
237 /*
238 * If we're exiting this screen, move to the next one, or, if
239 * there aren't any more, return to the main editor loop. The
240 * ordering is careful, don't discard the contents of sp until
241 * the end.
242 */
243 if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) {
244 if (file_end(sp, NULL, F_ISSET(sp, SC_EXIT_FORCE)))
245 goto ret;
246 if (vs_discard(sp, &next))
247 goto ret;
248 if (next == NULL && vs_swap(sp, &next, NULL))
249 goto ret;
250 *spp = next;
251 if (screen_end(sp))
252 goto ret;
253 if (next == NULL)
254 break;
255
256 /* Switch screens, change focus. */
257 sp = next;
258 vip = VIP(sp);
259 (void)sp->gp->scr_rename(sp, sp->frp->name, 1);
260
261 /* Don't trust the cursor. */
262 F_SET(vip, VIP_CUR_INVALID);
263
264 continue;
265 }
266
267 /*
268 * Set the dot command structure.
269 *
270 * !!!
271 * Historically, commands which used mapped keys did not
272 * set the dot command, with the exception of the text
273 * input commands.
274 */
275 if (F_ISSET(vp, V_DOT) && !mapped) {
276 *DOT = cmd;
277 F_SET(DOT, VC_ISDOT);
278
279 /*
280 * If a count was supplied for both the command and
281 * its motion, the count was used only for the motion.
282 * Turn the count back on for the dot structure.
283 */
284 if (F_ISSET(vp, VC_C1RESET))
285 F_SET(DOT, VC_C1SET);
286
287 /* VM flags aren't retained. */
288 F_CLR(DOT, VM_COMMASK | VM_RCM_MASK);
289 }
290
291 /*
292 * Some vi row movements are "attracted" to the last position
293 * set, i.e. the VM_RCM commands are moths to the VM_RCM_SET
294 * commands' candle. If the movement is to the EOL the vi
295 * command handles it. If it's to the beginning, we handle it
296 * here.
297 *
298 * Note, some commands (e.g. _, ^) don't set the VM_RCM_SETFNB
299 * flag, but do the work themselves. The reason is that they
300 * have to modify the column in case they're being used as a
301 * motion component. Other similar commands (e.g. +, -) don't
302 * have to modify the column because they are always line mode
303 * operations when used as motions, so the column number isn't
304 * of any interest.
305 *
306 * Does this totally violate the screen and editor layering?
307 * You betcha. As they say, if you think you understand it,
308 * you don't.
309 */
310 switch (F_ISSET(vp, VM_RCM_MASK)) {
311 case 0:
312 case VM_RCM_SET:
313 break;
314 case VM_RCM:
315 vp->m_final.cno = vs_rcm(sp,
316 vp->m_final.lno, F_ISSET(vip, VIP_RCM_LAST));
317 break;
318 case VM_RCM_SETLAST:
319 F_SET(vip, VIP_RCM_LAST);
320 break;
321 case VM_RCM_SETFNB:
322 vp->m_final.cno = 0;
323 /* FALLTHROUGH */
324 case VM_RCM_SETNNB:
325 if (nonblank(sp, vp->m_final.lno, &vp->m_final.cno))
326 goto err;
327 break;
328 default:
329 abort();
330 }
331
332 /* Update the cursor. */
333 sp->lno = vp->m_final.lno;
334 sp->cno = vp->m_final.cno;
335
336 /*
337 * Set the absolute mark -- set even if a tags or similar
338 * command, since the tag may be moving to the same file.
339 */
340 if ((F_ISSET(vp, V_ABS) ||
341 (F_ISSET(vp, V_ABS_L) && sp->lno != abs.lno) ||
342 (F_ISSET(vp, V_ABS_C) &&
343 (sp->lno != abs.lno || sp->cno != abs.cno))) &&
344 mark_set(sp, ABSMARK1, &abs, 1))
345 goto err;
346
347 if (0) {
348 err: if (v_event_flush(sp, CH_MAPPED))
349 msgq(sp, M_BERR,
350 "110|Vi command failed: mapped keys discarded");
351 }
352
353 /*
354 * Check and clear interrupts. There's an obvious race, but
355 * it's not worth fixing.
356 */
357 gc_err_noflush: if (INTERRUPTED(sp)) {
358 intr: CLR_INTERRUPT(sp);
359 if (v_event_flush(sp, CH_MAPPED))
360 msgq(sp, M_ERR,
361 "231|Interrupted: mapped keys discarded");
362 else
363 msgq(sp, M_ERR, "236|Interrupted");
364 }
365
366 /* If the last command switched screens, update. */
367 if (F_ISSET(sp, SC_SSWITCH)) {
368 F_CLR(sp, SC_SSWITCH);
369
370 /*
371 * If the current screen is still displayed, it will
372 * need a new status line.
373 */
374 F_SET(sp, SC_STATUS);
375
376 /* Switch screens, change focus. */
377 sp = sp->nextdisp;
378 vip = VIP(sp);
379 (void)sp->gp->scr_rename(sp, sp->frp->name, 1);
380
381 /* Don't trust the cursor. */
382 F_SET(vip, VIP_CUR_INVALID);
383
384 /* Refresh so we can display messages. */
385 if (vs_refresh(sp, 1))
386 return (1);
387 }
388
389 /* If the last command switched files, change focus. */
390 if (F_ISSET(sp, SC_FSWITCH)) {
391 F_CLR(sp, SC_FSWITCH);
392 (void)sp->gp->scr_rename(sp, sp->frp->name, 1);
393 }
394
395 /* If leaving vi, return to the main editor loop. */
396 if (F_ISSET(gp, G_SRESTART) || F_ISSET(sp, SC_EX)) {
397 *spp = sp;
398 v_dtoh(sp);
399 gp->scr_discard(sp, NULL);
400 break;
401 }
402 }
403 if (0)
404 ret: rval = 1;
405 return (rval);
406 }
407
408 #define KEY(key, ec_flags) do { \
409 if ((gcret = v_key(sp, 0, &ev, ec_flags)) != GC_OK) \
410 return (gcret); \
411 if (ev.e_value == K_ESCAPE) \
412 goto esc; \
413 if (F_ISSET(&ev.e_ch, CH_MAPPED)) \
414 *mappedp = 1; \
415 key = ev.e_c; \
416 } while (0)
417
418 /*
419 * The O_TILDEOP option makes the ~ command take a motion instead
420 * of a straight count. This is the replacement structure we use
421 * instead of the one currently in the VIKEYS table.
422 *
423 * XXX
424 * This should probably be deleted -- it's not all that useful, and
425 * we get help messages wrong.
426 */
427 VIKEYS const tmotion = {
428 v_mulcase, V_CNT|V_DOT|V_MOTION|VM_RCM_SET,
429 "[count]~[count]motion",
430 " ~ change case to motion"
431 };
432
433 /*
434 * v_cmd --
435 *
436 * The command structure for vi is less complex than ex (and don't think
437 * I'm not grateful!) The command syntax is:
438 *
439 * [count] [buffer] [count] key [[motion] | [buffer] [character]]
440 *
441 * and there are several special cases. The motion value is itself a vi
442 * command, with the syntax:
443 *
444 * [count] key [character]
445 */
446 static gcret_t
v_cmd(SCR * sp,VICMD * dp,VICMD * vp,VICMD * ismotion,int * comcountp,int * mappedp)447 v_cmd(
448 SCR *sp,
449 VICMD *dp,
450 VICMD *vp,
451 VICMD *ismotion, /* Previous key if getting motion component. */
452 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 an 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 an 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, "234|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, "208|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 imply the
676 * current line.
677 */
678 if (ismotion != NULL && ismotion->key != key && !LF_ISSET(V_MOVE)) {
679 msgq(sp, M_ERR, "210|%s may not be used as a motion command",
680 KEY_NAME(sp, key));
681 return (GC_ERR);
682 }
683
684 /* Pick up required trailing 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_curword(sp))
690 return (GC_ERR);
691
692 return (GC_OK);
693
694 esc: switch (cpart) {
695 case COMMANDMODE:
696 msgq(sp, M_BERR, "211|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
v_motion(SCR * sp,VICMD * dm,VICMD * vp,int * mappedp)713 v_motion(
714 SCR *sp,
715 VICMD *dm,
716 VICMD *vp,
717 int *mappedp)
718 {
719 VICMD motion;
720 size_t len;
721 u_long cnt;
722 u_int flags;
723 int tilde_reset, notused;
724
725 /*
726 * If '.' command, use the dot motion, else get the motion command.
727 * Clear any line motion flags, the subsequent motion isn't always
728 * the same, i.e. "/aaa" may or may not be a line motion.
729 */
730 if (F_ISSET(vp, VC_ISDOT)) {
731 motion = *dm;
732 F_SET(&motion, VC_ISDOT);
733 F_CLR(&motion, VM_COMMASK);
734 } else {
735 memset(&motion, 0, sizeof(VICMD));
736 if (v_cmd(sp, NULL, &motion, vp, ¬used, mappedp) != GC_OK)
737 return (1);
738 }
739
740 /*
741 * A count may be provided both to the command and to the motion, in
742 * which case the count is multiplicative. For example, "3y4y" is the
743 * same as "12yy". This count is provided to the motion command and
744 * not to the regular function.
745 */
746 cnt = motion.count = F_ISSET(&motion, VC_C1SET) ? motion.count : 1;
747 if (F_ISSET(vp, VC_C1SET)) {
748 motion.count *= vp->count;
749 F_SET(&motion, VC_C1SET);
750
751 /*
752 * Set flags to restore the original values of the command
753 * structure so dot commands can change the count values,
754 * e.g. "2dw" "3." deletes a total of five words.
755 */
756 F_CLR(vp, VC_C1SET);
757 F_SET(vp, VC_C1RESET);
758 }
759
760 /*
761 * Some commands can be repeated to indicate the current line. In
762 * this case, or if the command is a "line command", set the flags
763 * appropriately. If not a doubled command, run the function to get
764 * the resulting mark.
765 */
766 if (vp->key == motion.key) {
767 F_SET(vp, VM_LDOUBLE | VM_LMODE);
768
769 /* Set the origin of the command. */
770 vp->m_start.lno = sp->lno;
771 vp->m_start.cno = 0;
772
773 /*
774 * Set the end of the command.
775 *
776 * If the current line is missing, i.e. the file is empty,
777 * historic vi permitted a "cc" or "!!" command to insert
778 * text.
779 */
780 vp->m_stop.lno = sp->lno + motion.count - 1;
781 if (db_get(sp, vp->m_stop.lno, 0, NULL, &len)) {
782 if (vp->m_stop.lno != 1 ||
783 (vp->key != 'c' && vp->key != '!')) {
784 v_emsg(sp, NULL, VIM_EMPTY);
785 return (1);
786 }
787 vp->m_stop.cno = 0;
788 } else
789 vp->m_stop.cno = len ? len - 1 : 0;
790 } else {
791 /*
792 * Motion commands change the underlying movement (*snarl*).
793 * For example, "l" is illegal at the end of a line, but "dl"
794 * is not. Set flags so the function knows the situation.
795 */
796 motion.rkp = vp->kp;
797
798 /*
799 * XXX
800 * Use yank instead of creating a new motion command, it's a
801 * lot easier for now.
802 */
803 if (vp->kp == &tmotion) {
804 tilde_reset = 1;
805 vp->kp = &vikeys['y'];
806 } else
807 tilde_reset = 0;
808
809 /*
810 * Copy the key flags into the local structure, except for the
811 * RCM flags -- the motion command will set the RCM flags in
812 * the vp structure if necessary. This means that the motion
813 * command is expected to determine where the cursor ends up!
814 * However, we save off the current RCM mask and restore it if
815 * it no RCM flags are set by the motion command, with a small
816 * modification.
817 *
818 * We replace the VM_RCM_SET flag with the VM_RCM flag. This
819 * is so that cursor movement doesn't set the relative position
820 * unless the motion command explicitly specified it. This
821 * appears to match historic practice, but I've never been able
822 * to develop a hard-and-fast rule.
823 */
824 flags = F_ISSET(vp, VM_RCM_MASK);
825 if (LF_ISSET(VM_RCM_SET)) {
826 LF_SET(VM_RCM);
827 LF_CLR(VM_RCM_SET);
828 }
829 F_CLR(vp, VM_RCM_MASK);
830 F_SET(&motion, motion.kp->flags & ~VM_RCM_MASK);
831
832 /*
833 * Set the three cursor locations to the current cursor. This
834 * permits commands like 'j' and 'k', that are line oriented
835 * motions and have special cursor suck semantics when they are
836 * used as standalone commands, to ignore column positioning.
837 */
838 motion.m_final.lno =
839 motion.m_stop.lno = motion.m_start.lno = sp->lno;
840 motion.m_final.cno =
841 motion.m_stop.cno = motion.m_start.cno = sp->cno;
842
843 /* Run the function. */
844 if ((motion.kp->func)(sp, &motion))
845 return (1);
846
847 /*
848 * If the current line is missing, i.e. the file is empty,
849 * historic vi allowed "c<motion>" or "!<motion>" to insert
850 * text. Otherwise fail -- most motion commands will have
851 * already failed, but some, e.g. G, succeed in empty files.
852 */
853 if (!db_exist(sp, vp->m_stop.lno)) {
854 if (vp->m_stop.lno != 1 ||
855 (vp->key != 'c' && vp->key != '!')) {
856 v_emsg(sp, NULL, VIM_EMPTY);
857 return (1);
858 }
859 vp->m_stop.cno = 0;
860 }
861
862 /*
863 * XXX
864 * See above.
865 */
866 if (tilde_reset)
867 vp->kp = &tmotion;
868
869 /*
870 * Copy cut buffer, line mode and cursor position information
871 * from the motion command structure, i.e. anything that the
872 * motion command can set for us. The commands can flag the
873 * movement as a line motion (see v_sentence) as well as set
874 * the VM_RCM_* flags explicitly.
875 */
876 F_SET(vp, F_ISSET(&motion, VM_COMMASK | VM_RCM_MASK));
877
878 /*
879 * If the motion command set no relative motion flags, use
880 * the (slightly) modified previous values.
881 */
882 if (!F_ISSET(vp, VM_RCM_MASK))
883 F_SET(vp, flags);
884
885 /*
886 * Commands can change behaviors based on the motion command
887 * used, for example, the ! command repeated the last bang
888 * command if N or n was used as the motion.
889 */
890 vp->rkp = motion.kp;
891
892 /*
893 * Motion commands can reset all of the cursor information.
894 * If the motion is in the reverse direction, switch the
895 * from and to MARK's so that it's in a forward direction.
896 * Motions are from the from MARK to the to MARK (inclusive).
897 */
898 if (motion.m_start.lno > motion.m_stop.lno ||
899 (motion.m_start.lno == motion.m_stop.lno &&
900 motion.m_start.cno > motion.m_stop.cno)) {
901 vp->m_start = motion.m_stop;
902 vp->m_stop = motion.m_start;
903 } else {
904 vp->m_start = motion.m_start;
905 vp->m_stop = motion.m_stop;
906 }
907 vp->m_final = motion.m_final;
908 }
909
910 /*
911 * If the command sets dot, save the motion structure. The motion
912 * count was changed above and needs to be reset, that's why this
913 * is done here, and not in the calling routine.
914 */
915 if (F_ISSET(vp->kp, V_DOT)) {
916 *dm = motion;
917 dm->count = cnt;
918 }
919 return (0);
920 }
921
922 /*
923 * v_init --
924 * Initialize the vi screen.
925 */
926 static int
v_init(SCR * sp)927 v_init(SCR *sp)
928 {
929 GS *gp;
930 VI_PRIVATE *vip;
931
932 gp = sp->gp;
933 vip = VIP(sp);
934
935 /* Switch into vi. */
936 if (gp->scr_screen(sp, SC_VI))
937 return (1);
938 (void)gp->scr_attr(sp, SA_ALTERNATE, 1);
939
940 F_CLR(sp, SC_EX | SC_SCR_EX);
941 F_SET(sp, SC_VI);
942
943 /*
944 * Initialize screen values.
945 *
946 * Small windows: see vs_refresh(), section 6a.
947 *
948 * Setup:
949 * t_minrows is the minimum rows to display
950 * t_maxrows is the maximum rows to display (rows - 1)
951 * t_rows is the rows currently being displayed
952 */
953 sp->rows = vip->srows = O_VAL(sp, O_LINES);
954 sp->cols = O_VAL(sp, O_COLUMNS);
955 sp->t_rows = sp->t_minrows = O_VAL(sp, O_WINDOW);
956 if (sp->rows != 1) {
957 if (sp->t_rows > sp->rows - 1) {
958 sp->t_minrows = sp->t_rows = sp->rows - 1;
959 msgq(sp, M_INFO,
960 "214|Windows option value is too large, max is %u",
961 (u_int)sp->t_rows);
962 }
963 sp->t_maxrows = sp->rows - 1;
964 } else
965 sp->t_maxrows = 1;
966 sp->roff = sp->coff = 0;
967
968 /* Create a screen map. */
969 CALLOC_RET(sp, HMAP, SIZE_HMAP(sp), sizeof(SMAP));
970 TMAP = HMAP + (sp->t_rows - 1);
971 HMAP->lno = sp->lno;
972 HMAP->coff = 0;
973 HMAP->soff = 1;
974
975 /*
976 * Fill the screen map from scratch -- try and center the line. That
977 * way if we're starting with a file we've seen before, we'll put the
978 * line in the middle, otherwise, it won't work and we'll end up with
979 * the line at the top.
980 */
981 F_SET(sp, SC_SCR_REFORMAT | SC_SCR_CENTER);
982
983 /* Invalidate the cursor. */
984 F_SET(vip, VIP_CUR_INVALID);
985
986 /* Paint the screen image from scratch. */
987 F_SET(vip, VIP_N_EX_PAINT);
988
989 return (0);
990 }
991
992 /*
993 * v_dtoh --
994 * Move all but the current screen to the hidden queue.
995 */
996 static void
v_dtoh(SCR * sp)997 v_dtoh(SCR *sp)
998 {
999 GS *gp;
1000 SCR *tsp;
1001 int hidden;
1002
1003 /* Move all screens to the hidden queue, tossing screen maps. */
1004 for (hidden = 0, gp = sp->gp;
1005 (tsp = TAILQ_FIRST(gp->dq)) != NULL; ++hidden) {
1006 free(_HMAP(tsp));
1007 _HMAP(tsp) = NULL;
1008 TAILQ_REMOVE(gp->dq, tsp, q);
1009 TAILQ_INSERT_TAIL(gp->hq, tsp, q);
1010 /* XXXX Change if hidden screens per window */
1011 gp->scr_discard(tsp, NULL);
1012 }
1013
1014 /* Move current screen back to the display queue. */
1015 TAILQ_REMOVE(gp->hq, sp, q);
1016 TAILQ_INSERT_TAIL(gp->dq, sp, q);
1017
1018 if (hidden > 1)
1019 msgq(sp, M_INFO,
1020 "319|%d screens backgrounded; use :display to list them",
1021 hidden - 1);
1022 }
1023
1024 /*
1025 * v_curword --
1026 * Get the word (tagstring, actually) the cursor is on.
1027 *
1028 * PUBLIC: int v_curword(SCR *);
1029 */
1030 int
v_curword(SCR * sp)1031 v_curword(SCR *sp)
1032 {
1033 VI_PRIVATE *vip;
1034 size_t beg, end, len;
1035 int moved;
1036 CHAR_T *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, "212|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 /*
1068 * Find the end of the word.
1069 *
1070 * !!!
1071 * Historically, vi accepted any non-blank as initial character
1072 * when building up a tagstring. Required by IEEE 1003.1-2001.
1073 */
1074 for (end = beg; ++end < len && inword(p[end]););
1075
1076 vip = VIP(sp);
1077 vip->klen = len = (end - beg);
1078 BINC_RETW(sp, vip->keyw, vip->keywlen, len+1);
1079 MEMMOVE(vip->keyw, p + beg, len);
1080 vip->keyw[len] = '\0'; /* XXX */
1081 return (0);
1082 }
1083
1084 /*
1085 * v_alias --
1086 * Check for a command alias.
1087 */
1088 static VIKEYS const *
v_alias(SCR * sp,VICMD * vp,VIKEYS const * kp)1089 v_alias(
1090 SCR *sp,
1091 VICMD *vp,
1092 VIKEYS const *kp)
1093 {
1094 CHAR_T push;
1095
1096 switch (vp->key) {
1097 case 'C': /* C -> c$ */
1098 push = '$';
1099 vp->key = 'c';
1100 break;
1101 case 'D': /* D -> d$ */
1102 push = '$';
1103 vp->key = 'd';
1104 break;
1105 case 'S': /* S -> c_ */
1106 push = '_';
1107 vp->key = 'c';
1108 break;
1109 case 'Y': /* Y -> y_ */
1110 push = '_';
1111 vp->key = 'y';
1112 break;
1113 default:
1114 return (kp);
1115 }
1116 return (v_event_push(sp,
1117 NULL, &push, 1, CH_NOMAP | CH_QUOTED) ? NULL : &vikeys[vp->key]);
1118 }
1119
1120 /*
1121 * v_count --
1122 * Return the next count.
1123 */
1124 static int
v_count(SCR * sp,ARG_CHAR_T fkey,u_long * countp)1125 v_count(
1126 SCR *sp,
1127 ARG_CHAR_T fkey,
1128 u_long *countp)
1129 {
1130 EVENT ev;
1131 u_long count, tc;
1132
1133 ev.e_c = fkey;
1134 count = tc = 0;
1135 do {
1136 /*
1137 * XXX
1138 * Assume that overflow results in a smaller number.
1139 */
1140 tc = count * 10 + ev.e_c - '0';
1141 if (count > tc) {
1142 /* Toss to the next non-digit. */
1143 do {
1144 if (v_key(sp, 0, &ev,
1145 EC_MAPCOMMAND | EC_MAPNODIGIT) != GC_OK)
1146 return (1);
1147 } while (ISDIGIT(ev.e_c));
1148 msgq(sp, M_ERR,
1149 "235|Number larger than %lu", ULONG_MAX);
1150 return (1);
1151 }
1152 count = tc;
1153 if (v_key(sp, 0, &ev, EC_MAPCOMMAND | EC_MAPNODIGIT) != GC_OK)
1154 return (1);
1155 } while (ISDIGIT(ev.e_c));
1156 *countp = count;
1157 return (0);
1158 }
1159
1160 /*
1161 * v_key --
1162 * Return the next event.
1163 */
1164 static gcret_t
v_key(SCR * sp,int command_events,EVENT * evp,u_int32_t ec_flags)1165 v_key(
1166 SCR *sp,
1167 int command_events,
1168 EVENT *evp,
1169 u_int32_t ec_flags)
1170 {
1171 u_int32_t quote;
1172
1173 for (quote = 0;;) {
1174 if (v_event_get(sp, evp, 0, ec_flags | quote))
1175 return (GC_FATAL);
1176 quote = 0;
1177
1178 switch (evp->e_event) {
1179 case E_CHARACTER:
1180 /*
1181 * !!!
1182 * Historically, ^V was ignored in the command stream,
1183 * although it had a useful side-effect of interrupting
1184 * mappings. Adding a quoting bit to the call probably
1185 * extends historic practice, but it feels right.
1186 */
1187 if (evp->e_value == K_VLNEXT) {
1188 quote = EC_QUOTED;
1189 break;
1190 }
1191 return (GC_OK);
1192 case E_ERR:
1193 case E_EOF:
1194 return (GC_FATAL);
1195 case E_INTERRUPT:
1196 /*
1197 * !!!
1198 * Historically, vi beeped on command level interrupts.
1199 *
1200 * Historically, vi exited to ex mode if no file was
1201 * named on the command line, and two interrupts were
1202 * generated in a row. (Just figured you might want
1203 * to know that.)
1204 */
1205 (void)sp->gp->scr_bell(sp);
1206 return (GC_INTERRUPT);
1207 case E_REPAINT:
1208 if (vs_repaint(sp, evp))
1209 return (GC_FATAL);
1210 break;
1211 case E_WRESIZE:
1212 return (GC_ERR);
1213 default:
1214 v_event_err(sp, evp);
1215 return (GC_ERR);
1216 }
1217 }
1218 /* NOTREACHED */
1219 }
1220
1221 #if defined(DEBUG) && defined(COMLOG)
1222 /*
1223 * v_comlog --
1224 * Log the contents of the command structure.
1225 */
1226 static void
v_comlog(SCR * sp,VICMD * vp)1227 v_comlog(
1228 SCR *sp,
1229 VICMD *vp)
1230 {
1231 TRACE(sp, "vcmd: "WC, vp->key);
1232 if (F_ISSET(vp, VC_BUFFER))
1233 TRACE(sp, " buffer: "WC, vp->buffer);
1234 if (F_ISSET(vp, VC_C1SET))
1235 TRACE(sp, " c1: %lu", vp->count);
1236 if (F_ISSET(vp, VC_C2SET))
1237 TRACE(sp, " c2: %lu", vp->count2);
1238 TRACE(sp, " flags: 0x%x\n", vp->flags);
1239 }
1240 #endif
1241