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