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