align CHAR_T string in log
[nvi.git] / vi / vi.c
blobf356b04719d881b63849201649ed1d125ac2c064
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.
7 * See the LICENSE file for redistribution information.
8 */
10 #include "config.h"
12 #ifndef lint
13 static const char sccsid[] = "$Id: vi.c,v 10.71 2001/04/22 19:55:52 skimo Exp $ (Berkeley) $Date: 2001/04/22 19:55:52 $";
14 #endif /* not lint */
16 #include <sys/types.h>
17 #include <sys/queue.h>
18 #include <sys/time.h>
20 #include <bitstring.h>
21 #include <ctype.h>
22 #include <errno.h>
23 #include <limits.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
29 #include "../common/common.h"
30 #include "vi.h"
32 typedef enum {
33 GC_ERR, GC_ERR_NOFLUSH, GC_EVENT, GC_FATAL, GC_INTERRUPT, GC_OK
34 } gcret_t;
36 static VIKEYS const
37 *v_alias __P((SCR *, VICMD *, VIKEYS const *));
38 static gcret_t v_cmd __P((SCR *, VICMD *, VICMD *, VICMD *, int *, int *));
39 static int v_count __P((SCR *, VICMD *, ARG_CHAR_T, u_long *));
40 static void v_dtoh __P((SCR *));
41 static int v_init __P((SCR *));
42 static gcret_t v_key __P((SCR *, VICMD *, int, u_int32_t));
43 static int v_motion __P((SCR *, VICMD *, VICMD *, int *));
45 #if defined(DEBUG) && defined(COMLOG)
46 static void v_comlog __P((SCR *, VICMD *));
47 #endif
50 * Side-effect:
51 * The dot structure can be set by the underlying vi functions,
52 * see v_Put() and v_put().
54 #define DOT (&VIP(sp)->sdot)
55 #define DOTMOTION (&VIP(sp)->sdotmotion)
58 * vi --
59 * Main vi command loop.
61 * PUBLIC: int vi __P((SCR **));
63 int
64 vi(spp)
65 SCR **spp;
67 GS *gp;
68 WIN *wp;
69 MARK abs;
70 SCR *next, *sp;
71 VICMD cmd, *vp;
72 VI_PRIVATE *vip;
73 int comcount, mapped, rval;
75 /* Get the first screen. */
76 sp = *spp;
77 wp = sp->wp;
78 gp = sp->gp;
80 /* Initialize the command structure. */
81 vp = &cmd;
82 memset(vp, 0, sizeof(VICMD));
84 /* Reset strange attraction. */
85 F_SET(vp, VM_RCM_SET);
87 /* Initialize the vi screen. */
88 if (v_init(sp))
89 return (1);
91 /* Set the focus. */
92 (void)sp->gp->scr_rename(sp, sp->frp->name, 1);
94 for (vip = VIP(sp), rval = 0;;) {
95 /* Resolve messages. */
96 if (!MAPPED_KEYS_WAITING(sp) && vs_resolve(sp, NULL, 0))
97 goto ret;
100 * If not skipping a refresh, return to command mode and
101 * refresh the screen.
103 if (F_ISSET(vip, VIP_S_REFRESH))
104 F_CLR(vip, VIP_S_REFRESH);
105 else {
106 sp->showmode = SM_COMMAND;
107 if (vs_refresh(sp, 0))
108 goto ret;
111 /* Set the new favorite position. */
112 if (F_ISSET(vp, VM_RCM_SET | VM_RCM_SETFNB | VM_RCM_SETNNB)) {
113 F_CLR(vip, VIP_RCM_LAST);
114 (void)vs_column(sp, &sp->rcm);
118 * If not currently in a map, log the cursor position,
119 * and set a flag so that this command can become the
120 * DOT command.
122 if (MAPPED_KEYS_WAITING(sp))
123 mapped = 1;
124 else {
125 if (log_cursor(sp))
126 goto err;
127 mapped = 0;
131 * There may be an ex command waiting, and we returned here
132 * only because we exited a screen or file. In this case,
133 * we simply go back into the ex parser.
135 if (EXCMD_RUNNING(wp)) {
136 vp->kp = &vikeys[':'];
137 goto ex_continue;
140 /* Refresh the command structure. */
141 memset(vp, 0, sizeof(VICMD));
144 * We get a command, which may or may not have an associated
145 * motion. If it does, we get it too, calling its underlying
146 * function to get the resulting mark. We then call the
147 * command setting the cursor to the resulting mark.
149 * !!!
150 * Vi historically flushed mapped characters on error, but
151 * entering extra <escape> characters at the beginning of
152 * a map wasn't considered an error -- in fact, users would
153 * put leading <escape> characters in maps to clean up vi
154 * state before the map was interpreted. Beauty!
156 switch (v_cmd(sp, DOT, vp, NULL, &comcount, &mapped)) {
157 case GC_ERR:
158 goto err;
159 case GC_ERR_NOFLUSH:
160 goto gc_err_noflush;
161 case GC_FATAL:
162 goto ret;
163 case GC_INTERRUPT:
164 goto intr;
165 case GC_EVENT:
166 case GC_OK:
167 break;
170 /* Check for security setting. */
171 if (F_ISSET(vp->kp, V_SECURE) && O_ISSET(sp, O_SECURE)) {
172 ex_emsg(sp, KEY_NAME(sp, vp->key), EXM_SECURE);
173 goto err;
177 * Historical practice: if a dot command gets a new count,
178 * any motion component goes away, i.e. "d3w2." deletes a
179 * total of 5 words.
181 if (F_ISSET(vp, VC_ISDOT) && comcount)
182 DOTMOTION->count = 1;
184 /* Copy the key flags into the local structure. */
185 F_SET(vp, vp->kp->flags);
187 /* Prepare to set the previous context. */
188 if (F_ISSET(vp, V_ABS | V_ABS_C | V_ABS_L)) {
189 abs.lno = sp->lno;
190 abs.cno = sp->cno;
194 * Set the three cursor locations to the current cursor. The
195 * underlying routines don't bother if the cursor doesn't move.
196 * This also handles line commands (e.g. Y) defaulting to the
197 * current line.
199 vp->m_start.lno = vp->m_stop.lno = vp->m_final.lno = sp->lno;
200 vp->m_start.cno = vp->m_stop.cno = vp->m_final.cno = sp->cno;
203 * Do any required motion; v_motion sets the from MARK and the
204 * line mode flag, as well as the VM_RCM flags.
206 if (F_ISSET(vp, V_MOTION) &&
207 v_motion(sp, DOTMOTION, vp, &mapped)) {
208 if (INTERRUPTED(sp))
209 goto intr;
210 goto err;
214 * If a count is set and the command is line oriented, set the
215 * to MARK here relative to the cursor/from MARK. This is for
216 * commands that take both counts and motions, i.e. "4yy" and
217 * "y%". As there's no way the command can know which the user
218 * did, we have to do it here. (There are commands that are
219 * line oriented and that take counts ("#G", "#H"), for which
220 * this calculation is either completely meaningless or wrong.
221 * Each command must validate the value for itself.
223 if (F_ISSET(vp, VC_C1SET) && F_ISSET(vp, VM_LMODE))
224 vp->m_stop.lno += vp->count - 1;
226 /* Increment the command count. */
227 ++sp->ccnt;
229 #if defined(DEBUG) && defined(COMLOG)
230 v_comlog(sp, vp);
231 #endif
232 /* Call the function. */
233 ex_continue: if (vp->kp->func(sp, vp))
234 goto err;
235 #ifdef DEBUG
236 /* Make sure no function left the temporary space locked. */
237 if (F_ISSET(wp, W_TMP_INUSE)) {
238 F_CLR(wp, W_TMP_INUSE);
239 msgq(sp, M_ERR,
240 "232|vi: temporary buffer not released");
242 #endif
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.
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;
262 /* Switch screens, change focus. */
263 sp = next;
264 vip = VIP(sp);
265 (void)sp->gp->scr_rename(sp, sp->frp->name, 1);
267 /* Don't trust the cursor. */
268 F_SET(vip, VIP_CUR_INVALID);
270 continue;
274 * Set the dot command structure.
276 * !!!
277 * Historically, commands which used mapped keys did not
278 * set the dot command, with the exception of the text
279 * input commands.
281 if (F_ISSET(vp, V_DOT) && !mapped) {
282 *DOT = cmd;
283 F_SET(DOT, VC_ISDOT);
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.
290 if (F_ISSET(vp, VC_C1RESET))
291 F_SET(DOT, VC_C1SET);
293 /* VM flags aren't retained. */
294 F_CLR(DOT, VM_COMMASK | VM_RCM_MASK);
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.
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.
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.
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();
338 /* Update the cursor. */
339 sp->lno = vp->m_final.lno;
340 sp->cno = vp->m_final.cno;
343 * Set the absolute mark -- set even if a tags or similar
344 * command, since the tag may be moving to the same file.
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;
353 if (0) {
354 err: if (v_event_flush(sp, CH_MAPPED))
355 msgq(sp, M_BERR,
356 "110|Vi command failed: mapped keys discarded");
360 * Check and clear interrupts. There's an obvious race, but
361 * it's not worth fixing.
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 "231|Interrupted: mapped keys discarded");
368 else
369 msgq(sp, M_ERR, "236|Interrupted");
372 /* If the last command switched screens, update. */
373 if (F_ISSET(sp, SC_SSWITCH)) {
374 F_CLR(sp, SC_SSWITCH);
377 * If the current screen is still displayed, it will
378 * need a new status line.
380 F_SET(sp, SC_STATUS);
382 /* Switch screens, change focus. */
383 sp = sp->nextdisp;
384 vip = VIP(sp);
385 (void)sp->gp->scr_rename(sp, sp->frp->name, 1);
387 /* Don't trust the cursor. */
388 F_SET(vip, VIP_CUR_INVALID);
390 /* Refresh so we can display messages. */
391 if (vs_refresh(sp, 1))
392 return (1);
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);
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 gp->scr_discard(sp, NULL);
406 break;
409 if (0)
410 ret: rval = 1;
411 return (rval);
414 #define KEY(key, ec_flags) { \
415 if ((gcret = v_key(sp, vp, 0, ec_flags)) != GC_OK) \
416 return (gcret); \
417 if (vp->ev.e_value == K_ESCAPE) \
418 goto esc; \
419 if (FL_ISSET(vp->ev.e_flags, CH_MAPPED)) \
420 *mappedp = 1; \
421 key = vp->ev.e_c; \
425 * The O_TILDEOP option makes the ~ command take a motion instead
426 * of a straight count. This is the replacement structure we use
427 * instead of the one currently in the VIKEYS table.
429 * XXX
430 * This should probably be deleted -- it's not all that useful, and
431 * we get help messages wrong.
433 VIKEYS const tmotion = {
434 v_mulcase, V_CNT|V_DOT|V_MOTION|VM_RCM_SET,
435 "[count]~[count]motion",
436 " ~ change case to motion"
440 * v_cmd --
441 * Get a vi command.
443 static gcret_t
444 v_cmd(sp, dp, vp, ismotion, comcountp, mappedp)
445 SCR *sp;
446 VICMD *dp, *vp;
447 VICMD *ismotion; /* Previous key if getting motion component. */
448 int *comcountp, *mappedp;
450 enum { COMMANDMODE, ISPARTIAL, NOTPARTIAL } cpart;
451 CHAR_T key;
452 VIKEYS const *kp;
453 gcret_t gcret;
454 u_int flags;
455 char *s;
458 * Get an event command or a key. Event commands are simple, and
459 * don't have any additional information.
461 cpart = ismotion == NULL ? COMMANDMODE : ISPARTIAL;
462 gcret = v_key(sp, vp, 1, EC_MAPCOMMAND);
463 if (gcret != GC_OK) {
464 if (gcret != GC_EVENT)
465 return (gcret);
466 if (v_event(sp, vp))
467 return (GC_ERR);
468 if (ismotion != NULL && !F_ISSET(vp->kp, V_MOVE))
469 v_event_err(sp, &vp->ev);
470 return (GC_EVENT);
474 * Keys are not simple. (Although vi's command structure less complex
475 * than ex (and don't think I'm not grateful!) The command syntax is:
477 * [count] [buffer] [count] key [[motion] | [buffer] [character]]
479 * and there are, of course, several special cases. The motion value
480 * is itself a vi command, with the syntax:
482 * [count] key [character]
484 * <escape> cancels partial commands, i.e. a command where at least
485 * one non-numeric character has been entered. Otherwise, it beeps
486 * the terminal.
488 * !!!
489 * POSIX 1003.2-1992 explicitly disallows cancelling commands where
490 * all that's been entered is a number, requiring that the terminal
491 * be alerted.
493 if (vp->ev.e_value == K_ESCAPE)
494 goto esc;
497 * Commands that are mapped are treated differently (e.g., they
498 * don't set the dot command. Pass that information back.
500 if (FL_ISSET(vp->ev.e_flags, CH_MAPPED))
501 *mappedp = 1;
502 key = vp->ev.e_c;
504 if (ismotion == NULL)
505 cpart = NOTPARTIAL;
507 /* Pick up an optional buffer. */
508 if (key == '"') {
509 cpart = ISPARTIAL;
510 if (ismotion != NULL) {
511 v_emsg(sp, NULL, VIM_COMBUF);
512 return (GC_ERR);
514 KEY(vp->buffer, 0);
515 F_SET(vp, VC_BUFFER);
517 KEY(key, EC_MAPCOMMAND);
521 * Pick up an optional count, where a leading 0 isn't a count, it's
522 * a command. When a count is specified, the dot command behaves
523 * differently, pass the information back.
525 if (ISDIGIT(key) && key != '0') {
526 if (v_count(sp, vp, key, &vp->count))
527 return (GC_ERR);
529 F_SET(vp, VC_C1SET);
530 *comcountp = 1;
532 KEY(key, EC_MAPCOMMAND);
533 } else
534 *comcountp = 0;
536 /* Pick up optional buffer. */
537 if (key == '"') {
538 cpart = ISPARTIAL;
539 if (F_ISSET(vp, VC_BUFFER)) {
540 msgq(sp, M_ERR, "234|Only one buffer may be specified");
541 return (GC_ERR);
543 if (ismotion != NULL) {
544 v_emsg(sp, NULL, VIM_COMBUF);
545 return (GC_ERR);
547 KEY(vp->buffer, 0);
548 F_SET(vp, VC_BUFFER);
550 KEY(key, EC_MAPCOMMAND);
553 /* Check for an OOB command key. */
554 cpart = ISPARTIAL;
555 if (key > MAXVIKEY) {
556 v_emsg(sp, KEY_NAME(sp, key), VIM_NOCOM);
557 return (GC_ERR);
559 kp = &vikeys[vp->key = key];
562 * !!!
563 * Historically, D accepted and then ignored a count. Match it.
565 if (vp->key == 'D' && F_ISSET(vp, VC_C1SET)) {
566 *comcountp = 0;
567 vp->count = 0;
568 F_CLR(vp, VC_C1SET);
572 * There are several commands that we implement as aliases, both
573 * to match historic practice and to ensure consistency. Check
574 * for command aliases.
576 if (kp->func == NULL && (kp = v_alias(sp, vp, kp)) == NULL)
577 return (GC_ERR);
579 /* The tildeop option makes the ~ command take a motion. */
580 if (key == '~' && O_ISSET(sp, O_TILDEOP))
581 kp = &tmotion;
583 vp->kp = kp;
586 * Find the command. The only legal command with no underlying
587 * function is dot. It's historic practice that <escape> doesn't
588 * just erase the preceding number, it beeps the terminal as well.
589 * It's a common problem, so just beep the terminal unless verbose
590 * was set.
592 if (kp->func == NULL) {
593 if (key != '.') {
594 v_emsg(sp, KEY_NAME(sp, key),
595 vp->ev.e_value == K_ESCAPE ?
596 VIM_NOCOM_B : VIM_NOCOM);
597 return (GC_ERR);
600 /* If called for a motion command, stop now. */
601 if (dp == NULL)
602 goto usage;
605 * !!!
606 * If a '.' is immediately entered after an undo command, we
607 * replay the log instead of redoing the last command. This
608 * is necessary because 'u' can't set the dot command -- see
609 * vi/v_undo.c:v_undo for details.
611 if (VIP(sp)->u_ccnt == sp->ccnt) {
612 vp->kp = &vikeys['u'];
613 F_SET(vp, VC_ISDOT);
614 return (GC_OK);
617 /* Otherwise, a repeatable command must have been executed. */
618 if (!F_ISSET(dp, VC_ISDOT)) {
619 msgq(sp, M_ERR, "208|No command to repeat");
620 return (GC_ERR);
623 /* Set new count/buffer, if any, and return. */
624 if (F_ISSET(vp, VC_C1SET)) {
625 F_SET(dp, VC_C1SET);
626 dp->count = vp->count;
628 if (F_ISSET(vp, VC_BUFFER))
629 dp->buffer = vp->buffer;
631 *vp = *dp;
632 return (GC_OK);
635 /* Set the flags based on the command flags. */
636 flags = kp->flags;
638 /* Check for illegal count. */
639 if (F_ISSET(vp, VC_C1SET) && !LF_ISSET(V_CNT))
640 goto usage;
642 /* Illegal motion command. */
643 if (ismotion == NULL) {
644 /* Illegal buffer. */
645 if (!LF_ISSET(V_OBUF) && F_ISSET(vp, VC_BUFFER))
646 goto usage;
648 /* Required buffer. */
649 if (LF_ISSET(V_RBUF)) {
650 KEY(vp->buffer, 0);
651 F_SET(vp, VC_BUFFER);
656 * Special case: '[', ']' and 'Z' commands. Doesn't the fact that
657 * the *single* characters don't mean anything but the *doubled*
658 * characters do, just frost your shorts?
660 if (vp->key == '[' || vp->key == ']' || vp->key == 'Z') {
662 * Historically, half entered [[, ]] or Z commands weren't
663 * cancelled by <escape>, the terminal was beeped instead.
664 * POSIX.2-1992 probably didn't notice, and requires that
665 * they be cancelled instead of beeping. Seems fine to me.
667 * Don't set the EC_MAPCOMMAND flag, apparently ] is a popular
668 * vi meta-character, and we don't want the user to wait while
669 * we time out a possible mapping. This *appears* to match
670 * historic vi practice, but with mapping characters, You Just
671 * Never Know.
673 KEY(key, 0);
675 if (vp->key != key) {
676 usage: if (ismotion == NULL)
677 s = kp->usage;
678 else if (ismotion->key == '~' && O_ISSET(sp, O_TILDEOP))
679 s = tmotion.usage;
680 else
681 s = vikeys[ismotion->key].usage;
682 v_emsg(sp, s, VIM_USAGE);
683 return (GC_ERR);
686 /* Special case: 'z' command. */
687 if (vp->key == 'z') {
688 KEY(vp->character, 0);
689 if (ISDIGIT(vp->character)) {
690 if (v_count(sp, vp, vp->character, &vp->count2))
691 return (GC_ERR);
692 F_SET(vp, VC_C2SET);
693 KEY(vp->character, 0);
698 * Commands that have motion components can be doubled to imply the
699 * current line.
701 if (ismotion != NULL && ismotion->key != key && !LF_ISSET(V_MOVE)) {
702 msgq(sp, M_ERR, "210|%s may not be used as a motion command",
703 KEY_NAME(sp, key));
704 return (GC_ERR);
707 /* Pick up required trailing character. */
708 if (LF_ISSET(V_CHAR))
709 KEY(vp->character, 0);
711 /* Get any associated cursor word. */
712 if (F_ISSET(kp, V_KEYW) && v_curword(sp))
713 return (GC_ERR);
715 return (GC_OK);
717 esc: switch (cpart) {
718 case COMMANDMODE:
719 msgq(sp, M_BERR, "211|Already in command mode");
720 return (GC_ERR_NOFLUSH);
721 case ISPARTIAL:
722 break;
723 case NOTPARTIAL:
724 (void)sp->gp->scr_bell(sp);
725 break;
727 return (GC_ERR);
731 * v_motion --
733 * Get resulting motion mark.
735 static int
736 v_motion(sp, dm, vp, mappedp)
737 SCR *sp;
738 VICMD *dm, *vp;
739 int *mappedp;
741 VICMD motion;
742 gcret_t gcret;
743 size_t len;
744 u_long cnt;
745 u_int flags;
746 int tilde_reset, notused;
749 * If '.' command, use the dot motion, else get the motion command.
750 * Clear any line motion flags, the subsequent motion isn't always
751 * the same, i.e. "/aaa" may or may not be a line motion.
753 if (F_ISSET(vp, VC_ISDOT)) {
754 motion = *dm;
755 F_SET(&motion, VC_ISDOT);
756 F_CLR(&motion, VM_COMMASK);
757 gcret = GC_OK;
758 } else {
759 memset(&motion, 0, sizeof(VICMD));
760 gcret = v_cmd(sp, NULL, &motion, vp, &notused, mappedp);
761 if (gcret != GC_OK && gcret != GC_EVENT)
762 return (1);
766 * A count may be provided both to the command and to the motion, in
767 * which case the count is multiplicative. For example, "3y4y" is the
768 * same as "12yy". This count is provided to the motion command and
769 * not to the regular function.
771 cnt = motion.count = F_ISSET(&motion, VC_C1SET) ? motion.count : 1;
772 if (F_ISSET(vp, VC_C1SET)) {
773 motion.count *= vp->count;
774 F_SET(&motion, VC_C1SET);
777 * Set flags to restore the original values of the command
778 * structure so dot commands can change the count values,
779 * e.g. "2dw" "3." deletes a total of five words.
781 F_CLR(vp, VC_C1SET);
782 F_SET(vp, VC_C1RESET);
786 * Some commands can be repeated to indicate the current line. In
787 * this case, or if the command is a "line command", set the flags
788 * appropriately. If not a doubled command, run the function to get
789 * the resulting mark.
791 if (gcret != GC_EVENT && vp->key == motion.key) {
792 F_SET(vp, VM_LDOUBLE | VM_LMODE);
794 /* Set the origin of the command. */
795 vp->m_start.lno = sp->lno;
796 vp->m_start.cno = 0;
799 * Set the end of the command.
801 * If the current line is missing, i.e. the file is empty,
802 * historic vi permitted a "cc" or "!!" command to insert
803 * text.
805 vp->m_stop.lno = sp->lno + motion.count - 1;
806 if (db_get(sp, vp->m_stop.lno, 0, NULL, &len)) {
807 if (vp->m_stop.lno != 1 ||
808 vp->key != 'c' && vp->key != '!') {
809 v_emsg(sp, NULL, VIM_EMPTY);
810 return (1);
812 vp->m_stop.cno = 0;
813 } else
814 vp->m_stop.cno = len ? len - 1 : 0;
815 } else {
817 * Motion commands change the underlying movement (*snarl*).
818 * For example, "l" is illegal at the end of a line, but "dl"
819 * is not. Set flags so the function knows the situation.
821 motion.rkp = vp->kp;
824 * XXX
825 * Use yank instead of creating a new motion command, it's a
826 * lot easier for now.
828 if (vp->kp == &tmotion) {
829 tilde_reset = 1;
830 vp->kp = &vikeys['y'];
831 } else
832 tilde_reset = 0;
835 * Copy the key flags into the local structure, except for the
836 * RCM flags -- the motion command will set the RCM flags in
837 * the vp structure if necessary. This means that the motion
838 * command is expected to determine where the cursor ends up!
839 * However, we save off the current RCM mask and restore it if
840 * it no RCM flags are set by the motion command, with a small
841 * modification.
843 * We replace the VM_RCM_SET flag with the VM_RCM flag. This
844 * is so that cursor movement doesn't set the relative position
845 * unless the motion command explicitly specified it. This
846 * appears to match historic practice, but I've never been able
847 * to develop a hard-and-fast rule.
849 flags = F_ISSET(vp, VM_RCM_MASK);
850 if (LF_ISSET(VM_RCM_SET)) {
851 LF_SET(VM_RCM);
852 LF_CLR(VM_RCM_SET);
854 F_CLR(vp, VM_RCM_MASK);
855 F_SET(&motion, motion.kp->flags & ~VM_RCM_MASK);
858 * Set the three cursor locations to the current cursor. This
859 * permits commands like 'j' and 'k', that are line oriented
860 * motions and have special cursor suck semantics when they are
861 * used as standalone commands, to ignore column positioning.
863 motion.m_final.lno =
864 motion.m_stop.lno = motion.m_start.lno = sp->lno;
865 motion.m_final.cno =
866 motion.m_stop.cno = motion.m_start.cno = sp->cno;
868 /* Run the function. */
869 if ((motion.kp->func)(sp, &motion))
870 return (1);
873 * If the current line is missing, i.e. the file is empty,
874 * historic vi allowed "c<motion>" or "!<motion>" to insert
875 * text. Otherwise fail -- most motion commands will have
876 * already failed, but some, e.g. G, succeed in empty files.
878 if (!db_exist(sp, vp->m_stop.lno)) {
879 if (vp->m_stop.lno != 1 ||
880 vp->key != 'c' && vp->key != '!') {
881 v_emsg(sp, NULL, VIM_EMPTY);
882 return (1);
884 vp->m_stop.cno = 0;
888 * XXX
889 * See above.
891 if (tilde_reset)
892 vp->kp = &tmotion;
895 * Copy cut buffer, line mode and cursor position information
896 * from the motion command structure, i.e. anything that the
897 * motion command can set for us. The commands can flag the
898 * movement as a line motion (see v_sentence) as well as set
899 * the VM_RCM_* flags explicitly.
901 F_SET(vp, F_ISSET(&motion, VM_COMMASK | VM_RCM_MASK));
904 * If the motion command set no relative motion flags, use
905 * the (slightly) modified previous values.
907 if (!F_ISSET(vp, VM_RCM_MASK))
908 F_SET(vp, flags);
911 * Commands can change behaviors based on the motion command
912 * used, for example, the ! command repeated the last bang
913 * command if N or n was used as the motion.
915 vp->rkp = motion.kp;
918 * Motion commands can reset all of the cursor information.
919 * If the motion is in the reverse direction, switch the
920 * from and to MARK's so that it's in a forward direction.
921 * Motions are from the from MARK to the to MARK (inclusive).
923 if (motion.m_start.lno > motion.m_stop.lno ||
924 motion.m_start.lno == motion.m_stop.lno &&
925 motion.m_start.cno > motion.m_stop.cno) {
926 vp->m_start = motion.m_stop;
927 vp->m_stop = motion.m_start;
928 } else {
929 vp->m_start = motion.m_start;
930 vp->m_stop = motion.m_stop;
932 vp->m_final = motion.m_final;
936 * If the command sets dot, save the motion structure. The motion
937 * count was changed above and needs to be reset, that's why this
938 * is done here, and not in the calling routine.
940 if (F_ISSET(vp->kp, V_DOT)) {
941 *dm = motion;
942 dm->count = cnt;
944 return (0);
948 * v_init --
949 * Initialize the vi screen.
951 static int
952 v_init(sp)
953 SCR *sp;
955 GS *gp;
956 VI_PRIVATE *vip;
958 gp = sp->gp;
959 vip = VIP(sp);
961 /* Switch into vi. */
962 if (gp->scr_screen(sp, SC_VI))
963 return (1);
964 (void)gp->scr_attr(sp, SA_ALTERNATE, 1);
966 F_CLR(sp, SC_EX | SC_SCR_EX);
967 F_SET(sp, SC_VI);
970 * Initialize screen values.
972 * Small windows: see vs_refresh(), section 6a.
974 * Setup:
975 * t_minrows is the minimum rows to display
976 * t_maxrows is the maximum rows to display (rows - 1)
977 * t_rows is the rows currently being displayed
979 sp->rows = vip->srows = O_VAL(sp, O_LINES);
980 sp->cols = O_VAL(sp, O_COLUMNS);
981 sp->t_rows = sp->t_minrows = O_VAL(sp, O_WINDOW);
982 if (sp->rows != 1) {
983 if (sp->t_rows > sp->rows - 1) {
984 sp->t_minrows = sp->t_rows = sp->rows - 1;
985 msgq(sp, M_INFO,
986 "214|Windows option value is too large, max is %u",
987 sp->t_rows);
989 sp->t_maxrows = sp->rows - 1;
990 } else
991 sp->t_maxrows = 1;
992 sp->roff = sp->coff = 0;
994 /* Create a screen map. */
995 CALLOC_RET(sp, HMAP, SMAP *, SIZE_HMAP(sp), sizeof(SMAP));
996 TMAP = HMAP + (sp->t_rows - 1);
997 HMAP->lno = sp->lno;
998 HMAP->coff = 0;
999 HMAP->soff = 1;
1002 * Fill the screen map from scratch -- try and center the line. That
1003 * way if we're starting with a file we've seen before, we'll put the
1004 * line in the middle, otherwise, it won't work and we'll end up with
1005 * the line at the top.
1007 F_SET(sp, SC_SCR_REFORMAT | SC_SCR_CENTER);
1009 /* Invalidate the cursor. */
1010 F_SET(vip, VIP_CUR_INVALID);
1012 /* Paint the screen image from scratch. */
1013 F_SET(vip, VIP_N_EX_PAINT);
1015 return (0);
1019 * v_dtoh --
1020 * Move all but the current screen to the hidden queue.
1022 static void
1023 v_dtoh(sp)
1024 SCR *sp;
1026 GS *gp;
1027 SCR *tsp;
1028 WIN *wp;
1029 int hidden;
1031 /* Move all screens to the hidden queue, tossing screen maps. */
1032 for (hidden = 0, gp = sp->gp, wp = sp->wp;
1033 (tsp = wp->scrq.cqh_first) != (void *)&wp->scrq; ++hidden) {
1034 if (_HMAP(tsp) != NULL) {
1035 free(_HMAP(tsp));
1036 _HMAP(tsp) = NULL;
1038 CIRCLEQ_REMOVE(&wp->scrq, tsp, q);
1039 CIRCLEQ_INSERT_TAIL(&gp->hq, tsp, q);
1040 /* XXXX Change if hidden screens per window */
1041 tsp->wp = 0;
1042 gp->scr_discard(tsp, NULL);
1045 /* Move current screen back to the display queue. */
1046 CIRCLEQ_REMOVE(&gp->hq, sp, q);
1047 CIRCLEQ_INSERT_TAIL(&wp->scrq, sp, q);
1048 sp->wp = wp;
1050 if (hidden > 1)
1051 msgq(sp, M_INFO,
1052 "319|%d screens backgrounded; use :display to list them",
1053 hidden - 1);
1057 * v_curword --
1058 * Get the word (or non-word) the cursor is on.
1060 * PUBLIC: int v_curword __P((SCR *));
1063 v_curword(sp)
1064 SCR *sp;
1066 VI_PRIVATE *vip;
1067 size_t beg, end, len;
1068 int moved, state;
1069 CHAR_T *p;
1071 if (db_get(sp, sp->lno, DBG_FATAL, &p, &len))
1072 return (1);
1075 * !!!
1076 * Historically, tag commands skipped over any leading whitespace
1077 * characters. Make this true in general when using cursor words.
1078 * If movement, getting a cursor word implies moving the cursor to
1079 * its beginning. Refresh now.
1081 * !!!
1082 * Find the beginning/end of the keyword. Keywords are currently
1083 * used for cursor-word searching and for tags. Historical vi
1084 * only used the word in a tag search from the cursor to the end
1085 * of the word, i.e. if the cursor was on the 'b' in " abc ", the
1086 * tag was "bc". For consistency, we make cursor word searches
1087 * follow the same rule.
1089 for (moved = 0,
1090 beg = sp->cno; beg < len && isspace(p[beg]); moved = 1, ++beg);
1091 if (beg >= len) {
1092 msgq(sp, M_BERR, "212|Cursor not in a word");
1093 return (1);
1095 if (moved) {
1096 sp->cno = beg;
1097 (void)vs_refresh(sp, 0);
1100 /* Find the end of the word. */
1101 for (state = inword(p[beg]),
1102 end = beg; ++end < len && state == inword(p[end]););
1104 vip = VIP(sp);
1105 len = (end - beg);
1106 BINC_RETW(sp, vip->keyw, vip->klen, len+1);
1107 MEMMOVEW(vip->keyw, p + beg, len);
1108 vip->keyw[len] = '\0'; /* XXX */
1109 return (0);
1113 * v_alias --
1114 * Check for a command alias.
1116 static VIKEYS const *
1117 v_alias(sp, vp, kp)
1118 SCR *sp;
1119 VICMD *vp;
1120 VIKEYS const *kp;
1122 CHAR_T push;
1124 switch (vp->key) {
1125 case 'C': /* C -> c$ */
1126 push = '$';
1127 vp->key = 'c';
1128 break;
1129 case 'D': /* D -> d$ */
1130 push = '$';
1131 vp->key = 'd';
1132 break;
1133 case 'S': /* S -> c_ */
1134 push = '_';
1135 vp->key = 'c';
1136 break;
1137 case 'Y': /* Y -> y_ */
1138 push = '_';
1139 vp->key = 'y';
1140 break;
1141 default:
1142 return (kp);
1144 return (v_event_push(sp,
1145 NULL, &push, 1, CH_NOMAP | CH_QUOTED) ? NULL : &vikeys[vp->key]);
1149 * v_count --
1150 * Return the next count.
1152 static int
1153 v_count(sp, vp, fkey, countp)
1154 SCR *sp;
1155 VICMD *vp;
1156 ARG_CHAR_T fkey;
1157 u_long *countp;
1159 u_long count, tc;
1161 vp->ev.e_c = fkey;
1162 count = tc = 0;
1163 do {
1165 * XXX
1166 * Assume that overflow results in a smaller number.
1168 tc = count * 10 + vp->ev.e_c - '0';
1169 if (count > tc) {
1170 /* Toss to the next non-digit. */
1171 do {
1172 if (v_key(sp, vp, 0,
1173 EC_MAPCOMMAND | EC_MAPNODIGIT) != GC_OK)
1174 return (1);
1175 } while (ISDIGIT(vp->ev.e_c));
1176 msgq(sp, M_ERR,
1177 "235|Number larger than %lu", ULONG_MAX);
1178 return (1);
1180 count = tc;
1181 if (v_key(sp, vp, 0, EC_MAPCOMMAND | EC_MAPNODIGIT) != GC_OK)
1182 return (1);
1183 } while (ISDIGIT(vp->ev.e_c));
1184 *countp = count;
1185 return (0);
1189 * v_key --
1190 * Return the next event.
1192 static gcret_t
1193 v_key(sp, vp, events_ok, ec_flags)
1194 SCR *sp;
1195 VICMD *vp;
1196 int events_ok;
1197 u_int32_t ec_flags;
1199 EVENT *evp;
1200 u_int32_t quote;
1202 for (evp = &vp->ev, quote = 0;;) {
1203 if (v_event_get(sp, evp, 0, ec_flags | quote))
1204 return (GC_FATAL);
1205 quote = 0;
1207 switch (evp->e_event) {
1208 case E_CHARACTER:
1210 * !!!
1211 * Historically, ^V was ignored in the command stream,
1212 * although it had a useful side-effect of interrupting
1213 * mappings. Adding a quoting bit to the call probably
1214 * extends historic practice, but it feels right.
1216 if (evp->e_value == K_VLNEXT) {
1217 quote = EC_QUOTED;
1218 break;
1220 return (GC_OK);
1221 case E_ERR:
1222 case E_EOF:
1223 return (GC_FATAL);
1224 case E_INTERRUPT:
1226 * !!!
1227 * Historically, vi beeped on command level interrupts.
1229 * Historically, vi exited to ex mode if no file was
1230 * named on the command line, and two interrupts were
1231 * generated in a row. (I figured you might want to
1232 * know that, just in case there's a quiz later.)
1234 (void)sp->gp->scr_bell(sp);
1235 return (GC_INTERRUPT);
1236 case E_REPAINT:
1237 if (v_erepaint(sp, evp))
1238 return (GC_FATAL);
1239 break;
1240 case E_WRESIZE:
1242 * !!!
1243 * We don't do anything here, just return an error.
1244 * The vi loop will return because of this, and then
1245 * the main loop will realize that we had to restart
1246 * the world and will call the vi loop again.
1248 return (GC_ERR);
1249 case E_IPCOMMAND:
1250 if (events_ok)
1251 return (GC_EVENT);
1252 /* FALLTHROUGH */
1253 default:
1254 v_event_err(sp, evp);
1255 return (GC_ERR);
1258 /* NOTREACHED */
1261 #if defined(DEBUG) && defined(COMLOG)
1263 * v_comlog --
1264 * Log the contents of the command structure.
1266 static void
1267 v_comlog(sp, vp)
1268 SCR *sp;
1269 VICMD *vp;
1271 vtrace(sp, "vcmd: %c", vp->key);
1272 if (F_ISSET(vp, VC_BUFFER))
1273 vtrace(sp, " buffer: %c", vp->buffer);
1274 if (F_ISSET(vp, VC_C1SET))
1275 vtrace(sp, " c1: %lu", vp->count);
1276 if (F_ISSET(vp, VC_C2SET))
1277 vtrace(sp, " c2: %lu", vp->count2);
1278 vtrace(sp, " flags: 0x%x\n", vp->flags);
1280 #endif