rework initial error handling -- since we check for any screens on
[nvi.git] / vi / vi.c
blob40aa12b26319f2b12281f0b56af7fc9a5eeff16a
1 /*-
2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
5 * %sccs.include.redist.c%
6 */
8 #ifndef lint
9 static char sccsid[] = "$Id: vi.c,v 8.45 1994/01/22 13:13:21 bostic Exp $ (Berkeley) $Date: 1994/01/22 13:13:21 $";
10 #endif /* not lint */
12 #include <sys/types.h>
14 #include <ctype.h>
15 #include <errno.h>
16 #include <stdlib.h>
17 #include <string.h>
19 #include "vi.h"
20 #include "vcmd.h"
22 static int getcmd __P((SCR *, EXF *,
23 VICMDARG *, VICMDARG *, VICMDARG *, int *));
24 static inline int
25 getcount __P((SCR *, ARG_CHAR_T, u_long *));
26 static inline int
27 getkey __P((SCR *, CH *, u_int));
28 static int getkeyword __P((SCR *, EXF *, VICMDARG *, u_int));
29 static int getmotion __P((SCR *, EXF *,
30 VICMDARG *, VICMDARG *, MARK *, MARK *));
33 * Side-effect:
34 * The dot structure can be set by the underlying vi functions,
35 * see v_Put() and v_put().
37 #define DOT (&VIP(sp)->sdot)
38 #define DOTMOTION (&VIP(sp)->sdotmotion)
41 * vi --
42 * Main vi command loop.
44 int
45 vi(sp, ep)
46 SCR *sp;
47 EXF *ep;
49 MARK abs, fm, tm, m;
50 VICMDARG cmd, *vp;
51 u_int flags, saved_mode;
52 int comcount, eval;
54 /* Start vi. */
55 if (v_init(sp, ep))
56 return (1);
58 /* Paint the screen. */
59 if (sp->s_refresh(sp, ep)) {
60 (void)v_end(sp);
61 return (1);
64 /* Command initialization. */
65 memset(&cmd, 0, sizeof(VICMDARG));
67 for (eval = 0, vp = &cmd;;) {
68 if (!MAPPED_KEYS_WAITING(sp) && log_cursor(sp, ep))
69 goto err;
72 * We get a command, which may or may not have an associated
73 * motion. If it does, we get it too, calling its underlying
74 * function to get the resulting mark. We then call the
75 * command setting the cursor to the resulting mark.
77 if (getcmd(sp, ep, DOT, vp, NULL, &comcount))
78 goto err;
81 * Historical practice: if a dot command gets a new count,
82 * any motion component goes away, i.e. "d3w2." deletes a
83 * total of 5 words.
85 if (F_ISSET(vp, VC_ISDOT) && comcount)
86 DOTMOTION->count = 1;
88 /* Get any associated keyword. */
89 flags = vp->kp->flags;
90 if (LF_ISSET(V_KEYNUM | V_KEYW) &&
91 getkeyword(sp, ep, vp, flags))
92 goto err;
94 /* If a non-relative movement, copy the future absolute mark. */
95 if (LF_ISSET(V_ABS)) {
96 abs.lno = sp->lno;
97 abs.cno = sp->cno;
101 * Do any required motion; getmotion sets the from MARK
102 * and the line mode flag.
104 if (LF_ISSET(V_MOTION)) {
105 if (getmotion(sp, ep, DOTMOTION, vp, &fm, &tm))
106 goto err;
107 } else {
109 * Set everything to the current cursor position.
110 * Line commands (ex: Y) default to the current line.
112 tm.lno = fm.lno = sp->lno;
113 tm.cno = fm.cno = sp->cno;
116 * Set line mode flag, for example, "yy".
118 * If a count is set, we set the to MARK here relative
119 * to the cursor/from MARK. This is done for commands
120 * that take both counts and motions, i.e. "4yy" and
121 * "y%" -- there's no way the command can known which
122 * the user did, so we have to do it here. There are
123 * other commands that are line mode commands and take
124 * counts ("#G", "#H") and for which this calculation
125 * is either meaningless or wrong. Each command must
126 * do its own validity checking of the value.
128 if (F_ISSET(vp->kp, V_LMODE)) {
129 F_SET(vp, VC_LMODE);
130 if (F_ISSET(vp, VC_C1SET)) {
131 tm.lno = sp->lno + vp->count - 1;
132 tm.cno = sp->cno;
137 /* Increment the command count. */
138 ++sp->ccnt;
141 * Call the function. Set the return cursor to the current
142 * cursor position first -- the underlying routines don't
143 * bother to do the work if it doesn't move.
145 m.lno = sp->lno;
146 m.cno = sp->cno;
147 saved_mode = F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE);
148 if ((vp->kp->func)(sp, ep, vp, &fm, &tm, &m))
149 goto err;
150 #ifdef DEBUG
151 /* Make sure no function left the temporary space locked. */
152 if (F_ISSET(sp->gp, G_TMP_INUSE)) {
153 msgq(sp, M_ERR,
154 "Error: vi: temporary buffer not released.");
155 return (1);
157 #endif
159 * If that command took us out of vi or changed the screen,
160 * then exit the loop without further action.
162 if (saved_mode != F_ISSET(sp, S_SCREENS | S_MAJOR_CHANGE))
163 break;
165 /* Set the absolute mark. */
166 if (LF_ISSET(V_ABS) && mark_set(sp, ep, ABSMARK1, &abs, 1))
167 goto err;
169 /* Set the dot command structure. */
170 if (LF_ISSET(V_DOT)) {
171 *DOT = cmd;
172 F_SET(DOT, VC_ISDOT);
174 * If a count was supplied for both the command and
175 * its motion, the count was used only for the motion.
176 * Turn the count back on for the dot structure.
178 if (F_ISSET(vp, VC_C1RESET))
179 F_SET(DOT, VC_C1SET);
183 * Some vi row movements are "attracted" to the last position
184 * set, i.e. the V_RCM commands are moths to the V_RCM_SET
185 * commands' candle. It's broken into two parts. Here we deal
186 * with the command flags. In sp->relative(), we deal with the
187 * screen flags. If the movement is to the EOL the vi command
188 * handles it. If it's to the beginning, we handle it here.
190 * Note, some commands (e.g. _, ^) don't set the V_RCM_SETFNB
191 * flag, but do the work themselves. The reason is that they
192 * have to modify the column in case they're being used as a
193 * motion component. Other similar commands (e.g. +, -) don't
194 * have to modify the column because they are always line mode
195 * operations when used as motions, so the column number isn't
196 * of any interest.
198 * Does this totally violate the screen and editor layering?
199 * You betcha. As they say, if you think you understand it,
200 * you don't.
202 switch (LF_ISSET(V_RCM | V_RCM_SETFNB |
203 V_RCM_SETLAST | V_RCM_SETLFNB | V_RCM_SETNNB)) {
204 case 0:
205 break;
206 case V_RCM:
207 m.cno = sp->s_relative(sp, ep, m.lno);
208 break;
209 case V_RCM_SETLAST:
210 sp->rcmflags = RCM_LAST;
211 break;
212 case V_RCM_SETLFNB:
213 if (fm.lno != m.lno) {
214 if (nonblank(sp, ep, m.lno, &m.cno))
215 goto err;
216 sp->rcmflags = RCM_FNB;
218 break;
219 case V_RCM_SETFNB:
220 m.cno = 0;
221 /* FALLTHROUGH */
222 case V_RCM_SETNNB:
223 if (nonblank(sp, ep, m.lno, &m.cno))
224 goto err;
225 sp->rcmflags = RCM_FNB;
226 break;
227 default:
228 abort();
231 /* Update the cursor. */
232 sp->lno = m.lno;
233 sp->cno = m.cno;
235 if (!MAPPED_KEYS_WAITING(sp)) {
236 (void)msg_rpt(sp, 1);
238 if (0)
239 err: term_map_flush(sp, "Vi error");
242 /* Refresh the screen. */
243 if (sp->s_refresh(sp, ep)) {
244 eval = 1;
245 break;
248 /* Set the new favorite position. */
249 if (LF_ISSET(V_RCM_SET)) {
250 sp->rcmflags = 0;
251 (void)sp->s_column(sp, ep, &sp->rcm);
255 return (v_end(sp) || eval);
258 #define KEY(key, map) { \
259 if (getkey(sp, &ikey, map)) \
260 return (1); \
261 key = ikey.ch; \
265 * getcmd --
267 * The command structure for vi is less complex than ex (and don't think
268 * I'm not grateful!) The command syntax is:
270 * [count] [buffer] [count] key [[motion] | [buffer] [character]]
272 * and there are several special cases. The motion value is itself a vi
273 * command, with the syntax:
275 * [count] key [character]
277 static int
278 getcmd(sp, ep, dp, vp, ismotion, comcountp)
279 SCR *sp;
280 EXF *ep;
281 VICMDARG *dp, *vp;
282 VICMDARG *ismotion; /* Previous key if getting motion component. */
283 int *comcountp;
285 VIKEYS const *kp;
286 u_int flags;
287 CH ikey;
288 CHAR_T key;
290 /* Refresh the command structure. */
291 memset(&vp->vp_startzero, 0,
292 (char *)&vp->vp_endzero - (char *)&vp->vp_startzero);
294 /* An escape bells the user if in command mode. */
295 if (getkey(sp, &ikey, TXT_MAPCOMMAND)) {
296 if (ikey.value == K_ESCAPE && ismotion == NULL)
297 msgq(sp, M_BERR, "Already in command mode");
298 return (1);
301 key = ikey.ch;
302 if (key > MAXVIKEY) {
303 msgq(sp, M_BERR, "%s isn't a vi command", charname(sp, key));
304 return (1);
307 /* Pick up optional buffer. */
308 if (key == '"') {
309 KEY(vp->buffer, 0);
310 F_SET(vp, VC_BUFFER);
311 KEY(key, TXT_MAPCOMMAND);
315 * Pick up optional count, where a leading 0 is not a count,
316 * it's a command.
318 if (isdigit(key) && key != '0') {
319 if (getcount(sp, key, &vp->count))
320 return (1);
321 F_SET(vp, VC_C1SET);
322 *comcountp = 1;
323 KEY(key, TXT_MAPCOMMAND);
324 } else
325 *comcountp = 0;
327 /* Pick up optional buffer. */
328 if (key == '"') {
329 if (F_ISSET(vp, VC_BUFFER)) {
330 msgq(sp, M_ERR, "Only one buffer can be specified.");
331 return (1);
333 KEY(vp->buffer, 0);
334 F_SET(vp, VC_BUFFER);
335 KEY(key, TXT_MAPCOMMAND);
339 * Find the command. The only legal command with no underlying
340 * function is dot.
342 kp = vp->kp = &vikeys[vp->key = key];
343 if (kp->func == NULL) {
344 if (key != '.') {
345 msgq(sp, M_ERR,
346 "%s isn't a command", charname(sp, key));
347 return (1);
350 /* If called for a motion command, stop now. */
351 if (dp == NULL)
352 goto usage;
354 /* A repeatable command must have been executed. */
355 if (!F_ISSET(dp, VC_ISDOT)) {
356 msgq(sp, M_ERR, "No command to repeat.");
357 return (1);
361 * !!!
362 * If a '.' is immediately entered after an undo command, we
363 * replay the log instead of redoing the last command. This
364 * is necessary because 'u' can't set the dot command -- see
365 * vi/v_undo.c:v_undo for details.
367 if (VIP(sp)->u_ccnt == sp->ccnt) {
368 vp->kp = &vikeys['u'];
369 F_SET(vp, VC_ISDOT);
370 return (0);
373 /* Set new count/buffer, if any, and return. */
374 if (F_ISSET(vp, VC_C1SET)) {
375 F_SET(dp, VC_C1SET);
376 dp->count = vp->count;
378 if (F_ISSET(vp, VC_BUFFER))
379 dp->buffer = vp->buffer;
380 *vp = *dp;
381 return (0);
384 flags = kp->flags;
386 /* Check for illegal count. */
387 if (F_ISSET(vp, VC_C1SET) && !LF_ISSET(V_CNT))
388 goto usage;
390 /* Illegal motion command. */
391 if (ismotion == NULL) {
392 /* Illegal buffer. */
393 if (!LF_ISSET(V_OBUF) && F_ISSET(vp, VC_BUFFER))
394 goto usage;
396 /* Required buffer. */
397 if (LF_ISSET(V_RBUF))
398 KEY(vp->buffer, 0);
401 * Special case: '[', ']' and 'Z' commands. Doesn't the
402 * fact that the *single* characters don't mean anything
403 * but the *doubled* characters do just frost your shorts?
405 if (vp->key == '[' || vp->key == ']' || vp->key == 'Z') {
406 KEY(key, TXT_MAPCOMMAND);
407 if (vp->key != key)
408 goto usage;
410 /* Special case: 'z' command. */
411 if (vp->key == 'z') {
412 KEY(vp->character, 0);
413 if (isdigit(vp->character)) {
414 if (getcount(sp, vp->character, &vp->count2))
415 return (1);
416 F_SET(vp, VC_C2SET);
417 KEY(vp->character, 0);
423 * Commands that have motion components can be doubled to
424 * imply the current line.
426 else if (ismotion->key != key && !LF_ISSET(V_MOVE)) {
427 usage: msgq(sp, M_ERR, "Usage: %s", ismotion != NULL ?
428 vikeys[ismotion->key].usage : kp->usage);
429 return (1);
432 /* Required character. */
433 if (LF_ISSET(V_CHAR))
434 KEY(vp->character, 0);
436 return (0);
440 * getmotion --
442 * Get resulting motion mark.
444 static int
445 getmotion(sp, ep, dm, vp, fm, tm)
446 SCR *sp;
447 EXF *ep;
448 VICMDARG *dm, *vp;
449 MARK *fm, *tm;
451 MARK m;
452 VICMDARG motion;
453 u_long cnt;
454 int notused;
456 /* If '.' command, use the dot motion, else get the motion command. */
457 if (F_ISSET(vp, VC_ISDOT)) {
458 motion = *dm;
459 F_SET(&motion, VC_ISDOT);
460 } else if (getcmd(sp, ep, NULL, &motion, vp, &notused))
461 return (1);
464 * A count may be provided both to the command and to the motion, in
465 * which case the count is multiplicative. For example, "3y4y" is the
466 * same as "12yy". This count is provided to the motion command and
467 * not to the regular function.
469 cnt = motion.count = F_ISSET(&motion, VC_C1SET) ? motion.count : 1;
470 if (F_ISSET(vp, VC_C1SET)) {
471 motion.count *= vp->count;
472 F_SET(&motion, VC_C1SET);
475 * Set flags to restore the original values of the command
476 * structure so dot commands can change the count values,
477 * e.g. "2dw" "3." deletes a total of five words.
479 F_CLR(vp, VC_C1SET);
480 F_SET(vp, VC_C1RESET);
484 * Some commands can be repeated to indicate the current line. In
485 * this case, or if the command is a "line command", set the flags
486 * appropriately. If not a doubled command, run the function to get
487 * the resulting mark.
489 if (vp->key == motion.key) {
490 F_SET(vp, VC_LMODE);
493 * Set the end of the command; the column is after the line.
495 * If the current line is missing, i.e. the file is empty,
496 * historic vi permitted a "cc" or "!!" command to insert
497 * text.
499 tm->lno = sp->lno + motion.count - 1;
500 if (file_gline(sp, ep, tm->lno, &tm->cno) == NULL) {
501 if (tm->lno != 1 || vp->key != 'c' && vp->key != '!') {
502 m.lno = sp->lno;
503 m.cno = sp->cno;
504 v_eof(sp, ep, &m);
505 return (1);
507 tm->cno = 0;
510 /* Set the origin of the command. */
511 fm->lno = sp->lno;
512 fm->cno = 0;
513 } else {
515 * Motion commands change the underlying movement (*snarl*).
516 * For example, "l" is illegal at the end of a line, but "dl"
517 * is not. Set flags so the function knows the situation.
519 F_SET(&motion, vp->kp->flags & VC_COMMASK);
522 * Everything starts at the current position. This permits
523 * commands like 'j' and 'k', that are line oriented motions
524 * and have special cursor suck semantics when they are used
525 * as standalone commands, to ignore column positioning.
527 fm->lno = tm->lno = sp->lno;
528 fm->cno = tm->cno = sp->cno;
529 if ((motion.kp->func)(sp, ep, &motion, fm, NULL, tm))
530 return (1);
533 * If the underlying motion was a line motion, set the flag
534 * in the command structure. Underlying commands can also
535 * flag the movement as a line motion (see v_sentence).
537 if (F_ISSET(motion.kp, V_LMODE) || F_ISSET(&motion, VC_LMODE))
538 F_SET(vp, VC_LMODE);
541 * If the motion is in the reverse direction, switch the from
542 * and to MARK's so that it's always in a forward direction.
543 * Because the motion is always from the from MARK to, but not
544 * including, the to MARK, the function may have modified the
545 * from MARK, so that it gets the one-past-the-place semantics
546 * we use; see v_match() for an example. Also set a flag so
547 * that the underlying function knows that we did this; v_yank,
548 * for example, has to know so it gets the return cursor right.
550 if (tm->lno < fm->lno ||
551 tm->lno == fm->lno && tm->cno < fm->cno) {
552 m = *fm;
553 *fm = *tm;
554 *tm = m;
555 F_SET(vp, VC_REVMOVE);
560 * If the command sets dot, save the motion structure. The
561 * motion count was changed above and needs to be reset, that's
562 * why this is done here, and not in the calling routine.
564 if (F_ISSET(vp->kp, V_DOT)) {
565 *dm = motion;
566 dm->count = cnt;
569 /* Let the underlying function know what motion command was used. */
570 vp->mkp = motion.kp;
571 return (0);
574 #define innum(c) (isdigit(c) || strchr("abcdefABCDEF", c))
577 * getkeyword --
578 * Get the "word" the cursor is on.
580 static int
581 getkeyword(sp, ep, kp, flags)
582 SCR *sp;
583 EXF *ep;
584 VICMDARG *kp;
585 u_int flags;
587 recno_t lno;
588 size_t beg, end, len;
589 char *p;
591 if ((p = file_gline(sp, ep, sp->lno, &len)) == NULL) {
592 if (file_lline(sp, ep, &lno))
593 return (1);
594 if (lno == 0)
595 v_eof(sp, ep, NULL);
596 else
597 GETLINE_ERR(sp, sp->lno);
598 return (1);
600 beg = sp->cno;
602 /* May not be a keyword at all. */
603 if (p == NULL || len == 0 ||
604 LF_ISSET(V_KEYW) && !inword(p[beg]) ||
605 LF_ISSET(V_KEYNUM) && !innum(p[beg]) &&
606 p[beg] != '-' && p[beg] != '+') {
607 noword: msgq(sp, M_BERR, "Cursor not in a %s",
608 LF_ISSET(V_KEYW) ? "word" : "number");
609 return (1);
613 * !!!
614 * Find the beginning/end of the keyword. Keywords (V_KEYW) are
615 * used for cursor-word searching and for tags. Historical vi
616 * only used the word in a tag search from the cursor to the end
617 * of the word, i.e. if the cursor was on the 'b' in " abc ", the
618 * tag was "bc". For no particular reason, we make cursor word
619 * searches follow the same rule.
621 if (beg != 0)
622 if (LF_ISSET(V_KEYW)) {
623 #ifdef MOVE_TO_KEYWORD_BEGINNING
624 for (;;) {
625 --beg;
626 if (!inword(p[beg])) {
627 ++beg;
628 break;
630 if (beg == 0)
631 break;
633 #endif
634 } else {
635 for (;;) {
636 --beg;
637 if (!innum(p[beg])) {
638 if (beg > 0 && p[beg - 1] == '0' &&
639 (p[beg] == 'X' || p[beg] == 'x'))
640 --beg;
641 else
642 ++beg;
643 break;
645 if (beg == 0)
646 break;
649 /* Skip possible leading sign. */
650 if (beg != 0 && p[beg] != '0' &&
651 (p[beg - 1] == '+' || p[beg - 1] == '-'))
652 --beg;
655 if (LF_ISSET(V_KEYW)) {
656 for (end = sp->cno; ++end < len && inword(p[end]););
657 --end;
658 } else {
659 for (end = sp->cno; ++end < len;) {
660 if (p[end] == 'X' || p[end] == 'x') {
661 if (end != beg + 1 || p[beg] != '0')
662 break;
663 continue;
665 if (!innum(p[end]))
666 break;
669 /* Just a sign isn't a number. */
670 if (end == beg && (p[beg] == '+' || p[beg] == '-'))
671 goto noword;
672 --end;
676 * Getting a keyword implies moving the cursor to its beginning.
677 * Refresh now.
679 if (beg != sp->cno) {
680 sp->cno = beg;
681 sp->s_refresh(sp, ep);
685 * XXX
686 * 8-bit clean problem. Numeric keywords are handled using strtol(3)
687 * and friends. This would have to be fixed in v_increment and here
688 * to not depend on a trailing NULL.
690 len = (end - beg) + 2; /* XXX */
691 kp->klen = (end - beg) + 1;
692 BINC_RET(sp, kp->keyword, kp->kbuflen, len);
693 memmove(kp->keyword, p + beg, kp->klen);
694 kp->keyword[kp->klen] = '\0'; /* XXX */
695 return (0);
699 * getcount --
700 * Return the next count.
702 static inline int
703 getcount(sp, fkey, countp)
704 SCR *sp;
705 ARG_CHAR_T fkey;
706 u_long *countp;
708 u_long count, tc;
709 CH ikey;
711 ikey.ch = fkey;
712 count = tc = 0;
713 do {
714 /* Assume that overflow results in a smaller number. */
715 tc = count * 10 + ikey.ch - '0';
716 if (count > tc) {
717 /* Toss to the next non-digit. */
718 do {
719 if (getkey(sp, &ikey,
720 TXT_MAPCOMMAND | TXT_MAPNODIGIT))
721 return (1);
722 } while (isdigit(ikey.ch));
723 msgq(sp, M_ERR, "Number larger than %lu", ULONG_MAX);
724 return (1);
726 count = tc;
727 if (getkey(sp, &ikey, TXT_MAPCOMMAND | TXT_MAPNODIGIT))
728 return (1);
729 } while (isdigit(ikey.ch));
730 *countp = count;
731 return (0);
735 * getkey --
736 * Return the next key.
738 static inline int
739 getkey(sp, ikeyp, map)
740 SCR *sp;
741 CH *ikeyp;
742 u_int map;
744 switch (term_key(sp, ikeyp, map)) {
745 case INP_OK:
746 break;
747 case INP_EOF:
748 F_SET(sp, S_EXIT_FORCE);
749 /* FALLTHROUGH */
750 case INP_ERR:
751 return (1);
753 return (ikeyp->value == K_ESCAPE);