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