source: trunk/third/nvi/vi/vi.c @ 14302

Revision 14302, 30.3 KB checked in by ghudson, 25 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r14301, which included commits to RCS files with non-trunk default branches.
Line 
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#ifndef lint
13static const char sccsid[] = "@(#)vi.c  10.57 (Berkeley) 10/13/96";
14#endif /* not lint */
15
16#include <sys/types.h>
17#include <sys/queue.h>
18#include <sys/time.h>
19
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>
28
29#include "../common/common.h"
30#include "vi.h"
31
32typedef enum {
33        GC_ERR, GC_ERR_NOFLUSH, GC_EVENT, GC_FATAL, GC_INTERRUPT, GC_OK
34} gcret_t;
35
36static VIKEYS const
37               *v_alias __P((SCR *, VICMD *, VIKEYS const *));
38static gcret_t  v_cmd __P((SCR *, VICMD *, VICMD *, VICMD *, int *, int *));
39static int      v_count __P((SCR *, ARG_CHAR_T, u_long *));
40static void     v_dtoh __P((SCR *));
41static int      v_init __P((SCR *));
42static gcret_t  v_key __P((SCR *, int, EVENT *, u_int32_t));
43static int      v_keyword __P((SCR *));
44static int      v_motion __P((SCR *, VICMD *, VICMD *, int *));
45
46#if defined(DEBUG) && defined(COMLOG)
47static void     v_comlog __P((SCR *, VICMD *));
48#endif
49
50/*
51 * Side-effect:
52 *      The dot structure can be set by the underlying vi functions,
53 *      see v_Put() and v_put().
54 */
55#define DOT             (&VIP(sp)->sdot)
56#define DOTMOTION       (&VIP(sp)->sdotmotion)
57
58/*
59 * vi --
60 *      Main vi command loop.
61 *
62 * PUBLIC: int vi __P((SCR **));
63 */
64int
65vi(spp)
66        SCR **spp;
67{
68        GS *gp;
69        MARK abs;
70        SCR *next, *sp;
71        VICMD cmd, *vp;
72        VI_PRIVATE *vip;
73        int comcount, mapped, rval;
74
75        /* Get the first screen. */
76        sp = *spp;
77        gp = sp->gp;
78
79        /* Initialize the command structure. */
80        vp = &cmd;
81        memset(vp, 0, sizeof(VICMD));
82
83        /* Reset strange attraction. */
84        F_SET(vp, VM_RCM_SET);
85
86        /* Initialize the vi screen. */
87        if (v_init(sp))
88                return (1);
89
90        /* Set the focus. */
91        (void)sp->gp->scr_rename(sp, sp->frp->name, 1);
92
93        for (vip = VIP(sp), rval = 0;;) {
94                /* Resolve messages. */
95                if (!MAPPED_KEYS_WAITING(sp) && vs_resolve(sp, NULL, 0))
96                        goto ret;
97
98                /*
99                 * If not skipping a refresh, return to command mode and
100                 * refresh the screen.
101                 */
102                if (F_ISSET(vip, VIP_S_REFRESH))
103                        F_CLR(vip, VIP_S_REFRESH);
104                else {
105                        sp->showmode = SM_COMMAND;
106                        if (vs_refresh(sp, 0))
107                                goto ret;
108                }
109
110                /* Set the new favorite position. */
111                if (F_ISSET(vp, VM_RCM_SET | VM_RCM_SETFNB | VM_RCM_SETNNB)) {
112                        F_CLR(vip, VIP_RCM_LAST);
113                        (void)vs_column(sp, &sp->rcm);
114                }
115
116                /*
117                 * If not currently in a map, log the cursor position,
118                 * and set a flag so that this command can become the
119                 * DOT command.
120                 */
121                if (MAPPED_KEYS_WAITING(sp))
122                        mapped = 1;
123                else {
124                        if (log_cursor(sp))
125                                goto err;
126                        mapped = 0;
127                }
128
129                /*
130                 * There may be an ex command waiting, and we returned here
131                 * only because we exited a screen or file.  In this case,
132                 * we simply go back into the ex parser.
133                 */
134                if (EXCMD_RUNNING(gp)) {
135                        vp->kp = &vikeys[':'];
136                        goto ex_continue;
137                }
138
139                /* Refresh the command structure. */
140                memset(vp, 0, sizeof(VICMD));
141
142                /*
143                 * We get a command, which may or may not have an associated
144                 * motion.  If it does, we get it too, calling its underlying
145                 * function to get the resulting mark.  We then call the
146                 * command setting the cursor to the resulting mark.
147                 *
148                 * !!!
149                 * Vi historically flushed mapped characters on error, but
150                 * entering extra <escape> characters at the beginning of
151                 * a map wasn't considered an error -- in fact, users would
152                 * put leading <escape> characters in maps to clean up vi
153                 * state before the map was interpreted.  Beauty!
154                 */
155                switch (v_cmd(sp, DOT, vp, NULL, &comcount, &mapped)) {
156                case GC_ERR:
157                        goto err;
158                case GC_ERR_NOFLUSH:
159                        goto gc_err_noflush;
160                case GC_EVENT:
161                        if (v_event_exec(sp, vp))
162                                goto err;
163                        goto gc_event;
164                case GC_FATAL:
165                        goto ret;
166                case GC_INTERRUPT:
167                        goto intr;
168                case GC_OK:
169                        break;
170                }
171
172                /* Check for security setting. */
173                if (F_ISSET(vp->kp, V_SECURE) && O_ISSET(sp, O_SECURE)) {
174                        ex_emsg(sp, KEY_NAME(sp, vp->key), EXM_SECURE);
175                        goto err;
176                }
177
178                /*
179                 * Historical practice: if a dot command gets a new count,
180                 * any motion component goes away, i.e. "d3w2." deletes a
181                 * total of 5 words.
182                 */
183                if (F_ISSET(vp, VC_ISDOT) && comcount)
184                        DOTMOTION->count = 1;
185
186                /* Copy the key flags into the local structure. */
187                F_SET(vp, vp->kp->flags);
188
189                /* Prepare to set the previous context. */
190                if (F_ISSET(vp, V_ABS | V_ABS_C | V_ABS_L)) {
191                        abs.lno = sp->lno;
192                        abs.cno = sp->cno;
193                }
194
195                /*
196                 * Set the three cursor locations to the current cursor.  The
197                 * underlying routines don't bother if the cursor doesn't move.
198                 * This also handles line commands (e.g. Y) defaulting to the
199                 * current line.
200                 */
201                vp->m_start.lno = vp->m_stop.lno = vp->m_final.lno = sp->lno;
202                vp->m_start.cno = vp->m_stop.cno = vp->m_final.cno = sp->cno;
203
204                /*
205                 * Do any required motion; v_motion sets the from MARK and the
206                 * line mode flag, as well as the VM_RCM flags.
207                 */
208                if (F_ISSET(vp, V_MOTION) &&
209                    v_motion(sp, DOTMOTION, vp, &mapped)) {
210                        if (INTERRUPTED(sp))
211                                goto intr;
212                        goto err;
213                }
214
215                /*
216                 * If a count is set and the command is line oriented, set the
217                 * to MARK here relative to the cursor/from MARK.  This is for
218                 * commands that take both counts and motions, i.e. "4yy" and
219                 * "y%".  As there's no way the command can know which the user
220                 * did, we have to do it here.  (There are commands that are
221                 * line oriented and that take counts ("#G", "#H"), for which
222                 * this calculation is either completely meaningless or wrong.
223                 * Each command must validate the value for itself.
224                 */
225                if (F_ISSET(vp, VC_C1SET) && F_ISSET(vp, VM_LMODE))
226                        vp->m_stop.lno += vp->count - 1;
227
228                /* Increment the command count. */
229                ++sp->ccnt;
230
231#if defined(DEBUG) && defined(COMLOG)
232                v_comlog(sp, vp);
233#endif
234                /* Call the function. */
235ex_continue:    if (vp->kp->func(sp, vp))
236                        goto err;
237gc_event:
238#ifdef DEBUG
239                /* Make sure no function left the temporary space locked. */
240                if (F_ISSET(gp, G_TMP_INUSE)) {
241                        F_CLR(gp, G_TMP_INUSE);
242                        msgq(sp, M_ERR,
243                            "232|vi: temporary buffer not released");
244                }
245#endif
246                /*
247                 * If we're exiting this screen, move to the next one, or, if
248                 * there aren't any more, return to the main editor loop.  The
249                 * ordering is careful, don't discard the contents of sp until
250                 * the end.
251                 */
252                if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) {
253                        if (file_end(sp, NULL, F_ISSET(sp, SC_EXIT_FORCE)))
254                                goto ret;
255                        if (vs_discard(sp, &next))
256                                goto ret;
257                        if (next == NULL && vs_swap(sp, &next, NULL))
258                                goto ret;
259                        *spp = next;
260                        if (screen_end(sp))
261                                goto ret;
262                        if (next == NULL)
263                                break;
264
265                        /* Switch screens, change focus. */
266                        sp = next;
267                        vip = VIP(sp);
268                        (void)sp->gp->scr_rename(sp, sp->frp->name, 1);
269
270                        /* Don't trust the cursor. */
271                        F_SET(vip, VIP_CUR_INVALID);
272
273                        continue;
274                }
275
276                /*
277                 * Set the dot command structure.
278                 *
279                 * !!!
280                 * Historically, commands which used mapped keys did not
281                 * set the dot command, with the exception of the text
282                 * input commands.
283                 */
284                if (F_ISSET(vp, V_DOT) && !mapped) {
285                        *DOT = cmd;
286                        F_SET(DOT, VC_ISDOT);
287
288                        /*
289                         * If a count was supplied for both the command and
290                         * its motion, the count was used only for the motion.
291                         * Turn the count back on for the dot structure.
292                         */
293                        if (F_ISSET(vp, VC_C1RESET))
294                                F_SET(DOT, VC_C1SET);
295
296                        /* VM flags aren't retained. */
297                        F_CLR(DOT, VM_COMMASK | VM_RCM_MASK);
298                }
299
300                /*
301                 * Some vi row movements are "attracted" to the last position
302                 * set, i.e. the VM_RCM commands are moths to the VM_RCM_SET
303                 * commands' candle.  If the movement is to the EOL the vi
304                 * command handles it.  If it's to the beginning, we handle it
305                 * here.
306                 *
307                 * Note, some commands (e.g. _, ^) don't set the VM_RCM_SETFNB
308                 * flag, but do the work themselves.  The reason is that they
309                 * have to modify the column in case they're being used as a
310                 * motion component.  Other similar commands (e.g. +, -) don't
311                 * have to modify the column because they are always line mode
312                 * operations when used as motions, so the column number isn't
313                 * of any interest.
314                 *
315                 * Does this totally violate the screen and editor layering?
316                 * You betcha.  As they say, if you think you understand it,
317                 * you don't.
318                 */
319                switch (F_ISSET(vp, VM_RCM_MASK)) {
320                case 0:
321                case VM_RCM_SET:
322                        break;
323                case VM_RCM:
324                        vp->m_final.cno = vs_rcm(sp,
325                            vp->m_final.lno, F_ISSET(vip, VIP_RCM_LAST));
326                        break;
327                case VM_RCM_SETLAST:
328                        F_SET(vip, VIP_RCM_LAST);
329                        break;
330                case VM_RCM_SETFNB:
331                        vp->m_final.cno = 0;
332                        /* FALLTHROUGH */
333                case VM_RCM_SETNNB:
334                        if (nonblank(sp, vp->m_final.lno, &vp->m_final.cno))
335                                goto err;
336                        break;
337                default:
338                        abort();
339                }
340
341                /* Update the cursor. */
342                sp->lno = vp->m_final.lno;
343                sp->cno = vp->m_final.cno;
344
345                /*
346                 * Set the absolute mark -- set even if a tags or similar
347                 * command, since the tag may be moving to the same file.
348                 */
349                if ((F_ISSET(vp, V_ABS) ||
350                    F_ISSET(vp, V_ABS_L) && sp->lno != abs.lno ||
351                    F_ISSET(vp, V_ABS_C) &&
352                    (sp->lno != abs.lno || sp->cno != abs.cno)) &&
353                    mark_set(sp, ABSMARK1, &abs, 1))
354                        goto err;
355
356                if (0) {
357err:                    if (v_event_flush(sp, CH_MAPPED))
358                                msgq(sp, M_BERR,
359                            "110|Vi command failed: mapped keys discarded");
360                }
361
362                /*
363                 * Check and clear interrupts.  There's an obvious race, but
364                 * it's not worth fixing.
365                 */
366gc_err_noflush: if (INTERRUPTED(sp)) {
367intr:                   CLR_INTERRUPT(sp);
368                        if (v_event_flush(sp, CH_MAPPED))
369                                msgq(sp, M_ERR,
370                                    "231|Interrupted: mapped keys discarded");
371                        else
372                                msgq(sp, M_ERR, "236|Interrupted");
373                }
374
375                /* If the last command switched screens, update. */
376                if (F_ISSET(sp, SC_SSWITCH)) {
377                        F_CLR(sp, SC_SSWITCH);
378
379                        /*
380                         * If the current screen is still displayed, it will
381                         * need a new status line.
382                         */
383                        F_SET(sp, SC_STATUS);
384
385                        /* Switch screens, change focus. */
386                        sp = sp->nextdisp;
387                        vip = VIP(sp);
388                        (void)sp->gp->scr_rename(sp, sp->frp->name, 1);
389
390                        /* Don't trust the cursor. */
391                        F_SET(vip, VIP_CUR_INVALID);
392
393                        /* Refresh so we can display messages. */
394                        if (vs_refresh(sp, 1))
395                                return (1);
396                }
397
398                /* If the last command switched files, change focus. */
399                if (F_ISSET(sp, SC_FSWITCH)) {
400                        F_CLR(sp, SC_FSWITCH);
401                        (void)sp->gp->scr_rename(sp, sp->frp->name, 1);
402                }
403
404                /* If leaving vi, return to the main editor loop. */
405                if (F_ISSET(gp, G_SRESTART) || F_ISSET(sp, SC_EX)) {
406                        *spp = sp;
407                        v_dtoh(sp);
408                        break;
409                }
410        }
411        if (0)
412ret:            rval = 1;
413        return (rval);
414}
415
416#define KEY(key, ec_flags) {                                            \
417        if ((gcret = v_key(sp, 0, &ev, ec_flags)) != GC_OK)             \
418                return (gcret);                                         \
419        if (ev.e_value == K_ESCAPE)                                     \
420                goto esc;                                               \
421        if (F_ISSET(&ev.e_ch, CH_MAPPED))                               \
422                *mappedp = 1;                                           \
423        key = ev.e_c;                                                   \
424}
425
426/*
427 * The O_TILDEOP option makes the ~ command take a motion instead
428 * of a straight count.  This is the replacement structure we use
429 * instead of the one currently in the VIKEYS table.
430 *
431 * XXX
432 * This should probably be deleted -- it's not all that useful, and
433 * we get help messages wrong.
434 */
435VIKEYS const tmotion = {
436        v_mulcase,      V_CNT|V_DOT|V_MOTION|VM_RCM_SET,
437        "[count]~[count]motion",
438        " ~ change case to motion"
439};
440
441/*
442 * v_cmd --
443 *
444 * The command structure for vi is less complex than ex (and don't think
445 * I'm not grateful!)  The command syntax is:
446 *
447 *      [count] [buffer] [count] key [[motion] | [buffer] [character]]
448 *
449 * and there are several special cases.  The motion value is itself a vi
450 * command, with the syntax:
451 *
452 *      [count] key [character]
453 */
454static gcret_t
455v_cmd(sp, dp, vp, ismotion, comcountp, mappedp)
456        SCR *sp;
457        VICMD *dp, *vp;
458        VICMD *ismotion;        /* Previous key if getting motion component. */
459        int *comcountp, *mappedp;
460{
461        enum { COMMANDMODE, ISPARTIAL, NOTPARTIAL } cpart;
462        EVENT ev;
463        VIKEYS const *kp;
464        gcret_t gcret;
465        u_int flags;
466        CHAR_T key;
467        char *s;
468
469        /*
470         * Get a key.
471         *
472         * <escape> cancels partial commands, i.e. a command where at least
473         * one non-numeric character has been entered.  Otherwise, it beeps
474         * the terminal.
475         *
476         * !!!
477         * POSIX 1003.2-1992 explicitly disallows cancelling commands where
478         * all that's been entered is a number, requiring that the terminal
479         * be alerted.
480         */
481        cpart = ismotion == NULL ? COMMANDMODE : ISPARTIAL;
482        if ((gcret =
483            v_key(sp, ismotion == NULL, &ev, EC_MAPCOMMAND)) != GC_OK) {
484                if (gcret == GC_EVENT)
485                        vp->ev = ev;
486                return (gcret);
487        }
488        if (ev.e_value == K_ESCAPE)
489                goto esc;
490        if (F_ISSET(&ev.e_ch, CH_MAPPED))
491                *mappedp = 1;
492        key = ev.e_c;
493
494        if (ismotion == NULL)
495                cpart = NOTPARTIAL;
496
497        /* Pick up optional buffer. */
498        if (key == '"') {
499                cpart = ISPARTIAL;
500                if (ismotion != NULL) {
501                        v_emsg(sp, NULL, VIM_COMBUF);
502                        return (GC_ERR);
503                }
504                KEY(vp->buffer, 0);
505                F_SET(vp, VC_BUFFER);
506
507                KEY(key, EC_MAPCOMMAND);
508        }
509
510        /*
511         * Pick up optional count, where a leading 0 is not a count,
512         * it's a command.
513         */
514        if (isdigit(key) && key != '0') {
515                if (v_count(sp, key, &vp->count))
516                        return (GC_ERR);
517                F_SET(vp, VC_C1SET);
518                *comcountp = 1;
519
520                KEY(key, EC_MAPCOMMAND);
521        } else
522                *comcountp = 0;
523
524        /* Pick up optional buffer. */
525        if (key == '"') {
526                cpart = ISPARTIAL;
527                if (F_ISSET(vp, VC_BUFFER)) {
528                        msgq(sp, M_ERR, "234|Only one buffer may be specified");
529                        return (GC_ERR);
530                }
531                if (ismotion != NULL) {
532                        v_emsg(sp, NULL, VIM_COMBUF);
533                        return (GC_ERR);
534                }
535                KEY(vp->buffer, 0);
536                F_SET(vp, VC_BUFFER);
537
538                KEY(key, EC_MAPCOMMAND);
539        }
540
541        /* Check for an OOB command key. */
542        cpart = ISPARTIAL;
543        if (key > MAXVIKEY) {
544                v_emsg(sp, KEY_NAME(sp, key), VIM_NOCOM);
545                return (GC_ERR);
546        }
547        kp = &vikeys[vp->key = key];
548
549        /*
550         * !!!
551         * Historically, D accepted and then ignored a count.  Match it.
552         */
553        if (vp->key == 'D' && F_ISSET(vp, VC_C1SET)) {
554                *comcountp = 0;
555                vp->count = 0;
556                F_CLR(vp, VC_C1SET);
557        }
558
559        /* Check for command aliases. */
560        if (kp->func == NULL && (kp = v_alias(sp, vp, kp)) == NULL)
561                return (GC_ERR);
562
563        /* The tildeop option makes the ~ command take a motion. */
564        if (key == '~' && O_ISSET(sp, O_TILDEOP))
565                kp = &tmotion;
566
567        vp->kp = kp;
568
569        /*
570         * Find the command.  The only legal command with no underlying
571         * function is dot.  It's historic practice that <escape> doesn't
572         * just erase the preceding number, it beeps the terminal as well.
573         * It's a common problem, so just beep the terminal unless verbose
574         * was set.
575         */
576        if (kp->func == NULL) {
577                if (key != '.') {
578                        v_emsg(sp, KEY_NAME(sp, key),
579                            ev.e_value == K_ESCAPE ? VIM_NOCOM_B : VIM_NOCOM);
580                        return (GC_ERR);
581                }
582
583                /* If called for a motion command, stop now. */
584                if (dp == NULL)
585                        goto usage;
586
587                /*
588                 * !!!
589                 * If a '.' is immediately entered after an undo command, we
590                 * replay the log instead of redoing the last command.  This
591                 * is necessary because 'u' can't set the dot command -- see
592                 * vi/v_undo.c:v_undo for details.
593                 */
594                if (VIP(sp)->u_ccnt == sp->ccnt) {
595                        vp->kp = &vikeys['u'];
596                        F_SET(vp, VC_ISDOT);
597                        return (GC_OK);
598                }
599
600                /* Otherwise, a repeatable command must have been executed. */
601                if (!F_ISSET(dp, VC_ISDOT)) {
602                        msgq(sp, M_ERR, "208|No command to repeat");
603                        return (GC_ERR);
604                }
605
606                /* Set new count/buffer, if any, and return. */
607                if (F_ISSET(vp, VC_C1SET)) {
608                        F_SET(dp, VC_C1SET);
609                        dp->count = vp->count;
610                }
611                if (F_ISSET(vp, VC_BUFFER))
612                        dp->buffer = vp->buffer;
613
614                *vp = *dp;
615                return (GC_OK);
616        }
617
618        /* Set the flags based on the command flags. */
619        flags = kp->flags;
620
621        /* Check for illegal count. */
622        if (F_ISSET(vp, VC_C1SET) && !LF_ISSET(V_CNT))
623                goto usage;
624
625        /* Illegal motion command. */
626        if (ismotion == NULL) {
627                /* Illegal buffer. */
628                if (!LF_ISSET(V_OBUF) && F_ISSET(vp, VC_BUFFER))
629                        goto usage;
630
631                /* Required buffer. */
632                if (LF_ISSET(V_RBUF)) {
633                        KEY(vp->buffer, 0);
634                        F_SET(vp, VC_BUFFER);
635                }
636        }
637
638        /*
639         * Special case: '[', ']' and 'Z' commands.  Doesn't the fact that
640         * the *single* characters don't mean anything but the *doubled*
641         * characters do, just frost your shorts?
642         */
643        if (vp->key == '[' || vp->key == ']' || vp->key == 'Z') {
644                /*
645                 * Historically, half entered [[, ]] or Z commands weren't
646                 * cancelled by <escape>, the terminal was beeped instead.
647                 * POSIX.2-1992 probably didn't notice, and requires that
648                 * they be cancelled instead of beeping.  Seems fine to me.
649                 *
650                 * Don't set the EC_MAPCOMMAND flag, apparently ] is a popular
651                 * vi meta-character, and we don't want the user to wait while
652                 * we time out a possible mapping.  This *appears* to match
653                 * historic vi practice, but with mapping characters, you Just
654                 * Never Know.
655                 */
656                KEY(key, 0);
657
658                if (vp->key != key) {
659usage:                  if (ismotion == NULL)
660                                s = kp->usage;
661                        else if (ismotion->key == '~' && O_ISSET(sp, O_TILDEOP))
662                                s = tmotion.usage;
663                        else
664                                s = vikeys[ismotion->key].usage;
665                        v_emsg(sp, s, VIM_USAGE);
666                        return (GC_ERR);
667                }
668        }
669        /* Special case: 'z' command. */
670        if (vp->key == 'z') {
671                KEY(vp->character, 0);
672                if (isdigit(vp->character)) {
673                        if (v_count(sp, vp->character, &vp->count2))
674                                return (GC_ERR);
675                        F_SET(vp, VC_C2SET);
676                        KEY(vp->character, 0);
677                }
678        }
679
680        /*
681         * Commands that have motion components can be doubled to
682         * imply the current line.
683         */
684        if (ismotion != NULL && ismotion->key != key && !LF_ISSET(V_MOVE)) {
685                msgq(sp, M_ERR, "210|%s may not be used as a motion command",
686                    KEY_NAME(sp, key));
687                return (GC_ERR);
688        }
689
690        /* Required character. */
691        if (LF_ISSET(V_CHAR))
692                KEY(vp->character, 0);
693
694        /* Get any associated cursor word. */
695        if (F_ISSET(kp, V_KEYW) && v_keyword(sp))
696                return (GC_ERR);
697
698        return (GC_OK);
699
700esc:    switch (cpart) {
701        case COMMANDMODE:
702                msgq(sp, M_BERR, "211|Already in command mode");
703                return (GC_ERR_NOFLUSH);
704        case ISPARTIAL:
705                break;
706        case NOTPARTIAL:
707                (void)sp->gp->scr_bell(sp);
708                break;
709        }
710        return (GC_ERR);
711}
712
713/*
714 * v_motion --
715 *
716 * Get resulting motion mark.
717 */
718static int
719v_motion(sp, dm, vp, mappedp)
720        SCR *sp;
721        VICMD *dm, *vp;
722        int *mappedp;
723{
724        VICMD motion;
725        size_t len;
726        u_long cnt;
727        u_int flags;
728        int tilde_reset, notused;
729
730        /*
731         * If '.' command, use the dot motion, else get the motion command.
732         * Clear any line motion flags, the subsequent motion isn't always
733         * the same, i.e. "/aaa" may or may not be a line motion.
734         */
735        if (F_ISSET(vp, VC_ISDOT)) {
736                motion = *dm;
737                F_SET(&motion, VC_ISDOT);
738                F_CLR(&motion, VM_COMMASK);
739        } else {
740                memset(&motion, 0, sizeof(VICMD));
741                if (v_cmd(sp, NULL, &motion, vp, &notused, mappedp) != GC_OK)
742                        return (1);
743        }
744
745        /*
746         * A count may be provided both to the command and to the motion, in
747         * which case the count is multiplicative.  For example, "3y4y" is the
748         * same as "12yy".  This count is provided to the motion command and
749         * not to the regular function.
750         */
751        cnt = motion.count = F_ISSET(&motion, VC_C1SET) ? motion.count : 1;
752        if (F_ISSET(vp, VC_C1SET)) {
753                motion.count *= vp->count;
754                F_SET(&motion, VC_C1SET);
755
756                /*
757                 * Set flags to restore the original values of the command
758                 * structure so dot commands can change the count values,
759                 * e.g. "2dw" "3." deletes a total of five words.
760                 */
761                F_CLR(vp, VC_C1SET);
762                F_SET(vp, VC_C1RESET);
763        }
764
765        /*
766         * Some commands can be repeated to indicate the current line.  In
767         * this case, or if the command is a "line command", set the flags
768         * appropriately.  If not a doubled command, run the function to get
769         * the resulting mark.
770         */
771        if (vp->key == motion.key) {
772                F_SET(vp, VM_LDOUBLE | VM_LMODE);
773
774                /* Set the origin of the command. */
775                vp->m_start.lno = sp->lno;
776                vp->m_start.cno = 0;
777
778                /*
779                 * Set the end of the command.
780                 *
781                 * If the current line is missing, i.e. the file is empty,
782                 * historic vi permitted a "cc" or "!!" command to insert
783                 * text.
784                 */
785                vp->m_stop.lno = sp->lno + motion.count - 1;
786                if (db_get(sp, vp->m_stop.lno, 0, NULL, &len)) {
787                        if (vp->m_stop.lno != 1 ||
788                           vp->key != 'c' && vp->key != '!') {
789                                v_emsg(sp, NULL, VIM_EMPTY);
790                                return (1);
791                        }
792                        vp->m_stop.cno = 0;
793                } else
794                        vp->m_stop.cno = len ? len - 1 : 0;
795        } else {
796                /*
797                 * Motion commands change the underlying movement (*snarl*).
798                 * For example, "l" is illegal at the end of a line, but "dl"
799                 * is not.  Set flags so the function knows the situation.
800                 */
801                motion.rkp = vp->kp;
802
803                /*
804                 * XXX
805                 * Use yank instead of creating a new motion command, it's a
806                 * lot easier for now.
807                 */
808                if (vp->kp == &tmotion) {
809                        tilde_reset = 1;
810                        vp->kp = &vikeys['y'];
811                } else
812                        tilde_reset = 0;
813
814                /*
815                 * Copy the key flags into the local structure, except for the
816                 * RCM flags -- the motion command will set the RCM flags in
817                 * the vp structure if necessary.  This means that the motion
818                 * command is expected to determine where the cursor ends up!
819                 * However, we save off the current RCM mask and restore it if
820                 * it no RCM flags are set by the motion command, with a small
821                 * modification.
822                 *
823                 * We replace the VM_RCM_SET flag with the VM_RCM flag.  This
824                 * is so that cursor movement doesn't set the relative position
825                 * unless the motion command explicitly specified it.  This
826                 * appears to match historic practice, but I've never been able
827                 * to develop a hard-and-fast rule.
828                 */
829                flags = F_ISSET(vp, VM_RCM_MASK);
830                if (LF_ISSET(VM_RCM_SET)) {
831                        LF_SET(VM_RCM);
832                        LF_CLR(VM_RCM_SET);
833                }
834                F_CLR(vp, VM_RCM_MASK);
835                F_SET(&motion, motion.kp->flags & ~VM_RCM_MASK);
836
837                /*
838                 * Set the three cursor locations to the current cursor.  This
839                 * permits commands like 'j' and 'k', that are line oriented
840                 * motions and have special cursor suck semantics when they are
841                 * used as standalone commands, to ignore column positioning.
842                 */
843                motion.m_final.lno =
844                    motion.m_stop.lno = motion.m_start.lno = sp->lno;
845                motion.m_final.cno =
846                    motion.m_stop.cno = motion.m_start.cno = sp->cno;
847
848                /* Run the function. */
849                if ((motion.kp->func)(sp, &motion))
850                        return (1);
851
852                /*
853                 * If the current line is missing, i.e. the file is empty,
854                 * historic vi allowed "c<motion>" or "!<motion>" to insert
855                 * text.  Otherwise fail -- most motion commands will have
856                 * already failed, but some, e.g. G, succeed in empty files.
857                 */
858                if (!db_exist(sp, vp->m_stop.lno)) {
859                        if (vp->m_stop.lno != 1 ||
860                           vp->key != 'c' && vp->key != '!') {
861                                v_emsg(sp, NULL, VIM_EMPTY);
862                                return (1);
863                        }
864                        vp->m_stop.cno = 0;
865                }
866
867                /*
868                 * XXX
869                 * See above.
870                 */
871                if (tilde_reset)
872                        vp->kp = &tmotion;
873
874                /*
875                 * Copy cut buffer, line mode and cursor position information
876                 * from the motion command structure, i.e. anything that the
877                 * motion command can set for us.  The commands can flag the
878                 * movement as a line motion (see v_sentence) as well as set
879                 * the VM_RCM_* flags explicitly.
880                 */
881                F_SET(vp, F_ISSET(&motion, VM_COMMASK | VM_RCM_MASK));
882
883                /*
884                 * If the motion command set no relative motion flags, use
885                 * the (slightly) modified previous values.
886                 */
887                if (!F_ISSET(vp, VM_RCM_MASK))
888                        F_SET(vp, flags);
889
890                /*
891                 * Commands can change behaviors based on the motion command
892                 * used, for example, the ! command repeated the last bang
893                 * command if N or n was used as the motion.
894                 */
895                vp->rkp = motion.kp;
896
897                /*
898                 * Motion commands can reset all of the cursor information.
899                 * If the motion is in the reverse direction, switch the
900                 * from and to MARK's so that it's in a forward direction.
901                 * Motions are from the from MARK to the to MARK (inclusive).
902                 */
903                if (motion.m_start.lno > motion.m_stop.lno ||
904                    motion.m_start.lno == motion.m_stop.lno &&
905                    motion.m_start.cno > motion.m_stop.cno) {
906                        vp->m_start = motion.m_stop;
907                        vp->m_stop = motion.m_start;
908                } else {
909                        vp->m_start = motion.m_start;
910                        vp->m_stop = motion.m_stop;
911                }
912                vp->m_final = motion.m_final;
913        }
914
915        /*
916         * If the command sets dot, save the motion structure.  The motion
917         * count was changed above and needs to be reset, that's why this
918         * is done here, and not in the calling routine.
919         */
920        if (F_ISSET(vp->kp, V_DOT)) {
921                *dm = motion;
922                dm->count = cnt;
923        }
924        return (0);
925}
926
927/*
928 * v_init --
929 *      Initialize the vi screen.
930 */
931static int
932v_init(sp)
933        SCR *sp;
934{
935        GS *gp;
936        VI_PRIVATE *vip;
937
938        gp = sp->gp;
939        vip = VIP(sp);
940
941        /* Switch into vi. */
942        if (gp->scr_screen(sp, SC_VI))
943                return (1);
944        (void)gp->scr_attr(sp, SA_ALTERNATE, 1);
945
946        F_CLR(sp, SC_EX | SC_SCR_EX);
947        F_SET(sp, SC_VI);
948
949        /*
950         * Initialize screen values.
951         *
952         * Small windows: see vs_refresh(), section 6a.
953         *
954         * Setup:
955         *      t_minrows is the minimum rows to display
956         *      t_maxrows is the maximum rows to display (rows - 1)
957         *      t_rows is the rows currently being displayed
958         */
959        sp->rows = vip->srows = O_VAL(sp, O_LINES);
960        sp->cols = O_VAL(sp, O_COLUMNS);
961        sp->t_rows = sp->t_minrows = O_VAL(sp, O_WINDOW);
962        if (sp->rows != 1) {
963                if (sp->t_rows > sp->rows - 1) {
964                        sp->t_minrows = sp->t_rows = sp->rows - 1;
965                        msgq(sp, M_INFO,
966                            "214|Windows option value is too large, max is %u",
967                            sp->t_rows);
968                }
969                sp->t_maxrows = sp->rows - 1;
970        } else
971                sp->t_maxrows = 1;
972        sp->woff = 0;
973
974        /* Create a screen map. */
975        CALLOC_RET(sp, HMAP, SMAP *, SIZE_HMAP(sp), sizeof(SMAP));
976        TMAP = HMAP + (sp->t_rows - 1);
977        HMAP->lno = sp->lno;
978        HMAP->coff = 0;
979        HMAP->soff = 1;
980
981        /*
982         * Fill the screen map from scratch -- try and center the line.  That
983         * way if we're starting with a file we've seen before, we'll put the
984         * line in the middle, otherwise, it won't work and we'll end up with
985         * the line at the top.
986         */
987        F_SET(sp, SC_SCR_REFORMAT | SC_SCR_CENTER);
988
989        /* Invalidate the cursor. */
990        F_SET(vip, VIP_CUR_INVALID);
991
992        /* Paint the screen image from scratch. */
993        F_SET(vip, VIP_N_EX_PAINT);
994
995        return (0);
996}
997
998/*
999 * v_dtoh --
1000 *      Move all but the current screen to the hidden queue.
1001 */
1002static void
1003v_dtoh(sp)
1004        SCR *sp;
1005{
1006        GS *gp;
1007        SCR *tsp;
1008        int hidden;
1009
1010        /* Move all screens to the hidden queue, tossing screen maps. */
1011        for (hidden = 0, gp = sp->gp;
1012            (tsp = gp->dq.cqh_first) != (void *)&gp->dq; ++hidden) {
1013                if (_HMAP(tsp) != NULL) {
1014                        free(_HMAP(tsp));
1015                        _HMAP(tsp) = NULL;
1016                }
1017                CIRCLEQ_REMOVE(&gp->dq, tsp, q);
1018                CIRCLEQ_INSERT_TAIL(&gp->hq, tsp, q);
1019        }
1020
1021        /* Move current screen back to the display queue. */
1022        CIRCLEQ_REMOVE(&gp->hq, sp, q);
1023        CIRCLEQ_INSERT_TAIL(&gp->dq, sp, q);
1024
1025        /*
1026         * XXX
1027         * Don't bother internationalizing this message, it's going to
1028         * go away as soon as we have one-line screens.  --TK
1029         */
1030        if (hidden > 1)
1031                msgq(sp, M_INFO,
1032                    "%d screens backgrounded; use :display to list them",
1033                    hidden - 1);
1034}
1035
1036/*
1037 * v_keyword --
1038 *      Get the word (or non-word) the cursor is on.
1039 */
1040static int
1041v_keyword(sp)
1042        SCR *sp;
1043{
1044        VI_PRIVATE *vip;
1045        size_t beg, end, len;
1046        int moved, state;
1047        char *p;
1048
1049        if (db_get(sp, sp->lno, DBG_FATAL, &p, &len))
1050                return (1);
1051
1052        /*
1053         * !!!
1054         * Historically, tag commands skipped over any leading whitespace
1055         * characters.  Make this true in general when using cursor words.
1056         * If movement, getting a cursor word implies moving the cursor to
1057         * its beginning.  Refresh now.
1058         *
1059         * !!!
1060         * Find the beginning/end of the keyword.  Keywords are currently
1061         * used for cursor-word searching and for tags.  Historical vi
1062         * only used the word in a tag search from the cursor to the end
1063         * of the word, i.e. if the cursor was on the 'b' in " abc ", the
1064         * tag was "bc".  For consistency, we make cursor word searches
1065         * follow the same rule.
1066         */
1067        for (moved = 0,
1068            beg = sp->cno; beg < len && isspace(p[beg]); moved = 1, ++beg);
1069        if (beg >= len) {
1070                msgq(sp, M_BERR, "212|Cursor not in a word");
1071                return (1);
1072        }
1073        if (moved) {
1074                sp->cno = beg;
1075                (void)vs_refresh(sp, 0);
1076        }
1077
1078        /* Find the end of the word. */
1079        for (state = inword(p[beg]),
1080            end = beg; ++end < len && state == inword(p[end]););
1081
1082        vip = VIP(sp);
1083        len = (end - beg);
1084        BINC_RET(sp, vip->keyw, vip->klen, len);
1085        memmove(vip->keyw, p + beg, len);
1086        vip->keyw[len] = '\0';                          /* XXX */
1087        return (0);
1088}
1089
1090/*
1091 * v_alias --
1092 *      Check for a command alias.
1093 */
1094static VIKEYS const *
1095v_alias(sp, vp, kp)
1096        SCR *sp;
1097        VICMD *vp;
1098        VIKEYS const *kp;
1099{
1100        CHAR_T push;
1101
1102        switch (vp->key) {
1103        case 'C':                       /* C -> c$ */
1104                push = '$';
1105                vp->key = 'c';
1106                break;
1107        case 'D':                       /* D -> d$ */
1108                push = '$';
1109                vp->key = 'd';
1110                break;
1111        case 'S':                       /* S -> c_ */
1112                push = '_';
1113                vp->key = 'c';
1114                break;
1115        case 'Y':                       /* Y -> y_ */
1116                push = '_';
1117                vp->key = 'y';
1118                break;
1119        default:
1120                return (kp);
1121        }
1122        return (v_event_push(sp,
1123            NULL, &push, 1, CH_NOMAP | CH_QUOTED) ? NULL : &vikeys[vp->key]);
1124}
1125
1126/*
1127 * v_count --
1128 *      Return the next count.
1129 */
1130static int
1131v_count(sp, fkey, countp)
1132        SCR *sp;
1133        ARG_CHAR_T fkey;
1134        u_long *countp;
1135{
1136        EVENT ev;
1137        u_long count, tc;
1138
1139        ev.e_c = fkey;
1140        count = tc = 0;
1141        do {
1142                /*
1143                 * XXX
1144                 * Assume that overflow results in a smaller number.
1145                 */
1146                tc = count * 10 + ev.e_c - '0';
1147                if (count > tc) {
1148                        /* Toss to the next non-digit. */
1149                        do {
1150                                if (v_key(sp, 0, &ev,
1151                                    EC_MAPCOMMAND | EC_MAPNODIGIT) != GC_OK)
1152                                        return (1);
1153                        } while (isdigit(ev.e_c));
1154                        msgq(sp, M_ERR,
1155                            "235|Number larger than %lu", ULONG_MAX);
1156                        return (1);
1157                }
1158                count = tc;
1159                if (v_key(sp, 0, &ev, EC_MAPCOMMAND | EC_MAPNODIGIT) != GC_OK)
1160                        return (1);
1161        } while (isdigit(ev.e_c));
1162        *countp = count;
1163        return (0);
1164}
1165
1166/*
1167 * v_key --
1168 *      Return the next event.
1169 */
1170static gcret_t
1171v_key(sp, command_events, evp, ec_flags)
1172        SCR *sp;
1173        int command_events;
1174        EVENT *evp;
1175        u_int32_t ec_flags;
1176{
1177        u_int32_t quote;
1178
1179        for (quote = 0;;) {
1180                if (v_event_get(sp, evp, 0, ec_flags | quote))
1181                        return (GC_FATAL);
1182                quote = 0;
1183
1184                switch (evp->e_event) {
1185                case E_CHARACTER:
1186                        /*
1187                         * !!!
1188                         * Historically, ^V was ignored in the command stream,
1189                         * although it had a useful side-effect of interrupting
1190                         * mappings.  Adding a quoting bit to the call probably
1191                         * extends historic practice, but it feels right.
1192                         */
1193                        if (evp->e_value == K_VLNEXT) {
1194                                quote = EC_QUOTED;
1195                                break;
1196                        }
1197                        return (GC_OK);
1198                case E_ERR:
1199                case E_EOF:
1200                        return (GC_FATAL);
1201                case E_INTERRUPT:
1202                        /*
1203                         * !!!
1204                         * Historically, vi beeped on command level interrupts.
1205                         *
1206                         * Historically, vi exited to ex mode if no file was
1207                         * named on the command line, and two interrupts were
1208                         * generated in a row.  (Just figured you might want
1209                         * to know that.)
1210                         */
1211                        (void)sp->gp->scr_bell(sp);
1212                        return (GC_INTERRUPT);
1213                case E_REPAINT:
1214                        if (vs_repaint(sp, evp))
1215                                return (GC_FATAL);
1216                        break;
1217                case E_WRESIZE:
1218                        return (GC_ERR);
1219                case E_QUIT:
1220                case E_WRITE:
1221                        if (command_events)
1222                                return (GC_EVENT);
1223                        /* FALLTHROUGH */
1224                default:
1225                        v_event_err(sp, evp);
1226                        return (GC_ERR);
1227                }
1228        }
1229        /* NOTREACHED */
1230}
1231
1232#if defined(DEBUG) && defined(COMLOG)
1233/*
1234 * v_comlog --
1235 *      Log the contents of the command structure.
1236 */
1237static void
1238v_comlog(sp, vp)
1239        SCR *sp;
1240        VICMD *vp;
1241{
1242        TRACE(sp, "vcmd: %c", vp->key);
1243        if (F_ISSET(vp, VC_BUFFER))
1244                TRACE(sp, " buffer: %c", vp->buffer);
1245        if (F_ISSET(vp, VC_C1SET))
1246                TRACE(sp, " c1: %lu", vp->count);
1247        if (F_ISSET(vp, VC_C2SET))
1248                TRACE(sp, " c2: %lu", vp->count2);
1249        TRACE(sp, " flags: 0x%x\n", vp->flags);
1250}
1251#endif
Note: See TracBrowser for help on using the repository browser.