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

Revision 14302, 77.7 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) 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[] = "@(#)v_txt.c       10.87 (Berkeley) 10/13/96";
14#endif /* not lint */
15
16#include <sys/types.h>
17#include <sys/queue.h>
18#include <sys/stat.h>
19#include <sys/time.h>
20
21#include <bitstring.h>
22#include <ctype.h>
23#include <errno.h>
24#include <limits.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29
30#include "../common/common.h"
31#include "vi.h"
32
33static int       txt_abbrev __P((SCR *, TEXT *, CHAR_T *, int, int *, int *));
34static void      txt_ai_resolve __P((SCR *, TEXT *, int *));
35static TEXT     *txt_backup __P((SCR *, TEXTH *, TEXT *, u_int32_t *));
36static int       txt_dent __P((SCR *, TEXT *, int));
37static int       txt_emark __P((SCR *, TEXT *, size_t));
38static void      txt_err __P((SCR *, TEXTH *));
39static int       txt_fc __P((SCR *, TEXT *, int *));
40static int       txt_fc_col __P((SCR *, int, ARGS **));
41static int       txt_hex __P((SCR *, TEXT *));
42static int       txt_insch __P((SCR *, TEXT *, CHAR_T *, u_int));
43static int       txt_isrch __P((SCR *, VICMD *, TEXT *, u_int8_t *));
44static int       txt_map_end __P((SCR *));
45static int       txt_map_init __P((SCR *));
46static int       txt_margin __P((SCR *, TEXT *, TEXT *, int *, u_int32_t));
47static void      txt_nomorech __P((SCR *));
48static void      txt_Rresolve __P((SCR *, TEXTH *, TEXT *, const size_t));
49static int       txt_resolve __P((SCR *, TEXTH *, u_int32_t));
50static int       txt_showmatch __P((SCR *, TEXT *));
51static void      txt_unmap __P((SCR *, TEXT *, u_int32_t *));
52
53/* Cursor character (space is hard to track on the screen). */
54#if defined(DEBUG) && 0
55#undef  CH_CURSOR
56#define CH_CURSOR       '+'
57#endif
58
59/*
60 * v_tcmd --
61 *      Fill a buffer from the terminal for vi.
62 *
63 * PUBLIC: int v_tcmd __P((SCR *, VICMD *, ARG_CHAR_T, u_int));
64 */
65int
66v_tcmd(sp, vp, prompt, flags)
67        SCR *sp;
68        VICMD *vp;
69        ARG_CHAR_T prompt;
70        u_int flags;
71{
72        /* Normally, we end up where we started. */
73        vp->m_final.lno = sp->lno;
74        vp->m_final.cno = sp->cno;
75
76        /* Initialize the map. */
77        if (txt_map_init(sp))
78                return (1);
79
80        /* Move to the last line. */
81        sp->lno = TMAP[0].lno;
82        sp->cno = 0;
83
84        /* Don't update the modeline for now. */
85        F_SET(sp, SC_TINPUT_INFO);
86
87        /* Set the input flags. */
88        LF_SET(TXT_APPENDEOL |
89            TXT_CR | TXT_ESCAPE | TXT_INFOLINE | TXT_MAPINPUT);
90        if (O_ISSET(sp, O_ALTWERASE))
91                LF_SET(TXT_ALTWERASE);
92        if (O_ISSET(sp, O_TTYWERASE))
93                LF_SET(TXT_TTYWERASE);
94
95        /* Do the input thing. */
96        if (v_txt(sp, vp, NULL, NULL, 0, prompt, 0, 1, flags))
97                return (1);
98
99        /* Reenable the modeline updates. */
100        F_CLR(sp, SC_TINPUT_INFO);
101
102        /* Clean up the map. */
103        if (txt_map_end(sp))
104                return (1);
105
106        if (IS_ONELINE(sp))
107                F_SET(sp, SC_SCR_REDRAW);       /* XXX */
108
109        /* Set the cursor to the resulting position. */
110        sp->lno = vp->m_final.lno;
111        sp->cno = vp->m_final.cno;
112
113        return (0);
114}
115
116/*
117 * txt_map_init
118 *      Initialize the screen map for colon command-line input.
119 */
120static int
121txt_map_init(sp)
122        SCR *sp;
123{
124        SMAP *esmp;
125        VI_PRIVATE *vip;
126
127        vip = VIP(sp);
128        if (!IS_ONELINE(sp)) {
129                /*
130                 * Fake like the user is doing input on the last line of the
131                 * screen.  This makes all of the scrolling work correctly,
132                 * and allows us the use of the vi text editing routines, not
133                 * to mention practically infinite length ex commands.
134                 *
135                 * Save the current location.
136                 */
137                vip->sv_tm_lno = TMAP->lno;
138                vip->sv_tm_soff = TMAP->soff;
139                vip->sv_tm_coff = TMAP->coff;
140                vip->sv_t_maxrows = sp->t_maxrows;
141                vip->sv_t_minrows = sp->t_minrows;
142                vip->sv_t_rows = sp->t_rows;
143
144                /*
145                 * If it's a small screen, TMAP may be small for the screen.
146                 * Fix it, filling in fake lines as we go.
147                 */
148                if (IS_SMALL(sp))
149                        for (esmp =
150                            HMAP + (sp->t_maxrows - 1); TMAP < esmp; ++TMAP) {
151                                TMAP[1].lno = TMAP[0].lno + 1;
152                                TMAP[1].coff = HMAP->coff;
153                                TMAP[1].soff = 1;
154                        }
155
156                /* Build the fake entry. */
157                TMAP[1].lno = TMAP[0].lno + 1;
158                TMAP[1].soff = 1;
159                TMAP[1].coff = 0;
160                SMAP_FLUSH(&TMAP[1]);
161                ++TMAP;
162
163                /* Reset the screen information. */
164                sp->t_rows = sp->t_minrows = ++sp->t_maxrows;
165        }
166        return (0);
167}
168
169/*
170 * txt_map_end
171 *      Reset the screen map for colon command-line input.
172 */
173static int
174txt_map_end(sp)
175        SCR *sp;
176{
177        VI_PRIVATE *vip;
178        size_t cnt;
179
180        vip = VIP(sp);
181        if (!IS_ONELINE(sp)) {
182                /* Restore the screen information. */
183                sp->t_rows = vip->sv_t_rows;
184                sp->t_minrows = vip->sv_t_minrows;
185                sp->t_maxrows = vip->sv_t_maxrows;
186
187                /*
188                 * If it's a small screen, TMAP may be wrong.  Clear any
189                 * lines that might have been overwritten.
190                 */
191                if (IS_SMALL(sp)) {
192                        for (cnt = sp->t_rows; cnt <= sp->t_maxrows; ++cnt) {
193                                (void)sp->gp->scr_move(sp, cnt, 0);
194                                (void)sp->gp->scr_clrtoeol(sp);
195                        }
196                        TMAP = HMAP + (sp->t_rows - 1);
197                } else
198                        --TMAP;
199
200                /*
201                 * The map may be wrong if the user entered more than one
202                 * (logical) line.  Fix it.  If the user entered a whole
203                 * screen, this will be slow, but we probably don't care.
204                 */
205                if (!O_ISSET(sp, O_LEFTRIGHT))
206                        while (vip->sv_tm_lno != TMAP->lno ||
207                            vip->sv_tm_soff != TMAP->soff)
208                                if (vs_sm_1down(sp))
209                                        return (1);
210        }
211
212        /*
213         * Invalidate the cursor and the line size cache, the line never
214         * really existed.  This fixes bugs where the user searches for
215         * the last line on the screen + 1 and the refresh routine thinks
216         * that's where we just were.
217         */
218        VI_SCR_CFLUSH(vip);
219        F_SET(vip, VIP_CUR_INVALID);
220
221        return (0);
222}
223
224/*
225 * If doing input mapping on the colon command line, may need to unmap
226 * based on the command.
227 */
228#define UNMAP_TST                                                       \
229        FL_ISSET(ec_flags, EC_MAPINPUT) && LF_ISSET(TXT_INFOLINE)
230
231/*
232 * Internally, we maintain tp->lno and tp->cno, externally, everyone uses
233 * sp->lno and sp->cno.  Make them consistent as necessary.
234 */
235#define UPDATE_POSITION(sp, tp) {                                       \
236        (sp)->lno = (tp)->lno;                                          \
237        (sp)->cno = (tp)->cno;                                          \
238}
239
240/*
241 * v_txt --
242 *      Vi text input.
243 *
244 * PUBLIC: int v_txt __P((SCR *, VICMD *, MARK *,
245 * PUBLIC:    const char *, size_t, ARG_CHAR_T, recno_t, u_long, u_int32_t));
246 */
247int
248v_txt(sp, vp, tm, lp, len, prompt, ai_line, rcount, flags)
249        SCR *sp;
250        VICMD *vp;
251        MARK *tm;               /* To MARK. */
252        const char *lp;         /* Input line. */
253        size_t len;             /* Input line length. */
254        ARG_CHAR_T prompt;      /* Prompt to display. */
255        recno_t ai_line;        /* Line number to use for autoindent count. */
256        u_long rcount;          /* Replay count. */
257        u_int32_t flags;        /* TXT_* flags. */
258{
259        EVENT ev, *evp;         /* Current event. */
260        EVENT fc;               /* File name completion event. */
261        GS *gp;
262        TEXT *ntp, *tp;         /* Input text structures. */
263        TEXT ait;               /* Autoindent text structure. */
264        TEXT wmt;               /* Wrapmargin text structure. */
265        TEXTH *tiqh;
266        VI_PRIVATE *vip;
267        abb_t abb;              /* State of abbreviation checks. */
268        carat_t carat;          /* State of the "[^0]^D" sequences. */
269        quote_t quote;          /* State of quotation. */
270        size_t owrite, insert;  /* Temporary copies of TEXT fields. */
271        size_t margin;          /* Wrapmargin value. */
272        size_t rcol;            /* 0-N: insert offset in the replay buffer. */
273        size_t tcol;            /* Temporary column. */
274        u_int32_t ec_flags;     /* Input mapping flags. */
275#define IS_RESTART      0x01    /* Reset the incremental search. */
276#define IS_RUNNING      0x02    /* Incremental search turned on. */
277        u_int8_t is_flags;
278        int abcnt, ab_turnoff;  /* Abbreviation character count, switch. */
279        int filec_redraw;       /* Redraw after the file completion routine. */
280        int hexcnt;             /* Hex character count. */
281        int showmatch;          /* Showmatch set on this character. */
282        int wm_set, wm_skip;    /* Wrapmargin happened, blank skip flags. */
283        int max, tmp;
284        char *p;
285
286        gp = sp->gp;
287        vip = VIP(sp);
288
289        /*
290         * Set the input flag, so tabs get displayed correctly
291         * and everyone knows that the text buffer is in use.
292         */
293        F_SET(sp, SC_TINPUT);
294
295        /*
296         * Get one TEXT structure with some initial buffer space, reusing
297         * the last one if it's big enough.  (All TEXT bookkeeping fields
298         * default to 0 -- text_init() handles this.)  If changing a line,
299         * copy it into the TEXT buffer.
300         */
301        tiqh = &sp->tiq;
302        if (tiqh->cqh_first != (void *)tiqh) {
303                tp = tiqh->cqh_first;
304                if (tp->q.cqe_next != (void *)tiqh || tp->lb_len < len + 32) {
305                        text_lfree(tiqh);
306                        goto newtp;
307                }
308                tp->ai = tp->insert = tp->offset = tp->owrite = 0;
309                if (lp != NULL) {
310                        tp->len = len;
311                        memmove(tp->lb, lp, len);
312                } else
313                        tp->len = 0;
314        } else {
315newtp:          if ((tp = text_init(sp, lp, len, len + 32)) == NULL)
316                        return (1);
317                CIRCLEQ_INSERT_HEAD(tiqh, tp, q);
318        }
319
320        /* Set default termination condition. */
321        tp->term = TERM_OK;
322
323        /* Set the starting line, column. */
324        tp->lno = sp->lno;
325        tp->cno = sp->cno;
326
327        /*
328         * Set the insert and overwrite counts.  If overwriting characters,
329         * do insertion afterward.  If not overwriting characters, assume
330         * doing insertion.  If change is to a mark, emphasize it with an
331         * CH_ENDMARK character.
332         */
333        if (len) {
334                if (LF_ISSET(TXT_OVERWRITE)) {
335                        tp->owrite = (tm->cno - tp->cno) + 1;
336                        tp->insert = (len - tm->cno) - 1;
337                } else
338                        tp->insert = len - tp->cno;
339
340                if (LF_ISSET(TXT_EMARK) && txt_emark(sp, tp, tm->cno))
341                        return (1);
342        }
343
344        /*
345         * Many of the special cases in text input are to handle autoindent
346         * support.  Somebody decided that it would be a good idea if "^^D"
347         * and "0^D" deleted all of the autoindented characters.  In an editor
348         * that takes single character input from the user, this beggars the
349         * imagination.  Note also, "^^D" resets the next lines' autoindent,
350         * but "0^D" doesn't.
351         *
352         * We assume that autoindent only happens on empty lines, so insert
353         * and overwrite will be zero.  If doing autoindent, figure out how
354         * much indentation we need and fill it in.  Update input column and
355         * screen cursor as necessary.
356         */
357        if (LF_ISSET(TXT_AUTOINDENT) && ai_line != OOBLNO) {
358                if (v_txt_auto(sp, ai_line, NULL, 0, tp))
359                        return (1);
360                tp->cno = tp->ai;
361        } else {
362                /*
363                 * The cc and S commands have a special feature -- leading
364                 * <blank> characters are handled as autoindent characters.
365                 * Beauty!
366                 */
367                if (LF_ISSET(TXT_AICHARS)) {
368                        tp->offset = 0;
369                        tp->ai = tp->cno;
370                } else
371                        tp->offset = tp->cno;
372        }
373
374        /* If getting a command buffer from the user, there may be a prompt. */
375        if (LF_ISSET(TXT_PROMPT)) {
376                tp->lb[tp->cno++] = prompt;
377                ++tp->len;
378                ++tp->offset;
379        }
380
381        /*
382         * If appending after the end-of-line, add a space into the buffer
383         * and move the cursor right.  This space is inserted, i.e. pushed
384         * along, and then deleted when the line is resolved.  Assumes that
385         * the cursor is already positioned at the end of the line.  This
386         * avoids the nastiness of having the cursor reside on a magical
387         * column, i.e. a column that doesn't really exist.  The only down
388         * side is that we may wrap lines or scroll the screen before it's
389         * strictly necessary.  Not a big deal.
390         */
391        if (LF_ISSET(TXT_APPENDEOL)) {
392                tp->lb[tp->cno] = CH_CURSOR;
393                ++tp->len;
394                ++tp->insert;
395                (void)vs_change(sp, tp->lno, LINE_RESET);
396        }
397
398        /*
399         * Historic practice is that the wrapmargin value was a distance
400         * from the RIGHT-HAND margin, not the left.  It's more useful to
401         * us as a distance from the left-hand margin, i.e. the same as
402         * the wraplen value.  The wrapmargin option is historic practice.
403         * Nvi added the wraplen option so that it would be possible to
404         * edit files with consistent margins without knowing the number of
405         * columns in the window.
406         *
407         * XXX
408         * Setting margin causes a significant performance hit.  Normally
409         * we don't update the screen if there are keys waiting, but we
410         * have to if margin is set, otherwise the screen routines don't
411         * know where the cursor is.
412         *
413         * !!!
414         * Abbreviated keys were affected by the wrapmargin option in the
415         * historic 4BSD vi.  Mapped keys were usually, but sometimes not.
416         * See the comment in vi/v_text():set_txt_std for more information.
417         *
418         * !!!
419         * One more special case.  If an inserted <blank> character causes
420         * wrapmargin to split the line, the next user entered character is
421         * discarded if it's a <space> character.
422         */
423        wm_set = wm_skip = 0;
424        if (LF_ISSET(TXT_WRAPMARGIN))
425                if ((margin = O_VAL(sp, O_WRAPMARGIN)) != 0)
426                        margin = sp->cols - margin;
427                else
428                        margin = O_VAL(sp, O_WRAPLEN);
429        else
430                margin = 0;
431
432        /* Initialize abbreviation checks. */
433        abcnt = ab_turnoff = 0;
434        abb = F_ISSET(gp, G_ABBREV) &&
435            LF_ISSET(TXT_MAPINPUT) ? AB_INWORD : AB_NOTSET;
436
437        /*
438         * Set up the dot command.  Dot commands are done by saving the actual
439         * characters and then reevaluating them so that things like wrapmargin
440         * can change between the insert and the replay.
441         *
442         * !!!
443         * Historically, vi did not remap or reabbreviate replayed input.  (It
444         * did beep at you if you changed an abbreviation and then replayed the
445         * input.  We're not that compatible.)  We don't have to do anything to
446         * avoid remapping, as we're not getting characters from the terminal
447         * routines.  Turn the abbreviation check off.
448         *
449         * XXX
450         * It would be nice if we could swallow backspaces and such, but it's
451         * not all that easy to do.  What we can do is turn off the common
452         * error messages during the replay.  Otherwise, when the user enters
453         * an illegal command, e.g., "Ia<erase><erase><erase><erase>b<escape>",
454         * and then does a '.', they get a list of error messages after command
455         * completion.
456         */
457        rcol = 0;
458        if (LF_ISSET(TXT_REPLAY)) {
459                abb = AB_NOTSET;
460                LF_CLR(TXT_RECORD);
461        }
462
463        /* Other text input mode setup. */
464        quote = Q_NOTSET;
465        carat = C_NOTSET;
466        FL_INIT(is_flags,
467            LF_ISSET(TXT_SEARCHINCR) ? IS_RESTART | IS_RUNNING : 0);
468        filec_redraw = hexcnt = showmatch = 0;
469
470        /* Initialize input flags. */
471        ec_flags = LF_ISSET(TXT_MAPINPUT) ? EC_MAPINPUT : 0;
472
473        /* Refresh the screen. */
474        UPDATE_POSITION(sp, tp);
475        if (vs_refresh(sp, 1))
476                return (1);
477
478        /* If it's dot, just do it now. */
479        if (F_ISSET(vp, VC_ISDOT))
480                goto replay;
481
482        /* Get an event. */
483        evp = &ev;
484next:   if (v_event_get(sp, evp, 0, ec_flags))
485                return (1);
486
487        /*
488         * If file completion overwrote part of the screen and nothing else has
489         * been displayed, clean up.  We don't do this as part of the normal
490         * message resolution because we know the user is on the colon command
491         * line and there's no reason to enter explicit characters to continue.
492         */
493        if (filec_redraw && !F_ISSET(sp, SC_SCR_EXWROTE)) {
494                filec_redraw = 0;
495
496                fc.e_event = E_REPAINT;
497                fc.e_flno = vip->totalcount >=
498                    sp->rows ? 1 : sp->rows - vip->totalcount;
499                fc.e_tlno = sp->rows;
500                vip->linecount = vip->lcontinue = vip->totalcount = 0;
501                (void)vs_repaint(sp, &fc);
502                (void)vs_refresh(sp, 1);
503        }
504
505        /* Deal with all non-character events. */
506        switch (evp->e_event) {
507        case E_CHARACTER:
508                break;
509        case E_ERR:
510        case E_EOF:
511                F_SET(sp, SC_EXIT_FORCE);
512                return (1);
513        case E_INTERRUPT:
514                /*
515                 * !!!
516                 * Historically, <interrupt> exited the user from text input
517                 * mode or cancelled a colon command, and returned to command
518                 * mode.  It also beeped the terminal, but that seems a bit
519                 * excessive.
520                 */
521                goto k_escape;
522        case E_REPAINT:
523                if (vs_repaint(sp, &ev))
524                        return (1);
525                goto next;
526        case E_WRESIZE:
527                /* <resize> interrupts the input mode. */
528                v_emsg(sp, NULL, VIM_WRESIZE);
529                goto k_escape;
530        default:
531                v_event_err(sp, evp);
532                goto k_escape;
533        }
534
535        /*
536         * !!!
537         * If the first character of the input is a nul, replay the previous
538         * input.  (Historically, it's okay to replay non-existent input.)
539         * This was not documented as far as I know, and is a great test of vi
540         * clones.
541         */
542        if (rcol == 0 && !LF_ISSET(TXT_REPLAY) && evp->e_c == '\0') {
543                if (vip->rep == NULL)
544                        goto done;
545
546                abb = AB_NOTSET;
547                LF_CLR(TXT_RECORD);
548                LF_SET(TXT_REPLAY);
549                goto replay;
550        }
551
552        /*
553         * File name completion and colon command-line editing.   We don't
554         * have enough meta characters, so we expect people to overload
555         * them.  If the two characters are the same, then we do file name
556         * completion if the cursor is past the first column, and do colon
557         * command-line editing if it's not.
558         */
559        if (quote == Q_NOTSET) {
560                int L__cedit, L__filec;
561
562                L__cedit = L__filec = 0;
563                if (LF_ISSET(TXT_CEDIT) && O_STR(sp, O_CEDIT) != NULL &&
564                    O_STR(sp, O_CEDIT)[0] == evp->e_c)
565                        L__cedit = 1;
566                if (LF_ISSET(TXT_FILEC) && O_STR(sp, O_FILEC) != NULL &&
567                    O_STR(sp, O_FILEC)[0] == evp->e_c)
568                        L__filec = 1;
569                if (L__cedit == 1 && (L__filec == 0 || tp->cno == tp->offset)) {
570                        tp->term = TERM_CEDIT;
571                        goto k_escape;
572                }
573                if (L__filec == 1) {
574                        if (txt_fc(sp, tp, &filec_redraw))
575                                goto err;
576                        goto resolve;
577                }
578        }
579
580        /* Abbreviation overflow check.  See comment in txt_abbrev(). */
581#define MAX_ABBREVIATION_EXPANSION      256
582        if (F_ISSET(&evp->e_ch, CH_ABBREVIATED)) {
583                if (++abcnt > MAX_ABBREVIATION_EXPANSION) {
584                        if (v_event_flush(sp, CH_ABBREVIATED))
585                                msgq(sp, M_ERR,
586"191|Abbreviation exceeded expansion limit: characters discarded");
587                        abcnt = 0;
588                        if (LF_ISSET(TXT_REPLAY))
589                                goto done;
590                        goto resolve;
591                }
592        } else
593                abcnt = 0;
594
595        /* Check to see if the character fits into the replay buffers. */
596        if (LF_ISSET(TXT_RECORD)) {
597                BINC_GOTO(sp, vip->rep,
598                    vip->rep_len, (rcol + 1) * sizeof(EVENT));
599                vip->rep[rcol++] = *evp;
600        }
601
602replay: if (LF_ISSET(TXT_REPLAY))
603                evp = vip->rep + rcol++;
604
605        /* Wrapmargin check for leading space. */
606        if (wm_skip) {
607                wm_skip = 0;
608                if (evp->e_c == ' ')
609                        goto resolve;
610        }
611
612        /* If quoted by someone else, simply insert the character. */
613        if (F_ISSET(&evp->e_ch, CH_QUOTED))
614                goto insq_ch;
615
616        /*
617         * !!!
618         * If this character was quoted by a K_VLNEXT or a backslash, replace
619         * the placeholder (a carat or a backslash) with the new character.
620         * If it was quoted by a K_VLNEXT, we've already adjusted the cursor
621         * because it has to appear on top of the placeholder character.  If
622         * it was quoted by a backslash, adjust the cursor now, the cursor
623         * doesn't appear on top of it.  Historic practice in both cases.
624         *
625         * Skip tests for abbreviations; ":ab xa XA" followed by "ixa^V<space>"
626         * doesn't perform an abbreviation.  Special case, ^V^J (not ^V^M) is
627         * the same as ^J, historically.
628         */
629        if (quote == Q_BTHIS || quote == Q_VTHIS) {
630                FL_CLR(ec_flags, EC_QUOTED);
631                if (LF_ISSET(TXT_MAPINPUT))
632                        FL_SET(ec_flags, EC_MAPINPUT);
633
634                if (quote == Q_BTHIS &&
635                    (evp->e_value == K_VERASE || evp->e_value == K_VKILL)) {
636                        quote = Q_NOTSET;
637                        --tp->cno;
638                        ++tp->owrite;
639                        goto insl_ch;
640                }
641                if (quote == Q_VTHIS && evp->e_value != K_NL) {
642                        quote = Q_NOTSET;
643                        goto insl_ch;
644                }
645                quote = Q_NOTSET;
646        }
647
648        /*
649         * !!!
650         * Translate "<CH_HEX>[isxdigit()]*" to a character with a hex value:
651         * this test delimits the value by any non-hex character.  Offset by
652         * one, we use 0 to mean that we've found <CH_HEX>.
653         */
654        if (hexcnt > 1 && !isxdigit(evp->e_c)) {
655                hexcnt = 0;
656                if (txt_hex(sp, tp))
657                        goto err;
658        }
659
660        switch (evp->e_value) {
661        case K_CR:                              /* Carriage return. */
662        case K_NL:                              /* New line. */
663                /* Return in script windows and the command line. */
664k_cr:           if (LF_ISSET(TXT_CR)) {
665                        /*
666                         * If this was a map, we may have not displayed
667                         * the line.  Display it, just in case.
668                         *
669                         * If a script window and not the colon line,
670                         * push a <cr> so it gets executed.
671                         */
672                        if (LF_ISSET(TXT_INFOLINE)) {
673                                if (vs_change(sp, tp->lno, LINE_RESET))
674                                        goto err;
675                        } else if (F_ISSET(sp, SC_SCRIPT))
676                                (void)v_event_push(sp, NULL, "\r", 1, CH_NOMAP);
677
678                        /* Set term condition: if empty. */
679                        if (tp->cno <= tp->offset)
680                                tp->term = TERM_CR;
681                        /*
682                         * Set term condition: if searching incrementally and
683                         * the user entered a pattern, return a completed
684                         * search, regardless if the entire pattern was found.
685                         */
686                        if (FL_ISSET(is_flags, IS_RUNNING) &&
687                            tp->cno >= tp->offset + 1)
688                                tp->term = TERM_SEARCH;
689
690                        goto k_escape;
691                }
692
693#define LINE_RESOLVE {                                                  \
694                /*                                                      \
695                 * Handle abbreviations.  If there was one, discard the \
696                 * replay characters.                                   \
697                 */                                                     \
698                if (abb == AB_INWORD &&                                 \
699                    !LF_ISSET(TXT_REPLAY) && F_ISSET(gp, G_ABBREV)) {   \
700                        if (txt_abbrev(sp, tp, &evp->e_c,               \
701                            LF_ISSET(TXT_INFOLINE), &tmp,               \
702                            &ab_turnoff))                               \
703                                goto err;                               \
704                        if (tmp) {                                      \
705                                if (LF_ISSET(TXT_RECORD))               \
706                                        rcol -= tmp + 1;                \
707                                goto resolve;                           \
708                        }                                               \
709                }                                                       \
710                if (abb != AB_NOTSET)                                   \
711                        abb = AB_NOTWORD;                               \
712                if (UNMAP_TST)                                          \
713                        txt_unmap(sp, tp, &ec_flags);                   \
714                /*                                                      \
715                 * Delete any appended cursor.  It's possible to get in \
716                 * situations where TXT_APPENDEOL is set but tp->insert \
717                 * is 0 when using the R command and all the characters \
718                 * are tp->owrite characters.                           \
719                 */                                                     \
720                if (LF_ISSET(TXT_APPENDEOL) && tp->insert > 0) {        \
721                        --tp->len;                                      \
722                        --tp->insert;                                   \
723                }                                                       \
724}
725                LINE_RESOLVE;
726
727                /*
728                 * Save the current line information for restoration in
729                 * txt_backup(), and set the line final length.
730                 */
731                tp->sv_len = tp->len;
732                tp->sv_cno = tp->cno;
733                tp->len = tp->cno;
734
735                /* Update the old line. */
736                if (vs_change(sp, tp->lno, LINE_RESET))
737                        goto err;
738
739                /*
740                 * Historic practice, when the autoindent edit option was set,
741                 * was to delete <blank> characters following the inserted
742                 * newline.  This affected the 'R', 'c', and 's' commands; 'c'
743                 * and 's' retained the insert characters only, 'R' moved the
744                 * overwrite and insert characters into the next TEXT structure.
745                 * We keep track of the number of characters erased for the 'R'
746                 * command so that the final resolution of the line is correct.
747                 */
748                tp->R_erase = 0;
749                owrite = tp->owrite;
750                insert = tp->insert;
751                if (LF_ISSET(TXT_REPLACE) && owrite != 0) {
752                        for (p = tp->lb + tp->cno; owrite > 0 && isblank(*p);
753                            ++p, --owrite, ++tp->R_erase);
754                        if (owrite == 0)
755                                for (; insert > 0 && isblank(*p);
756                                    ++p, ++tp->R_erase, --insert);
757                } else {
758                        p = tp->lb + tp->cno + owrite;
759                        if (O_ISSET(sp, O_AUTOINDENT))
760                                for (; insert > 0 &&
761                                    isblank(*p); ++p, --insert);
762                        owrite = 0;
763                }
764
765                /*
766                 * !!!
767                 * Create a new line and insert the new TEXT into the queue.
768                 * DON'T insert until the old line has been updated, or the
769                 * inserted line count in line.c:db_get() will be wrong.
770                 */
771                if ((ntp = text_init(sp, p,
772                    insert + owrite, insert + owrite + 32)) == NULL)
773                        goto err;
774                CIRCLEQ_INSERT_TAIL(&sp->tiq, ntp, q);
775
776                /* Set up bookkeeping for the new line. */
777                ntp->insert = insert;
778                ntp->owrite = owrite;
779                ntp->lno = tp->lno + 1;
780
781                /*
782                 * Reset the autoindent line value.  0^D keeps the autoindent
783                 * line from changing, ^D changes the level, even if there were
784                 * no characters in the old line.  Note, if using the current
785                 * tp structure, use the cursor as the length, the autoindent
786                 * characters may have been erased.
787                 */
788                if (LF_ISSET(TXT_AUTOINDENT)) {
789                        if (carat == C_NOCHANGE) {
790                                if (v_txt_auto(sp, OOBLNO, &ait, ait.ai, ntp))
791                                        goto err;
792                                FREE_SPACE(sp, ait.lb, ait.lb_len);
793                        } else
794                                if (v_txt_auto(sp, OOBLNO, tp, tp->cno, ntp))
795                                        goto err;
796                        carat = C_NOTSET;
797                }
798
799                /* Reset the cursor. */
800                ntp->cno = ntp->ai;
801
802                /*
803                 * If we're here because wrapmargin was set and we've broken a
804                 * line, there may be additional information (i.e. the start of
805                 * a line) in the wmt structure.
806                 */
807                if (wm_set) {
808                        if (wmt.offset != 0 ||
809                            wmt.owrite != 0 || wmt.insert != 0) {
810#define WMTSPACE        wmt.offset + wmt.owrite + wmt.insert
811                                BINC_GOTO(sp, ntp->lb,
812                                    ntp->lb_len, ntp->len + WMTSPACE + 32);
813                                memmove(ntp->lb + ntp->cno, wmt.lb, WMTSPACE);
814                                ntp->len += WMTSPACE;
815                                ntp->cno += wmt.offset;
816                                ntp->owrite = wmt.owrite;
817                                ntp->insert = wmt.insert;
818                        }
819                        wm_set = 0;
820                }
821
822                /* New lines are TXT_APPENDEOL. */
823                if (ntp->owrite == 0 && ntp->insert == 0) {
824                        BINC_GOTO(sp, ntp->lb, ntp->lb_len, ntp->len + 1);
825                        LF_SET(TXT_APPENDEOL);
826                        ntp->lb[ntp->cno] = CH_CURSOR;
827                        ++ntp->insert;
828                        ++ntp->len;
829                }
830
831                /* Swap old and new TEXT's, and update the new line. */
832                tp = ntp;
833                if (vs_change(sp, tp->lno, LINE_INSERT))
834                        goto err;
835
836                goto resolve;
837        case K_ESCAPE:                          /* Escape. */
838                if (!LF_ISSET(TXT_ESCAPE))
839                        goto ins_ch;
840
841                /* If we have a count, start replaying the input. */
842                if (rcount > 1) {
843                        --rcount;
844
845                        rcol = 0;
846                        abb = AB_NOTSET;
847                        LF_CLR(TXT_RECORD);
848                        LF_SET(TXT_REPLAY);
849
850                        /*
851                         * Some commands (e.g. 'o') need a <newline> for each
852                         * repetition.
853                         */
854                        if (LF_ISSET(TXT_ADDNEWLINE))
855                                goto k_cr;
856
857                        /*
858                         * The R command turns into the 'a' command after the
859                         * first repetition.
860                         */
861                        if (LF_ISSET(TXT_REPLACE)) {
862                                tp->insert = tp->owrite;
863                                tp->owrite = 0;
864                                LF_CLR(TXT_REPLACE);
865                        }
866                        goto replay;
867                }
868
869                /* Set term condition: if empty. */
870                if (tp->cno <= tp->offset)
871                        tp->term = TERM_ESC;
872                /*
873                 * Set term condition: if searching incrementally and the user
874                 * entered a pattern, return a completed search, regardless if
875                 * the entire pattern was found.
876                 */
877                if (FL_ISSET(is_flags, IS_RUNNING) && tp->cno >= tp->offset + 1)
878                        tp->term = TERM_SEARCH;
879
880k_escape:       LINE_RESOLVE;
881
882                /*
883                 * Clean up for the 'R' command, restoring overwrite
884                 * characters, and making them into insert characters.
885                 */
886                if (LF_ISSET(TXT_REPLACE))
887                        txt_Rresolve(sp, &sp->tiq, tp, len);
888
889                /*
890                 * If there are any overwrite characters, copy down
891                 * any insert characters, and decrement the length.
892                 */
893                if (tp->owrite) {
894                        if (tp->insert)
895                                memmove(tp->lb + tp->cno,
896                                    tp->lb + tp->cno + tp->owrite, tp->insert);
897                        tp->len -= tp->owrite;
898                }
899
900                /*
901                 * Optionally resolve the lines into the file.  If not
902                 * resolving the lines into the file, end the line with
903                 * a nul.  If the line is empty, then set the length to
904                 * 0, the termination condition has already been set.
905                 *
906                 * XXX
907                 * This is wrong, should pass back a length.
908                 */
909                if (LF_ISSET(TXT_RESOLVE)) {
910                        if (txt_resolve(sp, &sp->tiq, flags))
911                                goto err;
912                } else {
913                        BINC_GOTO(sp, tp->lb, tp->lb_len, tp->len + 1);
914                        tp->lb[tp->len] = '\0';
915                }
916
917                /*
918                 * Set the return cursor position to rest on the last
919                 * inserted character.
920                 */
921                if (tp->cno != 0)
922                        --tp->cno;
923
924                /* Update the last line. */
925                if (vs_change(sp, tp->lno, LINE_RESET))
926                        return (1);
927                goto done;
928        case K_CARAT:                   /* Delete autoindent chars. */
929                if (tp->cno <= tp->ai && LF_ISSET(TXT_AUTOINDENT))
930                        carat = C_CARATSET;
931                goto ins_ch;
932        case K_ZERO:                    /* Delete autoindent chars. */
933                if (tp->cno <= tp->ai && LF_ISSET(TXT_AUTOINDENT))
934                        carat = C_ZEROSET;
935                goto ins_ch;
936        case K_CNTRLD:                  /* Delete autoindent char. */
937                /*
938                 * If in the first column or no characters to erase, ignore
939                 * the ^D (this matches historic practice).  If not doing
940                 * autoindent or already inserted non-ai characters, it's a
941                 * literal.  The latter test is done in the switch, as the
942                 * CARAT forms are N + 1, not N.
943                 */
944                if (!LF_ISSET(TXT_AUTOINDENT))
945                        goto ins_ch;
946                if (tp->cno == 0)
947                        goto resolve;
948
949                switch (carat) {
950                case C_CARATSET:        /* ^^D */
951                        if (tp->ai == 0 || tp->cno > tp->ai + tp->offset + 1)
952                                goto ins_ch;
953
954                        /* Save the ai string for later. */
955                        ait.lb = NULL;
956                        ait.lb_len = 0;
957                        BINC_GOTO(sp, ait.lb, ait.lb_len, tp->ai);
958                        memmove(ait.lb, tp->lb, tp->ai);
959                        ait.ai = ait.len = tp->ai;
960
961                        carat = C_NOCHANGE;
962                        goto leftmargin;
963                case C_ZEROSET:         /* 0^D */
964                        if (tp->ai == 0 || tp->cno > tp->ai + tp->offset + 1)
965                                goto ins_ch;
966
967                        carat = C_NOTSET;
968leftmargin:             tp->lb[tp->cno - 1] = ' ';
969                        tp->owrite += tp->cno - tp->offset;
970                        tp->ai = 0;
971                        tp->cno = tp->offset;
972                        break;
973                case C_NOTSET:          /* ^D */
974                        if (tp->ai == 0 || tp->cno > tp->ai + tp->offset)
975                                goto ins_ch;
976
977                        (void)txt_dent(sp, tp, 0);
978                        break;
979                default:
980                        abort();
981                }
982                break;
983        case K_VERASE:                  /* Erase the last character. */
984                /* If can erase over the prompt, return. */
985                if (tp->cno <= tp->offset && LF_ISSET(TXT_BS)) {
986                        tp->term = TERM_BS;
987                        goto done;
988                }
989
990                /*
991                 * If at the beginning of the line, try and drop back to a
992                 * previously inserted line.
993                 */
994                if (tp->cno == 0) {
995                        if ((ntp =
996                            txt_backup(sp, &sp->tiq, tp, &flags)) == NULL)
997                                goto err;
998                        tp = ntp;
999                        break;
1000                }
1001
1002                /* If nothing to erase, bell the user. */
1003                if (tp->cno <= tp->offset) {
1004                        if (!LF_ISSET(TXT_REPLAY))
1005                                txt_nomorech(sp);
1006                        break;
1007                }
1008
1009                /* Drop back one character. */
1010                --tp->cno;
1011
1012                /*
1013                 * Historically, vi didn't replace the erased characters with
1014                 * <blank>s, presumably because it's easier to fix a minor
1015                 * typing mistake and continue on if the previous letters are
1016                 * already there.  This is a problem for incremental searching,
1017                 * because the user can no longer tell where they are in the
1018                 * colon command line because the cursor is at the last search
1019                 * point in the screen.  So, if incrementally searching, erase
1020                 * the erased characters from the screen.
1021                 */
1022                if (FL_ISSET(is_flags, IS_RUNNING))
1023                        tp->lb[tp->cno] = ' ';
1024
1025                /*
1026                 * Increment overwrite, decrement ai if deleted.
1027                 *
1028                 * !!!
1029                 * Historic vi did not permit users to use erase characters
1030                 * to delete autoindent characters.  We do.  Eat hot death,
1031                 * POSIX.
1032                 */
1033                ++tp->owrite;
1034                if (tp->cno < tp->ai)
1035                        --tp->ai;
1036
1037                /* Reset if we deleted an incremental search character. */
1038                if (FL_ISSET(is_flags, IS_RUNNING))
1039                        FL_SET(is_flags, IS_RESTART);
1040                break;
1041        case K_VWERASE:                 /* Skip back one word. */
1042                /*
1043                 * If at the beginning of the line, try and drop back to a
1044                 * previously inserted line.
1045                 */
1046                if (tp->cno == 0) {
1047                        if ((ntp =
1048                            txt_backup(sp, &sp->tiq, tp, &flags)) == NULL)
1049                                goto err;
1050                        tp = ntp;
1051                }
1052
1053                /*
1054                 * If at offset, nothing to erase so bell the user.
1055                 */
1056                if (tp->cno <= tp->offset) {
1057                        if (!LF_ISSET(TXT_REPLAY))
1058                                txt_nomorech(sp);
1059                        break;
1060                }
1061
1062                /*
1063                 * The first werase goes back to any autoindent column and the
1064                 * second werase goes back to the offset.
1065                 *
1066                 * !!!
1067                 * Historic vi did not permit users to use erase characters to
1068                 * delete autoindent characters.
1069                 */
1070                if (tp->ai && tp->cno > tp->ai)
1071                        max = tp->ai;
1072                else {
1073                        tp->ai = 0;
1074                        max = tp->offset;
1075                }
1076
1077                /* Skip over trailing space characters. */
1078                while (tp->cno > max && isblank(tp->lb[tp->cno - 1])) {
1079                        --tp->cno;
1080                        ++tp->owrite;
1081                }
1082                if (tp->cno == max)
1083                        break;
1084                /*
1085                 * There are three types of word erase found on UNIX systems.
1086                 * They can be identified by how the string /a/b/c is treated
1087                 * -- as 1, 3, or 6 words.  Historic vi had two classes of
1088                 * characters, and strings were delimited by them and
1089                 * <blank>'s, so, 6 words.  The historic tty interface used
1090                 * <blank>'s to delimit strings, so, 1 word.  The algorithm
1091                 * offered in the 4.4BSD tty interface (as stty altwerase)
1092                 * treats it as 3 words -- there are two classes of
1093                 * characters, and strings are delimited by them and
1094                 * <blank>'s.  The difference is that the type of the first
1095                 * erased character erased is ignored, which is exactly right
1096                 * when erasing pathname components.  The edit options
1097                 * TXT_ALTWERASE and TXT_TTYWERASE specify the 4.4BSD tty
1098                 * interface and the historic tty driver behavior,
1099                 * respectively, and the default is the same as the historic
1100                 * vi behavior.
1101                 *
1102                 * Overwrite erased characters if doing incremental search;
1103                 * see comment above.
1104                 */
1105                if (LF_ISSET(TXT_TTYWERASE))
1106                        while (tp->cno > max) {
1107                                --tp->cno;
1108                                ++tp->owrite;
1109                                if (FL_ISSET(is_flags, IS_RUNNING))
1110                                        tp->lb[tp->cno] = ' ';
1111                                if (isblank(tp->lb[tp->cno - 1]))
1112                                        break;
1113                        }
1114                else {
1115                        if (LF_ISSET(TXT_ALTWERASE)) {
1116                                --tp->cno;
1117                                ++tp->owrite;
1118                                if (FL_ISSET(is_flags, IS_RUNNING))
1119                                        tp->lb[tp->cno] = ' ';
1120                                if (isblank(tp->lb[tp->cno - 1]))
1121                                        break;
1122                        }
1123                        if (tp->cno > max)
1124                                tmp = inword(tp->lb[tp->cno - 1]);
1125                        while (tp->cno > max) {
1126                                --tp->cno;
1127                                ++tp->owrite;
1128                                if (FL_ISSET(is_flags, IS_RUNNING))
1129                                        tp->lb[tp->cno] = ' ';
1130                                if (tmp != inword(tp->lb[tp->cno - 1])
1131                                    || isblank(tp->lb[tp->cno - 1]))
1132                                        break;
1133                        }
1134                }
1135
1136                /* Reset if we deleted an incremental search character. */
1137                if (FL_ISSET(is_flags, IS_RUNNING))
1138                        FL_SET(is_flags, IS_RESTART);
1139                break;
1140        case K_VKILL:                   /* Restart this line. */
1141                /*
1142                 * !!!
1143                 * If at the beginning of the line, try and drop back to a
1144                 * previously inserted line.  Historic vi did not permit
1145                 * users to go back to previous lines.
1146                 */
1147                if (tp->cno == 0) {
1148                        if ((ntp =
1149                            txt_backup(sp, &sp->tiq, tp, &flags)) == NULL)
1150                                goto err;
1151                        tp = ntp;
1152                }
1153
1154                /* If at offset, nothing to erase so bell the user. */
1155                if (tp->cno <= tp->offset) {
1156                        if (!LF_ISSET(TXT_REPLAY))
1157                                txt_nomorech(sp);
1158                        break;
1159                }
1160
1161                /*
1162                 * First kill goes back to any autoindent and second kill goes
1163                 * back to the offset.
1164                 *
1165                 * !!!
1166                 * Historic vi did not permit users to use erase characters to
1167                 * delete autoindent characters.
1168                 */
1169                if (tp->ai && tp->cno > tp->ai)
1170                        max = tp->ai;
1171                else {
1172                        tp->ai = 0;
1173                        max = tp->offset;
1174                }
1175                tp->owrite += tp->cno - max;
1176
1177                /*
1178                 * Overwrite erased characters if doing incremental search;
1179                 * see comment above.
1180                 */
1181                if (FL_ISSET(is_flags, IS_RUNNING))
1182                        do {
1183                                tp->lb[--tp->cno] = ' ';
1184                        } while (tp->cno > max);
1185                else
1186                        tp->cno = max;
1187
1188                /* Reset if we deleted an incremental search character. */
1189                if (FL_ISSET(is_flags, IS_RUNNING))
1190                        FL_SET(is_flags, IS_RESTART);
1191                break;
1192        case K_CNTRLT:                  /* Add autoindent characters. */
1193                if (!LF_ISSET(TXT_CNTRLT))
1194                        goto ins_ch;
1195                if (txt_dent(sp, tp, 1))
1196                        goto err;
1197                goto ebuf_chk;
1198        case K_RIGHTBRACE:
1199        case K_RIGHTPAREN:
1200                if (LF_ISSET(TXT_SHOWMATCH))
1201                        showmatch = 1;
1202                goto ins_ch;
1203        case K_BACKSLASH:               /* Quote next erase/kill. */
1204                /*
1205                 * !!!
1206                 * Historic vi tried to make abbreviations after a backslash
1207                 * escape work.  If you did ":ab x y", and inserted "x\^H",
1208                 * (assuming the erase character was ^H) you got "x^H", and
1209                 * no abbreviation was done.  If you inserted "x\z", however,
1210                 * it tried to back up and do the abbreviation, i.e. replace
1211                 * 'x' with 'y'.  The problem was it got it wrong, and you
1212                 * ended up with "zy\".
1213                 *
1214                 * This is really hard to do (you have to remember the
1215                 * word/non-word state, for example), and doesn't make any
1216                 * sense to me.  Both backslash and the characters it
1217                 * (usually) escapes will individually trigger the
1218                 * abbreviation, so I don't see why the combination of them
1219                 * wouldn't.  I don't expect to get caught on this one,
1220                 * particularly since it never worked right, but I've been
1221                 * wrong before.
1222                 *
1223                 * Do the tests for abbreviations, so ":ab xa XA",
1224                 * "ixa\<K_VERASE>" performs the abbreviation.
1225                 */
1226                quote = Q_BNEXT;
1227                goto insq_ch;
1228        case K_VLNEXT:                  /* Quote next character. */
1229                evp->e_c = '^';
1230                quote = Q_VNEXT;
1231                /*
1232                 * Turn on the quote flag so that the underlying routines
1233                 * quote the next character where it's possible. Turn off
1234                 * the input mapbiting flag so that we don't remap the next
1235                 * character.
1236                 */
1237                FL_SET(ec_flags, EC_QUOTED);
1238                FL_CLR(ec_flags, EC_MAPINPUT);
1239
1240                /*
1241                 * !!!
1242                 * Skip the tests for abbreviations, so ":ab xa XA",
1243                 * "ixa^V<space>" doesn't perform the abbreviation.
1244                 */
1245                goto insl_ch;
1246        case K_HEXCHAR:
1247                hexcnt = 1;
1248                goto insq_ch;
1249        default:                        /* Insert the character. */
1250ins_ch:         /*
1251                 * Historically, vi eliminated nul's out of hand.  If the
1252                 * beautify option was set, it also deleted any unknown
1253                 * ASCII value less than space (040) and the del character
1254                 * (0177), except for tabs.  Unknown is a key word here.
1255                 * Most vi documentation claims that it deleted everything
1256                 * but <tab>, <nl> and <ff>, as that's what the original
1257                 * 4BSD documentation said.  This is obviously wrong,
1258                 * however, as <esc> would be included in that list.  What
1259                 * we do is eliminate any unquoted, iscntrl() character that
1260                 * wasn't a replay and wasn't handled specially, except
1261                 * <tab> or <ff>.
1262                 */
1263                if (LF_ISSET(TXT_BEAUTIFY) && iscntrl(evp->e_c) &&
1264                    evp->e_value != K_FORMFEED && evp->e_value != K_TAB) {
1265                        msgq(sp, M_BERR,
1266                            "192|Illegal character; quote to enter");
1267                        if (LF_ISSET(TXT_REPLAY))
1268                                goto done;
1269                        break;
1270                }
1271
1272insq_ch:        /*
1273                 * If entering a non-word character after a word, check for
1274                 * abbreviations.  If there was one, discard replay characters.
1275                 * If entering a blank character, check for unmap commands,
1276                 * as well.
1277                 */
1278                if (!inword(evp->e_c)) {
1279                        if (abb == AB_INWORD &&
1280                            !LF_ISSET(TXT_REPLAY) && F_ISSET(gp, G_ABBREV)) {
1281                                if (txt_abbrev(sp, tp, &evp->e_c,
1282                                    LF_ISSET(TXT_INFOLINE), &tmp, &ab_turnoff))
1283                                        goto err;
1284                                if (tmp) {
1285                                        if (LF_ISSET(TXT_RECORD))
1286                                                rcol -= tmp + 1;
1287                                        goto resolve;
1288                                }
1289                        }
1290                        if (isblank(evp->e_c) && UNMAP_TST)
1291                                txt_unmap(sp, tp, &ec_flags);
1292                }
1293                if (abb != AB_NOTSET)
1294                        abb = inword(evp->e_c) ? AB_INWORD : AB_NOTWORD;
1295
1296insl_ch:        if (txt_insch(sp, tp, &evp->e_c, flags))
1297                        goto err;
1298
1299                /*
1300                 * If we're using K_VLNEXT to quote the next character, then
1301                 * we want the cursor to position itself on the ^ placeholder
1302                 * we're displaying, to match historic practice.
1303                 */
1304                if (quote == Q_VNEXT) {
1305                        --tp->cno;
1306                        ++tp->owrite;
1307                }
1308
1309                /*
1310                 * !!!
1311                 * Translate "<CH_HEX>[isxdigit()]*" to a character with
1312                 * a hex value: this test delimits the value by the max
1313                 * number of hex bytes.  Offset by one, we use 0 to mean
1314                 * that we've found <CH_HEX>.
1315                 */
1316                if (hexcnt != 0 && hexcnt++ == sizeof(CHAR_T) * 2 + 1) {
1317                        hexcnt = 0;
1318                        if (txt_hex(sp, tp))
1319                                goto err;
1320                }
1321
1322                /*
1323                 * Check to see if we've crossed the margin.
1324                 *
1325                 * !!!
1326                 * In the historic vi, the wrapmargin value was figured out
1327                 * using the display widths of the characters, i.e. <tab>
1328                 * characters were counted as two characters if the list edit
1329                 * option is set, but as the tabstop edit option number of
1330                 * characters otherwise.  That's what the vs_column() function
1331                 * gives us, so we use it.
1332                 */
1333                if (margin != 0) {
1334                        if (vs_column(sp, &tcol))
1335                                goto err;
1336                        if (tcol >= margin) {
1337                                if (txt_margin(sp, tp, &wmt, &tmp, flags))
1338                                        goto err;
1339                                if (tmp) {
1340                                        if (isblank(evp->e_c))
1341                                                wm_skip = 1;
1342                                        wm_set = 1;
1343                                        goto k_cr;
1344                                }
1345                        }
1346                }
1347
1348                /*
1349                 * If we've reached the end of the buffer, then we need to
1350                 * switch into insert mode.  This happens when there's a
1351                 * change to a mark and the user puts in more characters than
1352                 * the length of the motion.
1353                 */
1354ebuf_chk:       if (tp->cno >= tp->len) {
1355                        BINC_GOTO(sp, tp->lb, tp->lb_len, tp->len + 1);
1356                        LF_SET(TXT_APPENDEOL);
1357
1358                        tp->lb[tp->cno] = CH_CURSOR;
1359                        ++tp->insert;
1360                        ++tp->len;
1361                }
1362
1363                /* Step the quote state forward. */
1364                if (quote != Q_NOTSET) {
1365                        if (quote == Q_BNEXT)
1366                                quote = Q_BTHIS;
1367                        if (quote == Q_VNEXT)
1368                                quote = Q_VTHIS;
1369                }
1370                break;
1371        }
1372
1373#ifdef DEBUG
1374        if (tp->cno + tp->insert + tp->owrite != tp->len) {
1375                msgq(sp, M_ERR,
1376                    "len %u != cno: %u ai: %u insert %u overwrite %u",
1377                    tp->len, tp->cno, tp->ai, tp->insert, tp->owrite);
1378                if (LF_ISSET(TXT_REPLAY))
1379                        goto done;
1380                tp->len = tp->cno + tp->insert + tp->owrite;
1381        }
1382#endif
1383
1384resolve:/*
1385         * 1: If we don't need to know where the cursor really is and we're
1386         *    replaying text, keep going.
1387         */
1388        if (margin == 0 && LF_ISSET(TXT_REPLAY))
1389                goto replay;
1390
1391        /*
1392         * 2: Reset the line.  Don't bother unless we're about to wait on
1393         *    a character or we need to know where the cursor really is.
1394         *    We have to do this before showing matching characters so the
1395         *    user can see what they're matching.
1396         */
1397        if ((margin != 0 || !KEYS_WAITING(sp)) &&
1398            vs_change(sp, tp->lno, LINE_RESET))
1399                return (1);
1400
1401        /*
1402         * 3: If there aren't keys waiting, display the matching character.
1403         *    We have to do this before resolving any messages, otherwise
1404         *    the error message from a missing match won't appear correctly.
1405         */
1406        if (showmatch) {
1407                if (!KEYS_WAITING(sp) && txt_showmatch(sp, tp))
1408                        return (1);
1409                showmatch = 0;
1410        }
1411
1412        /*
1413         * 4: If there have been messages and we're not editing on the colon
1414         *    command line or doing file name completion, resolve them.
1415         */
1416        if ((vip->totalcount != 0 || F_ISSET(gp, G_BELLSCHED)) &&
1417            !F_ISSET(sp, SC_TINPUT_INFO) && !filec_redraw &&
1418            vs_resolve(sp, NULL, 0))
1419                return (1);
1420
1421        /*
1422         * 5: Refresh the screen if we're about to wait on a character or we
1423         *    need to know where the cursor really is.
1424         */
1425        if (margin != 0 || !KEYS_WAITING(sp)) {
1426                UPDATE_POSITION(sp, tp);
1427                if (vs_refresh(sp, margin != 0))
1428                        return (1);
1429        }
1430
1431        /* 6: Proceed with the incremental search. */
1432        if (FL_ISSET(is_flags, IS_RUNNING) && txt_isrch(sp, vp, tp, &is_flags))
1433                return (1);
1434
1435        /* 7: Next character... */
1436        if (LF_ISSET(TXT_REPLAY))
1437                goto replay;
1438        goto next;
1439
1440done:   /* Leave input mode. */
1441        F_CLR(sp, SC_TINPUT);
1442
1443        /* If recording for playback, save it. */
1444        if (LF_ISSET(TXT_RECORD))
1445                vip->rep_cnt = rcol;
1446
1447        /*
1448         * If not working on the colon command line, set the final cursor
1449         * position.
1450         */
1451        if (!F_ISSET(sp, SC_TINPUT_INFO)) {
1452                vp->m_final.lno = tp->lno;
1453                vp->m_final.cno = tp->cno;
1454        }
1455        return (0);
1456
1457err:
1458alloc_err:
1459        txt_err(sp, &sp->tiq);
1460        return (1);
1461}
1462
1463/*
1464 * txt_abbrev --
1465 *      Handle abbreviations.
1466 */
1467static int
1468txt_abbrev(sp, tp, pushcp, isinfoline, didsubp, turnoffp)
1469        SCR *sp;
1470        TEXT *tp;
1471        CHAR_T *pushcp;
1472        int isinfoline, *didsubp, *turnoffp;
1473{
1474        VI_PRIVATE *vip;
1475        CHAR_T ch, *p;
1476        SEQ *qp;
1477        size_t len, off;
1478
1479        /* Check to make sure we're not at the start of an append. */
1480        *didsubp = 0;
1481        if (tp->cno == tp->offset)
1482                return (0);
1483
1484        vip = VIP(sp);
1485
1486        /*
1487         * Find the start of the "word".
1488         *
1489         * !!!
1490         * We match historic practice, which, as far as I can tell, had an
1491         * off-by-one error.  The way this worked was that when the inserted
1492         * text switched from a "word" character to a non-word character,
1493         * vi would check for possible abbreviations.  It would then take the
1494         * type (i.e. word/non-word) of the character entered TWO characters
1495         * ago, and move backward in the text until reaching a character that
1496         * was not that type, or the beginning of the insert, the line, or
1497         * the file.  For example, in the string "abc<space>", when the <space>
1498         * character triggered the abbreviation check, the type of the 'b'
1499         * character was used for moving through the string.  Maybe there's a
1500         * reason for not using the first (i.e. 'c') character, but I can't
1501         * think of one.
1502         *
1503         * Terminate at the beginning of the insert or the character after the
1504         * offset character -- both can be tested for using tp->offset.
1505         */
1506        off = tp->cno - 1;                      /* Previous character. */
1507        p = tp->lb + off;
1508        len = 1;                                /* One character test. */
1509        if (off == tp->offset || isblank(p[-1]))
1510                goto search;
1511        if (inword(p[-1]))                      /* Move backward to change. */
1512                for (;;) {
1513                        --off; --p; ++len;
1514                        if (off == tp->offset || !inword(p[-1]))
1515                                break;
1516                }
1517        else
1518                for (;;) {
1519                        --off; --p; ++len;
1520                        if (off == tp->offset ||
1521                            inword(p[-1]) || isblank(p[-1]))
1522                                break;
1523                }
1524
1525        /*
1526         * !!!
1527         * Historic vi exploded abbreviations on the command line.  This has
1528         * obvious problems in that unabbreviating the string can be extremely
1529         * tricky, particularly if the string has, say, an embedded escape
1530         * character.  Personally, I think it's a stunningly bad idea.  Other
1531         * examples of problems this caused in historic vi are:
1532         *      :ab foo bar
1533         *      :ab foo baz
1534         * results in "bar" being abbreviated to "baz", which wasn't what the
1535         * user had in mind at all.  Also, the commands:
1536         *      :ab foo bar
1537         *      :unab foo<space>
1538         * resulted in an error message that "bar" wasn't mapped.  Finally,
1539         * since the string was already exploded by the time the unabbreviate
1540         * command got it, all it knew was that an abbreviation had occurred.
1541         * Cleverly, it checked the replacement string for its unabbreviation
1542         * match, which meant that the commands:
1543         *      :ab foo1 bar
1544         *      :ab foo2 bar
1545         *      :unab foo2
1546         * unabbreviate "foo1", and the commands:
1547         *      :ab foo bar
1548         *      :ab bar baz
1549         * unabbreviate "foo"!
1550         *
1551         * Anyway, people neglected to first ask my opinion before they wrote
1552         * macros that depend on this stuff, so, we make this work as follows.
1553         * When checking for an abbreviation on the command line, if we get a
1554         * string which is <blank> terminated and which starts at the beginning
1555         * of the line, we check to see it is the abbreviate or unabbreviate
1556         * commands.  If it is, turn abbreviations off and return as if no
1557         * abbreviation was found.  Note also, minor trickiness, so that if
1558         * the user erases the line and starts another command, we turn the
1559         * abbreviations back on.
1560         *
1561         * This makes the layering look like a Nachos Supreme.
1562         */
1563search: if (isinfoline)
1564                if (off == tp->ai || off == tp->offset)
1565                        if (ex_is_abbrev(p, len)) {
1566                                *turnoffp = 1;
1567                                return (0);
1568                        } else
1569                                *turnoffp = 0;
1570                else
1571                        if (*turnoffp)
1572                                return (0);
1573
1574        /* Check for any abbreviations. */
1575        if ((qp = seq_find(sp, NULL, NULL, p, len, SEQ_ABBREV, NULL)) == NULL)
1576                return (0);
1577
1578        /*
1579         * Push the abbreviation onto the tty stack.  Historically, characters
1580         * resulting from an abbreviation expansion were themselves subject to
1581         * map expansions, O_SHOWMATCH matching etc.  This means the expanded
1582         * characters will be re-tested for abbreviations.  It's difficult to
1583         * know what historic practice in this case was, since abbreviations
1584         * were applied to :colon command lines, so entering abbreviations that
1585         * looped was tricky, although possible.  In addition, obvious loops
1586         * didn't work as expected.  (The command ':ab a b|ab b c|ab c a' will
1587         * silently only implement and/or display the last abbreviation.)
1588         *
1589         * This implementation doesn't recover well from such abbreviations.
1590         * The main input loop counts abbreviated characters, and, when it
1591         * reaches a limit, discards any abbreviated characters on the queue.
1592         * It's difficult to back up to the original position, as the replay
1593         * queue would have to be adjusted, and the line state when an initial
1594         * abbreviated character was received would have to be saved.
1595         */
1596        ch = *pushcp;
1597        if (v_event_push(sp, NULL, &ch, 1, CH_ABBREVIATED))
1598                return (1);
1599        if (v_event_push(sp, NULL, qp->output, qp->olen, CH_ABBREVIATED))
1600                return (1);
1601
1602        /*
1603         * If the size of the abbreviation is larger than or equal to the size
1604         * of the original text, move to the start of the replaced characters,
1605         * and add their length to the overwrite count.
1606         *
1607         * If the abbreviation is smaller than the original text, we have to
1608         * delete the additional overwrite characters and copy down any insert
1609         * characters.
1610         */
1611        tp->cno -= len;
1612        if (qp->olen >= len)
1613                tp->owrite += len;
1614        else {
1615                if (tp->insert)
1616                        memmove(tp->lb + tp->cno + qp->olen,
1617                            tp->lb + tp->cno + tp->owrite + len, tp->insert);
1618                tp->owrite += qp->olen;
1619                tp->len -= len - qp->olen;
1620        }
1621
1622        /*
1623         * We return the length of the abbreviated characters.  This is so
1624         * the calling routine can replace the replay characters with the
1625         * abbreviation.  This means that subsequent '.' commands will produce
1626         * the same text, regardless of intervening :[un]abbreviate commands.
1627         * This is historic practice.
1628         */
1629        *didsubp = len;
1630        return (0);
1631}
1632
1633/*
1634 * txt_unmap --
1635 *      Handle the unmap command.
1636 */
1637static void
1638txt_unmap(sp, tp, ec_flagsp)
1639        SCR *sp;
1640        TEXT *tp;
1641        u_int32_t *ec_flagsp;
1642{
1643        size_t len, off;
1644        char *p;
1645
1646        /* Find the beginning of this "word". */
1647        for (off = tp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
1648                if (isblank(*p)) {
1649                        ++p;
1650                        break;
1651                }
1652                ++len;
1653                if (off == tp->ai || off == tp->offset)
1654                        break;
1655        }
1656
1657        /*
1658         * !!!
1659         * Historic vi exploded input mappings on the command line.  See the
1660         * txt_abbrev() routine for an explanation of the problems inherent
1661         * in this.
1662         *
1663         * We make this work as follows.  If we get a string which is <blank>
1664         * terminated and which starts at the beginning of the line, we check
1665         * to see it is the unmap command.  If it is, we return that the input
1666         * mapping should be turned off.  Note also, minor trickiness, so that
1667         * if the user erases the line and starts another command, we go ahead
1668         * an turn mapping back on.
1669         */
1670        if ((off == tp->ai || off == tp->offset) && ex_is_unmap(p, len))
1671                FL_CLR(*ec_flagsp, EC_MAPINPUT);
1672        else
1673                FL_SET(*ec_flagsp, EC_MAPINPUT);
1674}
1675
1676/*
1677 * txt_ai_resolve --
1678 *      When a line is resolved by <esc>, review autoindent characters.
1679 */
1680static void
1681txt_ai_resolve(sp, tp, changedp)
1682        SCR *sp;
1683        TEXT *tp;
1684        int *changedp;
1685{
1686        u_long ts;
1687        int del;
1688        size_t cno, len, new, old, scno, spaces, tab_after_sp, tabs;
1689        char *p;
1690
1691        *changedp = 0;
1692
1693        /*
1694         * If the line is empty, has an offset, or no autoindent
1695         * characters, we're done.
1696         */
1697        if (!tp->len || tp->offset || !tp->ai)
1698                return;
1699
1700        /*
1701         * If the length is less than or equal to the autoindent
1702         * characters, delete them.
1703         */
1704        if (tp->len <= tp->ai) {
1705                tp->ai = tp->cno = tp->len = 0;
1706                return;
1707        }
1708
1709        /*
1710         * The autoindent characters plus any leading <blank> characters
1711         * in the line are resolved into the minimum number of characters.
1712         * Historic practice.
1713         */
1714        ts = O_VAL(sp, O_TABSTOP);
1715
1716        /* Figure out the last <blank> screen column. */
1717        for (p = tp->lb, scno = 0, len = tp->len,
1718            spaces = tab_after_sp = 0; len-- && isblank(*p); ++p)
1719                if (*p == '\t') {
1720                        if (spaces)
1721                                tab_after_sp = 1;
1722                        scno += COL_OFF(scno, ts);
1723                } else {
1724                        ++spaces;
1725                        ++scno;
1726                }
1727
1728        /*
1729         * If there are no spaces, or no tabs after spaces and less than
1730         * ts spaces, it's already minimal.
1731         */
1732        if (!spaces || !tab_after_sp && spaces < ts)
1733                return;
1734
1735        /* Count up spaces/tabs needed to get to the target. */
1736        for (cno = 0, tabs = 0; cno + COL_OFF(cno, ts) <= scno; ++tabs)
1737                cno += COL_OFF(cno, ts);
1738        spaces = scno - cno;
1739
1740        /*
1741         * Figure out how many characters we're dropping -- if we're not
1742         * dropping any, it's already minimal, we're done.
1743         */
1744        old = p - tp->lb;
1745        new = spaces + tabs;
1746        if (old == new)
1747                return;
1748
1749        /* Shift the rest of the characters down, adjust the counts. */
1750        del = old - new;
1751        memmove(p - del, p, tp->len - old);
1752        tp->len -= del;
1753        tp->cno -= del;
1754
1755        /* Fill in space/tab characters. */
1756        for (p = tp->lb; tabs--;)
1757                *p++ = '\t';
1758        while (spaces--)
1759                *p++ = ' ';
1760        *changedp = 1;
1761}
1762
1763/*
1764 * v_txt_auto --
1765 *      Handle autoindent.  If aitp isn't NULL, use it, otherwise,
1766 *      retrieve the line.
1767 *
1768 * PUBLIC: int v_txt_auto __P((SCR *, recno_t, TEXT *, size_t, TEXT *));
1769 */
1770int
1771v_txt_auto(sp, lno, aitp, len, tp)
1772        SCR *sp;
1773        recno_t lno;
1774        TEXT *aitp, *tp;
1775        size_t len;
1776{
1777        size_t nlen;
1778        char *p, *t;
1779
1780        if (aitp == NULL) {
1781                /*
1782                 * If the ex append command is executed with an address of 0,
1783                 * it's possible to get here with a line number of 0.  Return
1784                 * an indent of 0.
1785                 */
1786                if (lno == 0) {
1787                        tp->ai = 0;
1788                        return (0);
1789                }
1790                if (db_get(sp, lno, DBG_FATAL, &t, &len))
1791                        return (1);
1792        } else
1793                t = aitp->lb;
1794
1795        /* Count whitespace characters. */
1796        for (p = t; len > 0; ++p, --len)
1797                if (!isblank(*p))
1798                        break;
1799
1800        /* Set count, check for no indentation. */
1801        if ((nlen = (p - t)) == 0)
1802                return (0);
1803
1804        /* Make sure the buffer's big enough. */
1805        BINC_RET(sp, tp->lb, tp->lb_len, tp->len + nlen);
1806
1807        /* Copy the buffer's current contents up. */
1808        if (tp->len != 0)
1809                memmove(tp->lb + nlen, tp->lb, tp->len);
1810        tp->len += nlen;
1811
1812        /* Copy the indentation into the new buffer. */
1813        memmove(tp->lb, t, nlen);
1814
1815        /* Set the autoindent count. */
1816        tp->ai = nlen;
1817        return (0);
1818}
1819
1820/*
1821 * txt_backup --
1822 *      Back up to the previously edited line.
1823 */
1824static TEXT *
1825txt_backup(sp, tiqh, tp, flagsp)
1826        SCR *sp;
1827        TEXTH *tiqh;
1828        TEXT *tp;
1829        u_int32_t *flagsp;
1830{
1831        VI_PRIVATE *vip;
1832        TEXT *ntp;
1833
1834        /* Get a handle on the previous TEXT structure. */
1835        if ((ntp = tp->q.cqe_prev) == (void *)tiqh) {
1836                if (!FL_ISSET(*flagsp, TXT_REPLAY))
1837                        msgq(sp, M_BERR,
1838                            "193|Already at the beginning of the insert");
1839                return (tp);
1840        }
1841
1842        /* Bookkeeping. */
1843        ntp->len = ntp->sv_len;
1844
1845        /* Handle appending to the line. */
1846        vip = VIP(sp);
1847        if (ntp->owrite == 0 && ntp->insert == 0) {
1848                ntp->lb[ntp->len] = CH_CURSOR;
1849                ++ntp->insert;
1850                ++ntp->len;
1851                FL_SET(*flagsp, TXT_APPENDEOL);
1852        } else
1853                FL_CLR(*flagsp, TXT_APPENDEOL);
1854
1855        /* Release the current TEXT. */
1856        CIRCLEQ_REMOVE(tiqh, tp, q);
1857        text_free(tp);
1858
1859        /* Update the old line on the screen. */
1860        if (vs_change(sp, ntp->lno + 1, LINE_DELETE))
1861                return (NULL);
1862
1863        /* Return the new/current TEXT. */
1864        return (ntp);
1865}
1866
1867/*
1868 * Text indentation is truly strange.  ^T and ^D do movements to the next or
1869 * previous shiftwidth value, i.e. for a 1-based numbering, with shiftwidth=3,
1870 * ^T moves a cursor on the 7th, 8th or 9th column to the 10th column, and ^D
1871 * moves it back.
1872 *
1873 * !!!
1874 * The ^T and ^D characters in historical vi had special meaning only when they
1875 * were the first characters entered after entering text input mode.  As normal
1876 * erase characters couldn't erase autoindent characters (^T in this case), it
1877 * meant that inserting text into previously existing text was strange -- ^T
1878 * only worked if it was the first keystroke(s), and then could only be erased
1879 * using ^D.  This implementation treats ^T specially anywhere it occurs in the
1880 * input, and permits the standard erase characters to erase the characters it
1881 * inserts.
1882 *
1883 * !!!
1884 * A fun test is to try:
1885 *      :se sw=4 ai list
1886 *      i<CR>^Tx<CR>^Tx<CR>^Tx<CR>^Dx<CR>^Dx<CR>^Dx<esc>
1887 * Historic vi loses some of the '$' marks on the line ends, but otherwise gets
1888 * it right.
1889 *
1890 * XXX
1891 * Technically, txt_dent should be part of the screen interface, as it requires
1892 * knowledge of character sizes, including <space>s, on the screen.  It's here
1893 * because it's a complicated little beast, and I didn't want to shove it down
1894 * into the screen.  It's probable that KEY_LEN will call into the screen once
1895 * there are screens with different character representations.
1896 *
1897 * txt_dent --
1898 *      Handle ^T indents, ^D outdents.
1899 *
1900 * If anything changes here, check the ex version to see if it needs similar
1901 * changes.
1902 */
1903static int
1904txt_dent(sp, tp, isindent)
1905        SCR *sp;
1906        TEXT *tp;
1907        int isindent;
1908{
1909        CHAR_T ch;
1910        u_long sw, ts;
1911        size_t cno, current, spaces, target, tabs, off;
1912        int ai_reset;
1913
1914        ts = O_VAL(sp, O_TABSTOP);
1915        sw = O_VAL(sp, O_SHIFTWIDTH);
1916
1917        /*
1918         * Since we don't know what precedes the character(s) being inserted
1919         * (or deleted), the preceding whitespace characters must be resolved.
1920         * An example is a <tab>, which doesn't need a full shiftwidth number
1921         * of columns because it's preceded by <space>s.  This is easy to get
1922         * if the user sets shiftwidth to a value less than tabstop (or worse,
1923         * something for which tabstop isn't a multiple) and then uses ^T to
1924         * indent, and ^D to outdent.
1925         *
1926         * Figure out the current and target screen columns.  In the historic
1927         * vi, the autoindent column was NOT determined using display widths
1928         * of characters as was the wrapmargin column.  For that reason, we
1929         * can't use the vs_column() function, but have to calculate it here.
1930         * This is slow, but it's normally only on the first few characters of
1931         * a line.
1932         */
1933        for (current = cno = 0; cno < tp->cno; ++cno)
1934                current += tp->lb[cno] == '\t' ?
1935                    COL_OFF(current, ts) : KEY_LEN(sp, tp->lb[cno]);
1936
1937        target = current;
1938        if (isindent)
1939                target += COL_OFF(target, sw);
1940        else
1941                target -= --target % sw;
1942
1943        /*
1944         * The AI characters will be turned into overwrite characters if the
1945         * cursor immediately follows them.  We test both the cursor position
1946         * and the indent flag because there's no single test.  (^T can only
1947         * be detected by the cursor position, and while we know that the test
1948         * is always true for ^D, the cursor can be in more than one place, as
1949         * "0^D" and "^D" are different.)
1950         */
1951        ai_reset = !isindent || tp->cno == tp->ai + tp->offset;
1952
1953        /*
1954         * Back up over any previous <blank> characters, changing them into
1955         * overwrite characters (including any ai characters).  Then figure
1956         * out the current screen column.
1957         */
1958        for (; tp->cno > tp->offset &&
1959            (tp->lb[tp->cno - 1] == ' ' || tp->lb[tp->cno - 1] == '\t');
1960            --tp->cno, ++tp->owrite);
1961        for (current = cno = 0; cno < tp->cno; ++cno)
1962                current += tp->lb[cno] == '\t' ?
1963                    COL_OFF(current, ts) : KEY_LEN(sp, tp->lb[cno]);
1964
1965        /*
1966         * If we didn't move up to or past the target, it's because there
1967         * weren't enough characters to delete, e.g. the first character
1968         * of the line was a tp->offset character, and the user entered
1969         * ^D to move to the beginning of a line.  An example of this is:
1970         *
1971         *      :set ai sw=4<cr>i<space>a<esc>i^T^D
1972         *
1973         * Otherwise, count up the total spaces/tabs needed to get from the
1974         * beginning of the line (or the last non-<blank> character) to the
1975         * target.
1976         */
1977        if (current >= target)
1978                spaces = tabs = 0;
1979        else {
1980                for (cno = current,
1981                    tabs = 0; cno + COL_OFF(cno, ts) <= target; ++tabs)
1982                        cno += COL_OFF(cno, ts);
1983                spaces = target - cno;
1984        }
1985
1986        /* If we overwrote ai characters, reset the ai count. */
1987        if (ai_reset)
1988                tp->ai = tabs + spaces;
1989
1990        /*
1991         * Call txt_insch() to insert each character, so that we get the
1992         * correct effect when we add a <tab> to replace N <spaces>.
1993         */
1994        for (ch = '\t'; tabs > 0; --tabs)
1995                (void)txt_insch(sp, tp, &ch, 0);
1996        for (ch = ' '; spaces > 0; --spaces)
1997                (void)txt_insch(sp, tp, &ch, 0);
1998        return (0);
1999}
2000
2001/*
2002 * txt_fc --
2003 *      File name completion.
2004 */
2005static int
2006txt_fc(sp, tp, redrawp)
2007        SCR *sp;
2008        TEXT *tp;
2009        int *redrawp;
2010{
2011        struct stat sb;
2012        ARGS **argv;
2013        CHAR_T s_ch;
2014        EXCMD cmd;
2015        size_t indx, len, nlen, off;
2016        int argc, trydir;
2017        char *p, *t;
2018
2019        trydir = 0;
2020        *redrawp = 0;
2021
2022        /*
2023         * Find the beginning of this "word" -- if we're at the beginning
2024         * of the line, it's a special case.
2025         */
2026        if (tp->cno == 1) {
2027                len = 0;
2028                p = tp->lb;
2029        } else
2030retry:          for (len = 0,
2031                    off = tp->cno - 1, p = tp->lb + off;; --off, --p) {
2032                        if (isblank(*p)) {
2033                                ++p;
2034                                break;
2035                        }
2036                        ++len;
2037                        if (off == tp->ai || off == tp->offset)
2038                                break;
2039                }
2040
2041        /*
2042         * Get enough space for a wildcard character.
2043         *
2044         * XXX
2045         * This won't work for "foo\", since the \ will escape the expansion
2046         * character.  I'm not sure if that's a bug or not...
2047         */
2048        off = p - tp->lb;
2049        BINC_RET(sp, tp->lb, tp->lb_len, tp->len + 1);
2050        p = tp->lb + off;
2051
2052        s_ch = p[len];
2053        p[len] = '*';
2054
2055        /* Build an ex command, and call the ex expansion routines. */
2056        ex_cinit(&cmd, 0, 0, OOBLNO, OOBLNO, 0, NULL);
2057        if (argv_init(sp, &cmd))
2058                return (1);
2059        if (argv_exp2(sp, &cmd, p, len + 1)) {
2060                p[len] = s_ch;
2061                return (0);
2062        }
2063        argc = cmd.argc;
2064        argv = cmd.argv;
2065
2066        p[len] = s_ch;
2067
2068        switch (argc) {
2069        case 0:                         /* No matches. */
2070                if (!trydir)
2071                        (void)sp->gp->scr_bell(sp);
2072                return (0);
2073        case 1:                         /* One match. */
2074                /* If something changed, do the exchange. */
2075                nlen = strlen(cmd.argv[0]->bp);
2076                if (len != nlen || memcmp(cmd.argv[0]->bp, p, len))
2077                        break;
2078
2079                /* If haven't done a directory test, do it now. */
2080                if (!trydir &&
2081                    !stat(cmd.argv[0]->bp, &sb) && S_ISDIR(sb.st_mode)) {
2082                        p += len;
2083                        goto isdir;
2084                }
2085
2086                /* If nothing changed, period, ring the bell. */
2087                if (!trydir)
2088                        (void)sp->gp->scr_bell(sp);
2089                return (0);
2090        default:                        /* Multiple matches. */
2091                *redrawp = 1;
2092                if (txt_fc_col(sp, argc, argv))
2093                        return (1);
2094
2095                /* Find the length of the shortest match. */
2096                for (nlen = cmd.argv[0]->len; --argc > 0;) {
2097                        if (cmd.argv[argc]->len < nlen)
2098                                nlen = cmd.argv[argc]->len;
2099                        for (indx = 0; indx < nlen &&
2100                            cmd.argv[argc]->bp[indx] == cmd.argv[0]->bp[indx];
2101                            ++indx);
2102                        nlen = indx;
2103                }
2104                break;
2105        }
2106
2107        /* Overwrite the expanded text first. */
2108        for (t = cmd.argv[0]->bp; len > 0 && nlen > 0; --len, --nlen)
2109                *p++ = *t++;
2110
2111        /* If lost text, make the remaining old text overwrite characters. */
2112        if (len) {
2113                tp->cno -= len;
2114                tp->owrite += len;
2115        }
2116
2117        /* Overwrite any overwrite characters next. */
2118        for (; nlen > 0 && tp->owrite > 0; --nlen, --tp->owrite, ++tp->cno)
2119                *p++ = *t++;
2120
2121        /* Shift remaining text up, and move the cursor to the end. */
2122        if (nlen) {
2123                off = p - tp->lb;
2124                BINC_RET(sp, tp->lb, tp->lb_len, tp->len + nlen);
2125                p = tp->lb + off;
2126
2127                tp->cno += nlen;
2128                tp->len += nlen;
2129
2130                if (tp->insert != 0)
2131                        (void)memmove(p + nlen, p, tp->insert);
2132                while (nlen--)
2133                        *p++ = *t++;
2134        }
2135
2136        /* If a single match and it's a directory, retry it. */
2137        if (argc == 1 && !stat(cmd.argv[0]->bp, &sb) && S_ISDIR(sb.st_mode)) {
2138isdir:          if (tp->owrite == 0) {
2139                        off = p - tp->lb;
2140                        BINC_RET(sp, tp->lb, tp->lb_len, tp->len + 1);
2141                        p = tp->lb + off;
2142                        if (tp->insert != 0)
2143                                (void)memmove(p + 1, p, tp->insert);
2144                        ++tp->len;
2145                } else
2146                        --tp->owrite;
2147
2148                ++tp->cno;
2149                *p++ = '/';
2150
2151                trydir = 1;
2152                goto retry;
2153        }
2154        return (0);
2155}
2156
2157/*
2158 * txt_fc_col --
2159 *      Display file names for file name completion.
2160 */
2161static int
2162txt_fc_col(sp, argc, argv)
2163        SCR *sp;
2164        int argc;
2165        ARGS **argv;
2166{
2167        ARGS **av;
2168        CHAR_T *p;
2169        GS *gp;
2170        size_t base, cnt, col, colwidth, numrows, numcols, prefix, row;
2171        int ac, nf, reset;
2172
2173        gp = sp->gp;
2174
2175        /* Trim any directory prefix common to all of the files. */
2176        if ((p = strrchr(argv[0]->bp, '/')) == NULL)
2177                prefix = 0;
2178        else {
2179                prefix = (p - argv[0]->bp) + 1;
2180                for (ac = argc - 1, av = argv + 1; ac > 0; --ac, ++av)
2181                        if (av[0]->len < prefix ||
2182                            memcmp(av[0]->bp, argv[0]->bp, prefix)) {
2183                                prefix = 0;
2184                                break;
2185                        }
2186        }
2187
2188        /*
2189         * Figure out the column width for the longest name.  Output is done on
2190         * 6 character "tab" boundaries for no particular reason.  (Since we
2191         * don't output tab characters, we ignore the terminal's tab settings.)
2192         * Ignore the user's tab setting because we have no idea how reasonable
2193         * it is.
2194         */
2195        for (ac = argc, av = argv, colwidth = 0; ac > 0; --ac, ++av) {
2196                for (col = 0, p = av[0]->bp + prefix; *p != '\0'; ++p)
2197                        col += KEY_LEN(sp, *p);
2198                if (col > colwidth)
2199                        colwidth = col;
2200        }
2201        colwidth += COL_OFF(colwidth, 6);
2202
2203        /*
2204         * Writing to the bottom line of the screen is always turned off when
2205         * SC_TINPUT_INFO is set.  Turn it back on, we know what we're doing.
2206         */
2207        if (F_ISSET(sp, SC_TINPUT_INFO)) {
2208                reset = 1;
2209                F_CLR(sp, SC_TINPUT_INFO);
2210        } else
2211                reset = 0;
2212
2213#define CHK_INTR                                                        \
2214        if (F_ISSET(gp, G_INTERRUPTED))                                 \
2215                goto intr;
2216
2217        /* If the largest file name is too large, just print them. */
2218        if (colwidth > sp->cols) {
2219                p = msg_print(sp, av[0]->bp + prefix, &nf);
2220                for (ac = argc, av = argv; ac > 0; --ac, ++av) {
2221                        (void)ex_printf(sp, "%s\n", p);
2222                        if (F_ISSET(gp, G_INTERRUPTED))
2223                                break;
2224                }
2225                if (nf)
2226                        FREE_SPACE(sp, p, 0);
2227                CHK_INTR;
2228        } else {
2229                /* Figure out the number of columns. */
2230                numcols = (sp->cols - 1) / colwidth;
2231                if (argc > numcols) {
2232                        numrows = argc / numcols;
2233                        if (argc % numcols)
2234                                ++numrows;
2235                } else
2236                        numrows = 1;
2237
2238                /* Display the files in sorted order. */
2239                for (row = 0; row < numrows; ++row) {
2240                        for (base = row, col = 0; col < numcols; ++col) {
2241                                p = msg_print(sp, argv[base]->bp + prefix, &nf);
2242                                cnt = ex_printf(sp, "%s", p);
2243                                if (nf)
2244                                        FREE_SPACE(sp, p, 0);
2245                                CHK_INTR;
2246                                if ((base += numrows) >= argc)
2247                                        break;
2248                                (void)ex_printf(sp,
2249                                    "%*s", (int)(colwidth - cnt), "");
2250                                CHK_INTR;
2251                        }
2252                        (void)ex_puts(sp, "\n");
2253                        CHK_INTR;
2254                }
2255                (void)ex_puts(sp, "\n");
2256                CHK_INTR;
2257        }
2258        (void)ex_fflush(sp);
2259
2260        if (0) {
2261intr:           F_CLR(gp, G_INTERRUPTED);
2262        }
2263        if (reset)
2264                F_SET(sp, SC_TINPUT_INFO);
2265
2266        return (0);
2267}
2268
2269/*
2270 * txt_emark --
2271 *      Set the end mark on the line.
2272 */
2273static int
2274txt_emark(sp, tp, cno)
2275        SCR *sp;
2276        TEXT *tp;
2277        size_t cno;
2278{
2279        CHAR_T ch, *kp;
2280        size_t chlen, nlen, olen;
2281        char *p;
2282
2283        ch = CH_ENDMARK;
2284
2285        /*
2286         * The end mark may not be the same size as the current character.
2287         * Don't let the line shift.
2288         */
2289        nlen = KEY_LEN(sp, ch);
2290        if (tp->lb[cno] == '\t')
2291                (void)vs_columns(sp, tp->lb, tp->lno, &cno, &olen);
2292        else
2293                olen = KEY_LEN(sp, tp->lb[cno]);
2294
2295        /*
2296         * If the line got longer, well, it's weird, but it's easy.  If
2297         * it's the same length, it's easy.  If it got shorter, we have
2298         * to fix it up.
2299         */
2300        if (olen > nlen) {
2301                BINC_RET(sp, tp->lb, tp->lb_len, tp->len + olen);
2302                chlen = olen - nlen;
2303                if (tp->insert != 0)
2304                        memmove(tp->lb + cno + 1 + chlen,
2305                            tp->lb + cno + 1, tp->insert);
2306
2307                tp->len += chlen;
2308                tp->owrite += chlen;
2309                p = tp->lb + cno;
2310                if (tp->lb[cno] == '\t')
2311                        for (cno += chlen; chlen--;)
2312                                *p++ = ' ';
2313                else
2314                        for (kp = KEY_NAME(sp, tp->lb[cno]),
2315                            cno += chlen; chlen--;)
2316                                *p++ = *kp++;
2317        }
2318        tp->lb[cno] = ch;
2319        return (vs_change(sp, tp->lno, LINE_RESET));
2320}
2321
2322/*
2323 * txt_err --
2324 *      Handle an error during input processing.
2325 */
2326static void
2327txt_err(sp, tiqh)
2328        SCR *sp;
2329        TEXTH *tiqh;
2330{
2331        recno_t lno;
2332
2333        /*
2334         * The problem with input processing is that the cursor is at an
2335         * indeterminate position since some input may have been lost due
2336         * to a malloc error.  So, try to go back to the place from which
2337         * the cursor started, knowing that it may no longer be available.
2338         *
2339         * We depend on at least one line number being set in the text
2340         * chain.
2341         */
2342        for (lno = tiqh->cqh_first->lno;
2343            !db_exist(sp, lno) && lno > 0; --lno);
2344
2345        sp->lno = lno == 0 ? 1 : lno;
2346        sp->cno = 0;
2347
2348        /* Redraw the screen, just in case. */
2349        F_SET(sp, SC_SCR_REDRAW);
2350}
2351
2352/*
2353 * txt_hex --
2354 *      Let the user insert any character value they want.
2355 *
2356 * !!!
2357 * This is an extension.  The pattern "^X[0-9a-fA-F]*" is a way
2358 * for the user to specify a character value which their keyboard
2359 * may not be able to enter.
2360 */
2361static int
2362txt_hex(sp, tp)
2363        SCR *sp;
2364        TEXT *tp;
2365{
2366        CHAR_T savec;
2367        size_t len, off;
2368        u_long value;
2369        char *p, *wp;
2370
2371        /*
2372         * Null-terminate the string.  Since nul isn't a legal hex value,
2373         * this should be okay, and lets us use a local routine, which
2374         * presumably understands the character set, to convert the value.
2375         */
2376        savec = tp->lb[tp->cno];
2377        tp->lb[tp->cno] = 0;
2378
2379        /* Find the previous CH_HEX character. */
2380        for (off = tp->cno - 1, p = tp->lb + off, len = 0;; --p, --off, ++len) {
2381                if (*p == CH_HEX) {
2382                        wp = p + 1;
2383                        break;
2384                }
2385                /* Not on this line?  Shouldn't happen. */
2386                if (off == tp->ai || off == tp->offset)
2387                        goto nothex;
2388        }
2389
2390        /* If length of 0, then it wasn't a hex value. */
2391        if (len == 0)
2392                goto nothex;
2393
2394        /* Get the value. */
2395        errno = 0;
2396        value = strtol(wp, NULL, 16);
2397        if (errno || value > MAX_CHAR_T) {
2398nothex:         tp->lb[tp->cno] = savec;
2399                return (0);
2400        }
2401
2402        /* Restore the original character. */
2403        tp->lb[tp->cno] = savec;
2404
2405        /* Adjust the bookkeeping. */
2406        tp->cno -= len;
2407        tp->len -= len;
2408        tp->lb[tp->cno - 1] = value;
2409
2410        /* Copy down any overwrite characters. */
2411        if (tp->owrite)
2412                memmove(tp->lb + tp->cno, tp->lb + tp->cno + len, tp->owrite);
2413
2414        /* Copy down any insert characters. */
2415        if (tp->insert)
2416                memmove(tp->lb + tp->cno + tp->owrite,
2417                    tp->lb + tp->cno + tp->owrite + len, tp->insert);
2418
2419        return (0);
2420}
2421
2422/*
2423 * txt_insch --
2424 *
2425 * !!!
2426 * Historic vi did a special screen optimization for tab characters.  As an
2427 * example, for the keystrokes "iabcd<esc>0C<tab>", the tab overwrote the
2428 * rest of the string when it was displayed.
2429 *
2430 * Because early versions of this implementation redisplayed the entire line
2431 * on each keystroke, the "bcd" was pushed to the right as it ignored that
2432 * the user had "promised" to change the rest of the characters.  However,
2433 * the historic vi implementation had an even worse bug: given the keystrokes
2434 * "iabcd<esc>0R<tab><esc>", the "bcd" disappears, and magically reappears
2435 * on the second <esc> key.
2436 *
2437 * POSIX 1003.2 requires (will require) that this be fixed, specifying that
2438 * vi overwrite characters the user has committed to changing, on the basis
2439 * of the screen space they require, but that it not overwrite other characters.
2440 */
2441static int
2442txt_insch(sp, tp, chp, flags)
2443        SCR *sp;
2444        TEXT *tp;
2445        CHAR_T *chp;
2446        u_int flags;
2447{
2448        CHAR_T *kp, savech;
2449        size_t chlen, cno, copydown, olen, nlen;
2450        char *p;
2451
2452        /*
2453         * The 'R' command does one-for-one replacement, because there's
2454         * no way to know how many characters the user intends to replace.
2455         */
2456        if (LF_ISSET(TXT_REPLACE)) {
2457                if (tp->owrite) {
2458                        --tp->owrite;
2459                        tp->lb[tp->cno++] = *chp;
2460                        return (0);
2461                }
2462        } else if (tp->owrite) {                /* Overwrite a character. */
2463                cno = tp->cno;
2464
2465                /*
2466                 * If the old or new characters are tabs, then the length of the
2467                 * display depends on the character position in the display.  We
2468                 * don't even try to handle this here, just ask the screen.
2469                 */
2470                if (*chp == '\t') {
2471                        savech = tp->lb[cno];
2472                        tp->lb[cno] = '\t';
2473                        (void)vs_columns(sp, tp->lb, tp->lno, &cno, &nlen);
2474                        tp->lb[cno] = savech;
2475                } else
2476                        nlen = KEY_LEN(sp, *chp);
2477
2478                /*
2479                 * Eat overwrite characters until we run out of them or we've
2480                 * handled the length of the new character.  If we only eat
2481                 * part of an overwrite character, break it into its component
2482                 * elements and display the remaining components.
2483                 */
2484                for (copydown = 0; nlen != 0 && tp->owrite != 0;) {
2485                        --tp->owrite;
2486
2487                        if (tp->lb[cno] == '\t')
2488                                (void)vs_columns(sp,
2489                                    tp->lb, tp->lno, &cno, &olen);
2490                        else
2491                                olen = KEY_LEN(sp, tp->lb[cno]);
2492
2493                        if (olen == nlen) {
2494                                nlen = 0;
2495                                break;
2496                        }
2497                        if (olen < nlen) {
2498                                ++copydown;
2499                                nlen -= olen;
2500                        } else {
2501                                BINC_RET(sp,
2502                                    tp->lb, tp->lb_len, tp->len + olen);
2503                                chlen = olen - nlen;
2504                                memmove(tp->lb + cno + 1 + chlen,
2505                                    tp->lb + cno + 1, tp->owrite + tp->insert);
2506
2507                                tp->len += chlen;
2508                                tp->owrite += chlen;
2509                                if (tp->lb[cno] == '\t')
2510                                        for (p = tp->lb + cno + 1; chlen--;)
2511                                                *p++ = ' ';
2512                                else
2513                                        for (kp =
2514                                            KEY_NAME(sp, tp->lb[cno]) + nlen,
2515                                            p = tp->lb + cno + 1; chlen--;)
2516                                                *p++ = *kp++;
2517                                nlen = 0;
2518                                break;
2519                        }
2520                }
2521
2522                /*
2523                 * If had to erase several characters, we adjust the total
2524                 * count, and if there are any characters left, shift them
2525                 * into position.
2526                 */
2527                if (copydown != 0 && (tp->len -= copydown) != 0)
2528                        memmove(tp->lb + cno, tp->lb + cno + copydown,
2529                            tp->owrite + tp->insert + copydown);
2530
2531                /* If we had enough overwrite characters, we're done. */
2532                if (nlen == 0) {
2533                        tp->lb[tp->cno++] = *chp;
2534                        return (0);
2535                }
2536        }
2537
2538        /* Check to see if the character fits into the input buffer. */
2539        BINC_RET(sp, tp->lb, tp->lb_len, tp->len + 1);
2540
2541        ++tp->len;
2542        if (tp->insert) {                       /* Insert a character. */
2543                if (tp->insert == 1)
2544                        tp->lb[tp->cno + 1] = tp->lb[tp->cno];
2545                else
2546                        memmove(tp->lb + tp->cno + 1,
2547                            tp->lb + tp->cno, tp->owrite + tp->insert);
2548        }
2549        tp->lb[tp->cno++] = *chp;
2550        return (0);
2551}
2552
2553/*
2554 * txt_isrch --
2555 *      Do an incremental search.
2556 */
2557static int
2558txt_isrch(sp, vp, tp, is_flagsp)
2559        SCR *sp;
2560        VICMD *vp;
2561        TEXT *tp;
2562        u_int8_t *is_flagsp;
2563{
2564        MARK start;
2565        recno_t lno;
2566        u_int sf;
2567
2568        /* If it's a one-line screen, we don't do incrementals. */
2569        if (IS_ONELINE(sp)) {
2570                FL_CLR(*is_flagsp, IS_RUNNING);
2571                return (0);
2572        }
2573
2574        /*
2575         * If the user erases back to the beginning of the buffer, there's
2576         * nothing to search for.  Reset the cursor to the starting point.
2577         */
2578        if (tp->cno <= 1) {
2579                vp->m_final = vp->m_start;
2580                return (0);
2581        }
2582
2583        /*
2584         * If it's an RE quote character, and not quoted, ignore it until
2585         * we get another character.
2586         */
2587        if (tp->lb[tp->cno - 1] == '\\' &&
2588            (tp->cno == 2 || tp->lb[tp->cno - 2] != '\\'))
2589                return (0);
2590
2591        /*
2592         * If it's a magic shell character, and not quoted, reset the cursor
2593         * to the starting point.
2594         */
2595        if (strchr(O_STR(sp, O_SHELLMETA), tp->lb[tp->cno - 1]) != NULL &&
2596            (tp->cno == 2 || tp->lb[tp->cno - 2] != '\\'))
2597                vp->m_final = vp->m_start;
2598
2599        /*
2600         * If we see the search pattern termination character, then quit doing
2601         * an incremental search.  There may be more, e.g., ":/foo/;/bar/",
2602         * and we can't handle that incrementally.  Also, reset the cursor to
2603         * the original location, the ex search routines don't know anything
2604         * about incremental searches.
2605         */
2606        if (tp->lb[0] == tp->lb[tp->cno - 1] &&
2607            (tp->cno == 2 || tp->lb[tp->cno - 2] != '\\')) {
2608                vp->m_final = vp->m_start;
2609                FL_CLR(*is_flagsp, IS_RUNNING);
2610                return (0);
2611        }
2612               
2613        /*
2614         * Remember the input line and discard the special input map,
2615         * but don't overwrite the input line on the screen.
2616         */
2617        lno = tp->lno;
2618        F_SET(VIP(sp), VIP_S_MODELINE);
2619        F_CLR(sp, SC_TINPUT | SC_TINPUT_INFO);
2620        if (txt_map_end(sp))
2621                return (1);
2622
2623        /*
2624         * Specify a starting point and search.  If we find a match, move to
2625         * it and refresh the screen.  If we didn't find the match, then we
2626         * beep the screen.  When searching from the original cursor position,
2627         * we have to move the cursor, otherwise, we don't want to move the
2628         * cursor in case the text at the current position continues to match.
2629         */
2630        if (FL_ISSET(*is_flagsp, IS_RESTART)) {
2631                start = vp->m_start;
2632                sf = SEARCH_SET;
2633        } else {
2634                start = vp->m_final;
2635                sf = SEARCH_INCR | SEARCH_SET;
2636        }
2637
2638        if (tp->lb[0] == '/' ?
2639            !f_search(sp,
2640            &start, &vp->m_final, tp->lb + 1, tp->cno - 1, NULL, sf) :
2641            !b_search(sp,
2642            &start, &vp->m_final, tp->lb + 1, tp->cno - 1, NULL, sf)) {
2643                sp->lno = vp->m_final.lno;
2644                sp->cno = vp->m_final.cno;
2645                FL_CLR(*is_flagsp, IS_RESTART);
2646
2647                if (!KEYS_WAITING(sp) && vs_refresh(sp, 0))
2648                        return (1);
2649        } else
2650                FL_SET(*is_flagsp, IS_RESTART);
2651
2652        /* Reinstantiate the special input map. */
2653        if (txt_map_init(sp))
2654                return (1);
2655        F_CLR(VIP(sp), VIP_S_MODELINE);
2656        F_SET(sp, SC_TINPUT | SC_TINPUT_INFO);
2657
2658        /* Reset the line number of the input line. */
2659        tp->lno = TMAP[0].lno;
2660
2661        /*
2662         * If the colon command-line moved, i.e. the screen scrolled,
2663         * refresh the input line.
2664         *
2665         * XXX
2666         * We shouldn't be calling vs_line, here -- we need dirty bits
2667         * on entries in the SMAP array.
2668         */
2669        if (lno != TMAP[0].lno) {
2670                if (vs_line(sp, &TMAP[0], NULL, NULL))
2671                        return (1);
2672                (void)sp->gp->scr_refresh(sp, 0);
2673        }
2674        return (0);
2675}
2676
2677/*
2678 * txt_resolve --
2679 *      Resolve the input text chain into the file.
2680 */
2681static int
2682txt_resolve(sp, tiqh, flags)
2683        SCR *sp;
2684        TEXTH *tiqh;
2685        u_int32_t flags;
2686{
2687        VI_PRIVATE *vip;
2688        TEXT *tp;
2689        recno_t lno;
2690        int changed;
2691
2692        /*
2693         * The first line replaces a current line, and all subsequent lines
2694         * are appended into the file.  Resolve autoindented characters for
2695         * each line before committing it.  If the latter causes the line to
2696         * change, we have to redisplay it, otherwise the information cached
2697         * about the line will be wrong.
2698         */
2699        vip = VIP(sp);
2700        tp = tiqh->cqh_first;
2701
2702        if (LF_ISSET(TXT_AUTOINDENT))
2703                txt_ai_resolve(sp, tp, &changed);
2704        else
2705                changed = 0;
2706        if (db_set(sp, tp->lno, tp->lb, tp->len) ||
2707            changed && vs_change(sp, tp->lno, LINE_RESET))
2708                return (1);
2709
2710        for (lno = tp->lno; (tp = tp->q.cqe_next) != (void *)&sp->tiq; ++lno) {
2711                if (LF_ISSET(TXT_AUTOINDENT))
2712                        txt_ai_resolve(sp, tp, &changed);
2713                else
2714                        changed = 0;
2715                if (db_append(sp, 0, lno, tp->lb, tp->len) ||
2716                    changed && vs_change(sp, tp->lno, LINE_RESET))
2717                        return (1);
2718        }
2719
2720        /*
2721         * Clear the input flag, the look-aside buffer is no longer valid.
2722         * Has to be done as part of text resolution, or upon return we'll
2723         * be looking at incorrect data.
2724         */
2725        F_CLR(sp, SC_TINPUT);
2726
2727        return (0);
2728}
2729
2730/*
2731 * txt_showmatch --
2732 *      Show a character match.
2733 *
2734 * !!!
2735 * Historic vi tried to display matches even in the :colon command line.
2736 * I think not.
2737 */
2738static int
2739txt_showmatch(sp, tp)
2740        SCR *sp;
2741        TEXT *tp;
2742{
2743        GS *gp;
2744        VCS cs;
2745        MARK m;
2746        int cnt, endc, startc;
2747
2748        gp = sp->gp;
2749
2750        /*
2751         * Do a refresh first, in case we haven't done one in awhile,
2752         * so the user can see what we're complaining about.
2753         */
2754        UPDATE_POSITION(sp, tp);
2755        if (vs_refresh(sp, 1))
2756                return (1);
2757
2758        /*
2759         * We don't display the match if it's not on the screen.  Find
2760         * out what the first character on the screen is.
2761         */
2762        if (vs_sm_position(sp, &m, 0, P_TOP))
2763                return (1);
2764
2765        /* Initialize the getc() interface. */
2766        cs.cs_lno = tp->lno;
2767        cs.cs_cno = tp->cno - 1;
2768        if (cs_init(sp, &cs))
2769                return (1);
2770        startc = (endc = cs.cs_ch)  == ')' ? '(' : '{';
2771
2772        /* Search for the match. */
2773        for (cnt = 1;;) {
2774                if (cs_prev(sp, &cs))
2775                        return (1);
2776                if (cs.cs_flags != 0) {
2777                        if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF) {
2778                                msgq(sp, M_BERR,
2779                                    "Unmatched %s", KEY_NAME(sp, endc));
2780                                return (0);
2781                        }
2782                        continue;
2783                }
2784                if (cs.cs_ch == endc)
2785                        ++cnt;
2786                else if (cs.cs_ch == startc && --cnt == 0)
2787                        break;
2788        }
2789
2790        /* If the match is on the screen, move to it. */
2791        if (cs.cs_lno < m.lno || cs.cs_lno == m.lno && cs.cs_cno < m.cno)
2792                return (0);
2793        sp->lno = cs.cs_lno;
2794        sp->cno = cs.cs_cno;
2795        if (vs_refresh(sp, 1))
2796                return (1);
2797
2798        /* Wait for timeout or character arrival. */
2799        return (v_event_get(sp,
2800            NULL, O_VAL(sp, O_MATCHTIME) * 100, EC_TIMEOUT));
2801}
2802
2803/*
2804 * txt_margin --
2805 *      Handle margin wrap.
2806 */
2807static int
2808txt_margin(sp, tp, wmtp, didbreak, flags)
2809        SCR *sp;
2810        TEXT *tp, *wmtp;
2811        int *didbreak;
2812        u_int32_t flags;
2813{
2814        VI_PRIVATE *vip;
2815        size_t len, off;
2816        char *p, *wp;
2817
2818        /* Find the nearest previous blank. */
2819        for (off = tp->cno - 1, p = tp->lb + off, len = 0;; --off, --p, ++len) {
2820                if (isblank(*p)) {
2821                        wp = p + 1;
2822                        break;
2823                }
2824
2825                /*
2826                 * If reach the start of the line, there's nowhere to break.
2827                 *
2828                 * !!!
2829                 * Historic vi belled each time a character was entered after
2830                 * crossing the margin until a space was entered which could
2831                 * be used to break the line.  I don't as it tends to wake the
2832                 * cats.
2833                 */
2834                if (off == tp->ai || off == tp->offset) {
2835                        *didbreak = 0;
2836                        return (0);
2837                }
2838        }
2839
2840        /*
2841         * Store saved information about the rest of the line in the
2842         * wrapmargin TEXT structure.
2843         *
2844         * !!!
2845         * The offset field holds the length of the current characters
2846         * that the user entered, but which are getting split to the new
2847         * line -- it's going to be used to set the cursor value when we
2848         * move to the new line.
2849         */
2850        vip = VIP(sp);
2851        wmtp->lb = p + 1;
2852        wmtp->offset = len;
2853        wmtp->insert = LF_ISSET(TXT_APPENDEOL) ?  tp->insert - 1 : tp->insert;
2854        wmtp->owrite = tp->owrite;
2855
2856        /* Correct current bookkeeping information. */
2857        tp->cno -= len;
2858        if (LF_ISSET(TXT_APPENDEOL)) {
2859                tp->len -= len + tp->owrite + (tp->insert - 1);
2860                tp->insert = 1;
2861        } else {
2862                tp->len -= len + tp->owrite + tp->insert;
2863                tp->insert = 0;
2864        }
2865        tp->owrite = 0;
2866
2867        /*
2868         * !!!
2869         * Delete any trailing whitespace from the current line.
2870         */
2871        for (;; --p, --off) {
2872                if (!isblank(*p))
2873                        break;
2874                --tp->cno;
2875                --tp->len;
2876                if (off == tp->ai || off == tp->offset)
2877                        break;
2878        }
2879        *didbreak = 1;
2880        return (0);
2881}
2882
2883/*
2884 * txt_Rresolve --
2885 *      Resolve the input line for the 'R' command.
2886 */
2887static void
2888txt_Rresolve(sp, tiqh, tp, orig_len)
2889        SCR *sp;
2890        TEXTH *tiqh;
2891        TEXT *tp;
2892        const size_t orig_len;
2893{
2894        TEXT *ttp;
2895        size_t input_len, retain;
2896        char *p;
2897
2898        /*
2899         * Check to make sure that the cursor hasn't moved beyond
2900         * the end of the line.
2901         */
2902        if (tp->owrite == 0)
2903                return;
2904
2905        /*
2906         * Calculate how many characters the user has entered,
2907         * plus the blanks erased by <carriage-return>/<newline>s.
2908         */
2909        for (ttp = tiqh->cqh_first, input_len = 0;;) {
2910                input_len += ttp == tp ? tp->cno : ttp->len + ttp->R_erase;
2911                if ((ttp = ttp->q.cqe_next) == (void *)&sp->tiq)
2912                        break;
2913        }
2914
2915        /*
2916         * If the user has entered less characters than the original line
2917         * was long, restore any overwriteable characters to the original
2918         * characters.  These characters are entered as "insert characters",
2919         * because they're after the cursor and we don't want to lose them.
2920         * (This is okay because the R command has no insert characters.)
2921         * We set owrite to 0 so that the insert characters don't get copied
2922         * to somewhere else, which means that the line and the length have
2923         * to be adjusted here as well.
2924         *
2925         * We have to retrieve the original line because the original pinned
2926         * page has long since been discarded.  If it doesn't exist, that's
2927         * okay, the user just extended the file.
2928         */
2929        if (input_len < orig_len) {
2930                retain = MIN(tp->owrite, orig_len - input_len);
2931                if (db_get(sp,
2932                    tiqh->cqh_first->lno, DBG_FATAL | DBG_NOCACHE, &p, NULL))
2933                        return;
2934                memcpy(tp->lb + tp->cno, p + input_len, retain);
2935                tp->len -= tp->owrite - retain;
2936                tp->owrite = 0;
2937                tp->insert += retain;
2938        }
2939}
2940
2941/*
2942 * txt_nomorech --
2943 *      No more characters message.
2944 */
2945static void
2946txt_nomorech(sp)
2947        SCR *sp;
2948{
2949        msgq(sp, M_BERR, "194|No more characters to erase");
2950}
Note: See TracBrowser for help on using the repository browser.