GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/vi/build/../vi/v_txt.c Lines: 0 989 0.0 %
Date: 2017-11-13 Branches: 0 1111 0.0 %

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