xref: /titanic_52/usr/src/cmd/vi/port/ex_vops2.c (revision 23a1ccea6aac035f084a7a4cdc968687d1b02daf)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5bbfd0aa6Scf46844  * Common Development and Distribution License (the "License").
6bbfd0aa6Scf46844  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21*23a1cceaSRoger A. Faulkner 
227c478bd9Sstevel@tonic-gate /*
23*23a1cceaSRoger A. Faulkner  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
277c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /* Copyright (c) 1981 Regents of the University of California */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include "ex.h"
337c478bd9Sstevel@tonic-gate #include "ex_tty.h"
347c478bd9Sstevel@tonic-gate #include "ex_vis.h"
357c478bd9Sstevel@tonic-gate #ifndef PRESUNEUC
367c478bd9Sstevel@tonic-gate #include <wctype.h>
377c478bd9Sstevel@tonic-gate /* Undef putchar/getchar if they're defined. */
387c478bd9Sstevel@tonic-gate #ifdef putchar
397c478bd9Sstevel@tonic-gate #	undef putchar
407c478bd9Sstevel@tonic-gate #endif
417c478bd9Sstevel@tonic-gate #ifdef getchar
427c478bd9Sstevel@tonic-gate #	undef getchar
437c478bd9Sstevel@tonic-gate #endif
447c478bd9Sstevel@tonic-gate #endif /* PRESUNEUC */
457c478bd9Sstevel@tonic-gate 
463a5240e9Scf46844 extern size_t strlcpy(char *, const char *, size_t);
473a5240e9Scf46844 
487c478bd9Sstevel@tonic-gate /*
497c478bd9Sstevel@tonic-gate  * Low level routines for operations sequences,
507c478bd9Sstevel@tonic-gate  * and mostly, insert mode (and a subroutine
517c478bd9Sstevel@tonic-gate  * to read an input line, including in the echo area.)
527c478bd9Sstevel@tonic-gate  */
537c478bd9Sstevel@tonic-gate extern unsigned char	*vUA1, *vUA2;		/* extern; also in ex_vops.c */
547c478bd9Sstevel@tonic-gate extern unsigned char	*vUD1, *vUD2;		/* extern; also in ex_vops.c */
557c478bd9Sstevel@tonic-gate 
56bbfd0aa6Scf46844 #ifdef XPG6
57bbfd0aa6Scf46844 /* XPG6 assertion 313 & 254 [count]r\n :  Also used in ex_vmain.c */
58bbfd0aa6Scf46844 extern int redisplay;
59bbfd0aa6Scf46844 #endif
60bbfd0aa6Scf46844 
61f6db9f27Scf46844 int vmaxrep(unsigned char, int);
623a5240e9Scf46844 static void imultlinerep(int, line *, int, int);
633a5240e9Scf46844 static void omultlinerep(int, line *, int);
64bbfd0aa6Scf46844 #ifdef XPG6
65bbfd0aa6Scf46844 static void rmultlinerep(int, int);
66bbfd0aa6Scf46844 #endif
67bbfd0aa6Scf46844 void fixdisplay(void);
68f6db9f27Scf46844 
697c478bd9Sstevel@tonic-gate /*
707c478bd9Sstevel@tonic-gate  * Obleeperate characters in hardcopy
717c478bd9Sstevel@tonic-gate  * open with \'s.
727c478bd9Sstevel@tonic-gate  */
73f6db9f27Scf46844 void
74f6db9f27Scf46844 bleep(int i, unsigned char *cp)
757c478bd9Sstevel@tonic-gate {
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate 	i -= lcolumn(nextchr(cp));
787c478bd9Sstevel@tonic-gate 	do
797c478bd9Sstevel@tonic-gate 		putchar('\\' | QUOTE);
807c478bd9Sstevel@tonic-gate 	while (--i >= 0);
817c478bd9Sstevel@tonic-gate 	rubble = 1;
827c478bd9Sstevel@tonic-gate }
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate /*
857c478bd9Sstevel@tonic-gate  * Common code for middle part of delete
867c478bd9Sstevel@tonic-gate  * and change operating on parts of lines.
877c478bd9Sstevel@tonic-gate  */
88f6db9f27Scf46844 int
89f6db9f27Scf46844 vdcMID(void)
907c478bd9Sstevel@tonic-gate {
91f6db9f27Scf46844 	unsigned char *cp;
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	squish();
947c478bd9Sstevel@tonic-gate 	setLAST();
957c478bd9Sstevel@tonic-gate 	if (FIXUNDO)
967c478bd9Sstevel@tonic-gate 		vundkind = VCHNG, CP(vutmp, linebuf);
977c478bd9Sstevel@tonic-gate 	if (wcursor < cursor)
987c478bd9Sstevel@tonic-gate 		cp = wcursor, wcursor = cursor, cursor = cp;
997c478bd9Sstevel@tonic-gate 	vUD1 = vUA1 = vUA2 = cursor; vUD2 = wcursor;
100bbfd0aa6Scf46844 	/*
101bbfd0aa6Scf46844 	 * XPG6 assertion 273: Set vmcurs so that undo positions the
102bbfd0aa6Scf46844 	 * cursor column correctly when we've moved off the initial line
103bbfd0aa6Scf46844 	 * that was changed, as with the C, c, and s commands,
104bbfd0aa6Scf46844 	 * when G has moved us off the line, or when a
105bbfd0aa6Scf46844 	 * multi-line change was done.
106bbfd0aa6Scf46844 	 */
107bbfd0aa6Scf46844 	fixundo();
1087c478bd9Sstevel@tonic-gate 	return (lcolumn(wcursor));
1097c478bd9Sstevel@tonic-gate }
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate /*
1127c478bd9Sstevel@tonic-gate  * Take text from linebuf and stick it
1137c478bd9Sstevel@tonic-gate  * in the VBSIZE buffer BUF.  Used to save
1147c478bd9Sstevel@tonic-gate  * deleted text of part of line.
1157c478bd9Sstevel@tonic-gate  */
116f6db9f27Scf46844 void
117f6db9f27Scf46844 takeout(unsigned char *BUF)
1187c478bd9Sstevel@tonic-gate {
119f6db9f27Scf46844 	unsigned char *cp;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 	if (wcursor < linebuf)
1227c478bd9Sstevel@tonic-gate 		wcursor = linebuf;
1237c478bd9Sstevel@tonic-gate 	if (cursor == wcursor) {
124f6db9f27Scf46844 		(void) beep();
1257c478bd9Sstevel@tonic-gate 		return;
1267c478bd9Sstevel@tonic-gate 	}
1277c478bd9Sstevel@tonic-gate 	if (wcursor < cursor) {
1287c478bd9Sstevel@tonic-gate 		cp = wcursor;
1297c478bd9Sstevel@tonic-gate 		wcursor = cursor;
1307c478bd9Sstevel@tonic-gate 		cursor = cp;
1317c478bd9Sstevel@tonic-gate 	}
1327c478bd9Sstevel@tonic-gate 	setBUF(BUF);
1337c478bd9Sstevel@tonic-gate 	if ((unsigned char)BUF[128] == 0200)
134f6db9f27Scf46844 		(void) beep();
1357c478bd9Sstevel@tonic-gate }
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate /*
1387c478bd9Sstevel@tonic-gate  * Are we at the end of the printed representation of the
1397c478bd9Sstevel@tonic-gate  * line?  Used internally in hardcopy open.
1407c478bd9Sstevel@tonic-gate  */
141f6db9f27Scf46844 int
142f6db9f27Scf46844 ateopr(void)
1437c478bd9Sstevel@tonic-gate {
144f6db9f27Scf46844 	wchar_t i, c;
145f6db9f27Scf46844 	wchar_t *cp = vtube[destline] + destcol;
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 	for (i = WCOLS - destcol; i > 0; i--) {
1487c478bd9Sstevel@tonic-gate 		c = *cp++;
1497c478bd9Sstevel@tonic-gate 		if (c == 0) {
1507c478bd9Sstevel@tonic-gate 			/*
1517c478bd9Sstevel@tonic-gate 			 * Optimization to consider returning early, saving
1527c478bd9Sstevel@tonic-gate 			 * CPU time.  We have to make a special check that
1537c478bd9Sstevel@tonic-gate 			 * we aren't missing a mode indicator.
1547c478bd9Sstevel@tonic-gate 			 */
1557c478bd9Sstevel@tonic-gate 			if (destline == WECHO && destcol < WCOLS-11 && vtube[WECHO][WCOLS-20])
1567c478bd9Sstevel@tonic-gate 				return 0;
1577c478bd9Sstevel@tonic-gate 			return (1);
1587c478bd9Sstevel@tonic-gate 		}
1597c478bd9Sstevel@tonic-gate 		if (c != ' ' && (c & QUOTE) == 0)
1607c478bd9Sstevel@tonic-gate 			return (0);
1617c478bd9Sstevel@tonic-gate 	}
1627c478bd9Sstevel@tonic-gate 	return (1);
1637c478bd9Sstevel@tonic-gate }
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate /*
1667c478bd9Sstevel@tonic-gate  * Append.
1677c478bd9Sstevel@tonic-gate  *
1687c478bd9Sstevel@tonic-gate  * This routine handles the top level append, doing work
1697c478bd9Sstevel@tonic-gate  * as each new line comes in, and arranging repeatability.
1707c478bd9Sstevel@tonic-gate  * It also handles append with repeat counts, and calculation
1717c478bd9Sstevel@tonic-gate  * of autoindents for new lines.
1727c478bd9Sstevel@tonic-gate  */
1737c478bd9Sstevel@tonic-gate bool	vaifirst;
1747c478bd9Sstevel@tonic-gate bool	gobbled;
1757c478bd9Sstevel@tonic-gate unsigned char	*ogcursor;
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate static int 	INSCDCNT; /* number of ^D's (backtabs) in insertion buffer */
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate static int 	inscdcnt; /*
1807c478bd9Sstevel@tonic-gate 			   * count of ^D's (backtabs) not seen yet when doing
1817c478bd9Sstevel@tonic-gate 		 	   * repeat of insertion
1827c478bd9Sstevel@tonic-gate 			   */
1837c478bd9Sstevel@tonic-gate 
184f6db9f27Scf46844 void
185f6db9f27Scf46844 vappend(int ch, int cnt, int indent)
1867c478bd9Sstevel@tonic-gate {
187f6db9f27Scf46844 	int i;
188f6db9f27Scf46844 	unsigned char *gcursor;
1897c478bd9Sstevel@tonic-gate 	bool escape;
1907c478bd9Sstevel@tonic-gate 	int repcnt, savedoomed;
1917c478bd9Sstevel@tonic-gate 	short oldhold = hold;
1923a5240e9Scf46844 	int savecnt = cnt;
1933a5240e9Scf46844 	line *startsrcline;
1943a5240e9Scf46844 	int startsrccol, endsrccol;
1953a5240e9Scf46844 	int gotNL = 0;
1963a5240e9Scf46844 	int imultlinecnt = 0;
1973a5240e9Scf46844 	int omultlinecnt = 0;
1983a5240e9Scf46844 
1993a5240e9Scf46844 	if ((savecnt > 1) && (ch == 'o' || ch == 'O')) {
2003a5240e9Scf46844 		omultlinecnt = 1;
2013a5240e9Scf46844 	}
2023a5240e9Scf46844 #ifdef XPG6
2033a5240e9Scf46844 	if ((savecnt > 1) && (ch == 'a' || ch == 'A' || ch == 'i' || ch == 'I'))
2043a5240e9Scf46844 		imultlinecnt = 1;
2053a5240e9Scf46844 #endif /* XPG6 */
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	/*
2087c478bd9Sstevel@tonic-gate 	 * Before a move in hardopen when the line is dirty
2097c478bd9Sstevel@tonic-gate 	 * or we are in the middle of the printed representation,
2107c478bd9Sstevel@tonic-gate 	 * we retype the line to the left of the cursor so the
2117c478bd9Sstevel@tonic-gate 	 * insert looks clean.
2127c478bd9Sstevel@tonic-gate 	 */
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 	if (ch != 'o' && state == HARDOPEN && (rubble || !ateopr())) {
2157c478bd9Sstevel@tonic-gate 		rubble = 1;
2167c478bd9Sstevel@tonic-gate 		gcursor = cursor;
2177c478bd9Sstevel@tonic-gate 		i = *gcursor;
2187c478bd9Sstevel@tonic-gate 		*gcursor = ' ';
2197c478bd9Sstevel@tonic-gate 		wcursor = gcursor;
220f6db9f27Scf46844 		(void) vmove();
2217c478bd9Sstevel@tonic-gate 		*gcursor = i;
2227c478bd9Sstevel@tonic-gate 	}
223bbfd0aa6Scf46844 	/*
224bbfd0aa6Scf46844 	 * If vrep() passed indent = 0, this is the 'r' command,
225bbfd0aa6Scf46844 	 * so don't autoindent until the last char.
226bbfd0aa6Scf46844 	 */
2277c478bd9Sstevel@tonic-gate 	vaifirst = indent == 0;
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	/*
2307c478bd9Sstevel@tonic-gate 	 * Handle replace character by (eventually)
2317c478bd9Sstevel@tonic-gate 	 * limiting the number of input characters allowed
2327c478bd9Sstevel@tonic-gate 	 * in the vgetline routine.
2337c478bd9Sstevel@tonic-gate 	 */
2347c478bd9Sstevel@tonic-gate 	if (ch == 'r')
2357c478bd9Sstevel@tonic-gate 		repcnt = 2;
2367c478bd9Sstevel@tonic-gate 	else
2377c478bd9Sstevel@tonic-gate 		repcnt = 0;
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	/*
2407c478bd9Sstevel@tonic-gate 	 * If an autoindent is specified, then
2417c478bd9Sstevel@tonic-gate 	 * generate a mixture of blanks to tabs to implement
2427c478bd9Sstevel@tonic-gate 	 * it and place the cursor after the indent.
2437c478bd9Sstevel@tonic-gate 	 * Text read by the vgetline routine will be placed in genbuf,
2447c478bd9Sstevel@tonic-gate 	 * so the indent is generated there.
2457c478bd9Sstevel@tonic-gate 	 */
2467c478bd9Sstevel@tonic-gate 	if (value(vi_AUTOINDENT) && indent != 0) {
2477c478bd9Sstevel@tonic-gate 		unsigned char x;
2487c478bd9Sstevel@tonic-gate 		gcursor = genindent(indent);
2497c478bd9Sstevel@tonic-gate 		*gcursor = 0;
2507c478bd9Sstevel@tonic-gate 		vgotoCL(nqcolumn(lastchr(linebuf, cursor), genbuf));
2517c478bd9Sstevel@tonic-gate 	} else {
2527c478bd9Sstevel@tonic-gate 		gcursor = genbuf;
2537c478bd9Sstevel@tonic-gate 		*gcursor = 0;
2547c478bd9Sstevel@tonic-gate 		if (ch == 'o')
2557c478bd9Sstevel@tonic-gate 			vfixcurs();
2567c478bd9Sstevel@tonic-gate 	}
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	/*
2597c478bd9Sstevel@tonic-gate 	 * Prepare for undo.  Pointers delimit inserted portion of line.
2607c478bd9Sstevel@tonic-gate 	 */
2617c478bd9Sstevel@tonic-gate 	vUA1 = vUA2 = cursor;
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	/*
2647c478bd9Sstevel@tonic-gate 	 * If we are not in a repeated command and a ^@ comes in
2657c478bd9Sstevel@tonic-gate 	 * then this means the previous inserted text.
2667c478bd9Sstevel@tonic-gate 	 * If there is none or it was too long to be saved,
2677c478bd9Sstevel@tonic-gate 	 * then beep() and also arrange to undo any damage done
2687c478bd9Sstevel@tonic-gate 	 * so far (e.g. if we are a change.)
2697c478bd9Sstevel@tonic-gate 	 */
2707c478bd9Sstevel@tonic-gate 	switch (ch) {
2717c478bd9Sstevel@tonic-gate 	case 'r':
2727c478bd9Sstevel@tonic-gate 		break;
2737c478bd9Sstevel@tonic-gate 	case 'a':
2747c478bd9Sstevel@tonic-gate 		/*
2757c478bd9Sstevel@tonic-gate 		 * TRANSLATION_NOTE
2767c478bd9Sstevel@tonic-gate 		 *	"A" is a terse mode message corresponding to
2777c478bd9Sstevel@tonic-gate 		 *	"APPEND MODE".
2787c478bd9Sstevel@tonic-gate 		 *	Translated message of "A" must be 1 character (not byte).
2797c478bd9Sstevel@tonic-gate 		 *	Or, just leave it.
2807c478bd9Sstevel@tonic-gate 		 */
2817c478bd9Sstevel@tonic-gate 		if (value(vi_TERSE)) {
2827c478bd9Sstevel@tonic-gate 			vshowmode(gettext("A"));
2837c478bd9Sstevel@tonic-gate 		} else {
2847c478bd9Sstevel@tonic-gate 			vshowmode(gettext("APPEND MODE"));
2857c478bd9Sstevel@tonic-gate 		}
2867c478bd9Sstevel@tonic-gate 		break;
2877c478bd9Sstevel@tonic-gate 	case 's':
2887c478bd9Sstevel@tonic-gate 		/*
2897c478bd9Sstevel@tonic-gate 		 * TRANSLATION_NOTE
2907c478bd9Sstevel@tonic-gate 		 *	"S" is a terse mode message corresponding to
2917c478bd9Sstevel@tonic-gate 		 *	"SUBSTITUTE MODE".
2927c478bd9Sstevel@tonic-gate 		 *	Translated message of "S" must be 1 character (not byte).
2937c478bd9Sstevel@tonic-gate 		 *	Or, just leave it.
2947c478bd9Sstevel@tonic-gate 		 */
2957c478bd9Sstevel@tonic-gate 		if (value(vi_TERSE)) {
2967c478bd9Sstevel@tonic-gate 			vshowmode(gettext("S"));
2977c478bd9Sstevel@tonic-gate 		} else {
2987c478bd9Sstevel@tonic-gate 			vshowmode(gettext("SUBSTITUTE MODE"));
2997c478bd9Sstevel@tonic-gate 		}
3007c478bd9Sstevel@tonic-gate 		break;
3017c478bd9Sstevel@tonic-gate 	case 'c':
3027c478bd9Sstevel@tonic-gate 		/*
3037c478bd9Sstevel@tonic-gate 		 * TRANSLATION_NOTE
3047c478bd9Sstevel@tonic-gate 		 *	"C" is a terse mode message corresponding to
3057c478bd9Sstevel@tonic-gate 		 *	"CHANGE MODE".
3067c478bd9Sstevel@tonic-gate 		 *	Translated message of "C" must be 1 character (not byte).
3077c478bd9Sstevel@tonic-gate 		 *	Or, just leave it.
3087c478bd9Sstevel@tonic-gate 		 */
3097c478bd9Sstevel@tonic-gate 		if (value(vi_TERSE)) {
3107c478bd9Sstevel@tonic-gate 			vshowmode(gettext("C"));
3117c478bd9Sstevel@tonic-gate 		} else {
3127c478bd9Sstevel@tonic-gate 			vshowmode(gettext("CHANGE MODE"));
3137c478bd9Sstevel@tonic-gate 		}
3147c478bd9Sstevel@tonic-gate 		break;
3157c478bd9Sstevel@tonic-gate 	case 'R':
3167c478bd9Sstevel@tonic-gate 		/*
3177c478bd9Sstevel@tonic-gate 		 * TRANSLATION_NOTE
3187c478bd9Sstevel@tonic-gate 		 *	"R" is a terse mode message corresponding to
3197c478bd9Sstevel@tonic-gate 		 *	"REPLACE MODE".
3207c478bd9Sstevel@tonic-gate 		 *	Translated message of "R" must be 1 character (not byte).
3217c478bd9Sstevel@tonic-gate 		 *	Or, just leave it.
3227c478bd9Sstevel@tonic-gate 		 */
3237c478bd9Sstevel@tonic-gate 		if (value(vi_TERSE)) {
3247c478bd9Sstevel@tonic-gate 			vshowmode(gettext("R"));
3257c478bd9Sstevel@tonic-gate 		} else {
3267c478bd9Sstevel@tonic-gate 			vshowmode(gettext("REPLACE MODE"));
3277c478bd9Sstevel@tonic-gate 		}
3287c478bd9Sstevel@tonic-gate 		break;
3297c478bd9Sstevel@tonic-gate 	case 'o':
3307c478bd9Sstevel@tonic-gate 		/*
3317c478bd9Sstevel@tonic-gate 		 * TRANSLATION_NOTE
3327c478bd9Sstevel@tonic-gate 		 *	"O" is a terse mode message corresponding to
3337c478bd9Sstevel@tonic-gate 		 *	"OPEN MODE".
3347c478bd9Sstevel@tonic-gate 		 *	Translated message of "O" must be 1 character (not byte).
3357c478bd9Sstevel@tonic-gate 		 *	Or, just leave it.
3367c478bd9Sstevel@tonic-gate 		 */
3377c478bd9Sstevel@tonic-gate 		if (value(vi_TERSE)) {
3387c478bd9Sstevel@tonic-gate 			vshowmode(gettext("O"));
3397c478bd9Sstevel@tonic-gate 		} else {
3407c478bd9Sstevel@tonic-gate 			vshowmode(gettext("OPEN MODE"));
3417c478bd9Sstevel@tonic-gate 		}
3427c478bd9Sstevel@tonic-gate 		break;
3437c478bd9Sstevel@tonic-gate 	case 'i':
3447c478bd9Sstevel@tonic-gate 		/*
3457c478bd9Sstevel@tonic-gate 		 * TRANSLATION_NOTE
3467c478bd9Sstevel@tonic-gate 		 *	"I" is a terse mode message corresponding to
3477c478bd9Sstevel@tonic-gate 		 *	"INSERT MODE" and the following "INPUT MODE".
3487c478bd9Sstevel@tonic-gate 		 *	Translated message of "I" must be 1 character (not byte).
3497c478bd9Sstevel@tonic-gate 		 *	Or, just leave it.
3507c478bd9Sstevel@tonic-gate 		 */
3517c478bd9Sstevel@tonic-gate 		if (value(vi_TERSE)) {
3527c478bd9Sstevel@tonic-gate 			vshowmode(gettext("I"));
3537c478bd9Sstevel@tonic-gate 		} else {
3547c478bd9Sstevel@tonic-gate 			vshowmode(gettext("INSERT MODE"));
3557c478bd9Sstevel@tonic-gate 		}
3567c478bd9Sstevel@tonic-gate 		break;
3577c478bd9Sstevel@tonic-gate 	default:
3587c478bd9Sstevel@tonic-gate 		/*
3597c478bd9Sstevel@tonic-gate 		 * TRANSLATION_NOTE
3607c478bd9Sstevel@tonic-gate 		 *	"I" is a terse mode message corresponding to
3617c478bd9Sstevel@tonic-gate 		 *	"INPUT MODE" and the previous "INSERT MODE".
3627c478bd9Sstevel@tonic-gate 		 *	Translated message of "I" must be 1 character (not byte).
3637c478bd9Sstevel@tonic-gate 		 *	Or, just leave it.
3647c478bd9Sstevel@tonic-gate 		 */
3657c478bd9Sstevel@tonic-gate 		if (value(vi_TERSE)) {
3667c478bd9Sstevel@tonic-gate 			vshowmode(gettext("I"));
3677c478bd9Sstevel@tonic-gate 		} else {
3687c478bd9Sstevel@tonic-gate 			vshowmode(gettext("INPUT MODE"));
3697c478bd9Sstevel@tonic-gate 		}
3707c478bd9Sstevel@tonic-gate 	}
3717c478bd9Sstevel@tonic-gate 	ixlatctl(1);
3727c478bd9Sstevel@tonic-gate 	if ((vglobp && *vglobp == 0) || peekbr()) {
3737c478bd9Sstevel@tonic-gate 		if (INS[128] == 0200) {
374f6db9f27Scf46844 			(void) beep();
3757c478bd9Sstevel@tonic-gate 			if (!splitw)
3767c478bd9Sstevel@tonic-gate 				ungetkey('u');
3777c478bd9Sstevel@tonic-gate 			doomed = 0;
3787c478bd9Sstevel@tonic-gate 			hold = oldhold;
3797c478bd9Sstevel@tonic-gate 			return;
3807c478bd9Sstevel@tonic-gate 		}
3817c478bd9Sstevel@tonic-gate 		/*
3827c478bd9Sstevel@tonic-gate 		 * Unread input from INS.
3837c478bd9Sstevel@tonic-gate 		 * An escape will be generated at end of string.
3847c478bd9Sstevel@tonic-gate 		 * Hold off n^^2 type update on dumb terminals.
3857c478bd9Sstevel@tonic-gate 		 */
3867c478bd9Sstevel@tonic-gate 		vglobp = INS;
3877c478bd9Sstevel@tonic-gate 		inscdcnt = INSCDCNT;
3887c478bd9Sstevel@tonic-gate 		hold |= HOLDQIK;
3897c478bd9Sstevel@tonic-gate 	} else if (vglobp == 0) {
3907c478bd9Sstevel@tonic-gate 		/*
3917c478bd9Sstevel@tonic-gate 		 * Not a repeated command, get
3927c478bd9Sstevel@tonic-gate 		 * a new inserted text for repeat.
3937c478bd9Sstevel@tonic-gate 		 */
3947c478bd9Sstevel@tonic-gate 		INS[0] = 0;
3957c478bd9Sstevel@tonic-gate 		INS[128] = 0;
3967c478bd9Sstevel@tonic-gate 		INSCDCNT = 0;
3977c478bd9Sstevel@tonic-gate 	}
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	/*
4007c478bd9Sstevel@tonic-gate 	 * For wrapmargin to hack away second space after a '.'
4017c478bd9Sstevel@tonic-gate 	 * when the first space caused a line break we keep
4027c478bd9Sstevel@tonic-gate 	 * track that this happened in gobblebl, which says
4037c478bd9Sstevel@tonic-gate 	 * to gobble up a blank silently.
4047c478bd9Sstevel@tonic-gate 	 */
4057c478bd9Sstevel@tonic-gate 	gobblebl = 0;
4067c478bd9Sstevel@tonic-gate 
4073a5240e9Scf46844 	startsrcline = dot;
4083a5240e9Scf46844 	startsrccol = cursor - linebuf;
4093a5240e9Scf46844 
4107c478bd9Sstevel@tonic-gate 	/*
4117c478bd9Sstevel@tonic-gate 	 * Text gathering loop.
4127c478bd9Sstevel@tonic-gate 	 * New text goes into genbuf starting at gcursor.
4137c478bd9Sstevel@tonic-gate 	 * cursor preserves place in linebuf where text will eventually go.
4147c478bd9Sstevel@tonic-gate 	 */
4157c478bd9Sstevel@tonic-gate 	if (*cursor == 0 || state == CRTOPEN)
4167c478bd9Sstevel@tonic-gate 		hold |= HOLDROL;
4177c478bd9Sstevel@tonic-gate 	for (;;) {
4187c478bd9Sstevel@tonic-gate 		if (ch == 'r' && repcnt == 0)
4197c478bd9Sstevel@tonic-gate 			escape = 0;
4207c478bd9Sstevel@tonic-gate 		else {
4217c478bd9Sstevel@tonic-gate 			ixlatctl(1);
422bbfd0aa6Scf46844 			/*
423bbfd0aa6Scf46844 			 * When vgetline() returns, gcursor is
424bbfd0aa6Scf46844 			 * pointing to '\0' and vgetline() has
425bbfd0aa6Scf46844 			 * read an ESCAPE or NL.
426bbfd0aa6Scf46844 			 */
4277c478bd9Sstevel@tonic-gate 			gcursor = vgetline(repcnt, gcursor, &escape, ch);
4283a5240e9Scf46844 			if (escape == '\n') {
4293a5240e9Scf46844 				gotNL = 1;
430bbfd0aa6Scf46844 #ifdef XPG6
431bbfd0aa6Scf46844 				if (ch == 'r') {
432bbfd0aa6Scf46844 					/*
433bbfd0aa6Scf46844 					 * XPG6 assertion 313 [count]r\n :
434bbfd0aa6Scf46844 					 * Arrange to set cursor correctly.
435bbfd0aa6Scf46844 					 */
436bbfd0aa6Scf46844 					endsrccol = gcursor - genbuf - 1;
437bbfd0aa6Scf46844 				}
438bbfd0aa6Scf46844 #endif /* XPG6 */
4393a5240e9Scf46844 			} else {
4403a5240e9Scf46844 				/*
4413a5240e9Scf46844 				 * Upon escape, gcursor is pointing to '\0'
4423a5240e9Scf46844 				 * terminating the string in genbuf.
4433a5240e9Scf46844 				 */
4443a5240e9Scf46844 				endsrccol = gcursor - genbuf - 1;
4453a5240e9Scf46844 			}
4467c478bd9Sstevel@tonic-gate 			ixlatctl(0);
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 			/*
4497c478bd9Sstevel@tonic-gate 			 * After an append, stick information
4507c478bd9Sstevel@tonic-gate 			 * about the ^D's and ^^D's and 0^D's in
4517c478bd9Sstevel@tonic-gate 			 * the repeated text buffer so repeated
4527c478bd9Sstevel@tonic-gate 			 * inserts of stuff indented with ^D as backtab's
4537c478bd9Sstevel@tonic-gate 			 * can work.
4547c478bd9Sstevel@tonic-gate 			 */
4557c478bd9Sstevel@tonic-gate 			if (HADUP)
4567c478bd9Sstevel@tonic-gate 				addtext("^");
4577c478bd9Sstevel@tonic-gate 			else if (HADZERO)
4587c478bd9Sstevel@tonic-gate 				addtext("0");
4597c478bd9Sstevel@tonic-gate 			if(!vglobp)
4607c478bd9Sstevel@tonic-gate 				INSCDCNT = CDCNT;
4617c478bd9Sstevel@tonic-gate 			while (CDCNT > 0) {
4627c478bd9Sstevel@tonic-gate 				addtext("\004");
4637c478bd9Sstevel@tonic-gate 				CDCNT--;
4647c478bd9Sstevel@tonic-gate 			}
4657c478bd9Sstevel@tonic-gate 			if (gobbled)
4667c478bd9Sstevel@tonic-gate 				addtext(" ");
4677c478bd9Sstevel@tonic-gate 			addtext(ogcursor);
4687c478bd9Sstevel@tonic-gate 		}
4697c478bd9Sstevel@tonic-gate 		repcnt = 0;
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 		/*
4727c478bd9Sstevel@tonic-gate 		 * Smash the generated and preexisting indents together
4737c478bd9Sstevel@tonic-gate 		 * and generate one cleanly made out of tabs and spaces
474bbfd0aa6Scf46844 		 * if we are using autoindent and this isn't 'r' command.
4757c478bd9Sstevel@tonic-gate 		 */
4767c478bd9Sstevel@tonic-gate 		if (!vaifirst && value(vi_AUTOINDENT)) {
4777c478bd9Sstevel@tonic-gate 			i = fixindent(indent);
4787c478bd9Sstevel@tonic-gate 			if (!HADUP)
4797c478bd9Sstevel@tonic-gate 				indent = i;
4807c478bd9Sstevel@tonic-gate 			gcursor = strend(genbuf);
4817c478bd9Sstevel@tonic-gate 		}
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 		/*
4843a5240e9Scf46844 		 * Set cnt to 1 to avoid repeating the text on the same line.
4853a5240e9Scf46844 		 * Do this for commands 'i', 'I', 'a', and 'A', if we're
4863a5240e9Scf46844 		 * inserting anything with a newline for XPG6.  Always do this
4873a5240e9Scf46844 		 * for commands 'o' and 'O'.
4883a5240e9Scf46844 		 */
4893a5240e9Scf46844 		if ((imultlinecnt && gotNL) || omultlinecnt) {
4903a5240e9Scf46844 			cnt = 1;
4913a5240e9Scf46844 		}
4923a5240e9Scf46844 
4933a5240e9Scf46844 		/*
4947c478bd9Sstevel@tonic-gate 		 * Limit the repetition count based on maximum
4957c478bd9Sstevel@tonic-gate 		 * possible line length; do output implied
4967c478bd9Sstevel@tonic-gate 		 * by further count (> 1) and cons up the new line
4977c478bd9Sstevel@tonic-gate 		 * in linebuf.
4987c478bd9Sstevel@tonic-gate 		 */
4997c478bd9Sstevel@tonic-gate 		cnt = vmaxrep(ch, cnt);
500bbfd0aa6Scf46844 		/*
501bbfd0aa6Scf46844 		 * cursor points to linebuf
502bbfd0aa6Scf46844 		 * Copy remaining old text (cursor) in original
503bbfd0aa6Scf46844 		 * line to after new text (gcursor + 1) in genbuf.
504bbfd0aa6Scf46844 		 */
5057c478bd9Sstevel@tonic-gate 		CP(gcursor + 1, cursor);
506bbfd0aa6Scf46844 		/*
507bbfd0aa6Scf46844 		 * For [count] r \n command, when replacing [count] chars
508bbfd0aa6Scf46844 		 * with '\n', this loop replaces [count] chars with "".
509bbfd0aa6Scf46844 		 */
5107c478bd9Sstevel@tonic-gate 		do {
511bbfd0aa6Scf46844 			/* cp new text (genbuf) into linebuf (cursor) */
5127c478bd9Sstevel@tonic-gate 			CP(cursor, genbuf);
5137c478bd9Sstevel@tonic-gate 			if (cnt > 1) {
5147c478bd9Sstevel@tonic-gate 				int oldhold = hold;
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 				Outchar = vinschar;
5177c478bd9Sstevel@tonic-gate 				hold |= HOLDQIK;
518f6db9f27Scf46844 				viprintf("%s", genbuf);
5197c478bd9Sstevel@tonic-gate 				hold = oldhold;
5207c478bd9Sstevel@tonic-gate 				Outchar = vputchar;
5217c478bd9Sstevel@tonic-gate 			}
522bbfd0aa6Scf46844 			/* point cursor after new text in linebuf */
5237c478bd9Sstevel@tonic-gate 			cursor += gcursor - genbuf;
5247c478bd9Sstevel@tonic-gate 		} while (--cnt > 0);
5257c478bd9Sstevel@tonic-gate 		endim();
5267c478bd9Sstevel@tonic-gate 		vUA2 = cursor;
527bbfd0aa6Scf46844 		/* add the remaining old text after the cursor */
5287c478bd9Sstevel@tonic-gate 		if (escape != '\n')
5297c478bd9Sstevel@tonic-gate 			CP(cursor, gcursor + 1);
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 		/*
5327c478bd9Sstevel@tonic-gate 		 * If doomed characters remain, clobber them,
5337c478bd9Sstevel@tonic-gate 		 * and reopen the line to get the display exact.
534bbfd0aa6Scf46844 		 * eg. c$ to change to end of line
5357c478bd9Sstevel@tonic-gate 		 */
5367c478bd9Sstevel@tonic-gate 		if (state != HARDOPEN) {
5377c478bd9Sstevel@tonic-gate 			DEPTH(vcline) = 0;
5387c478bd9Sstevel@tonic-gate 			savedoomed = doomed;
5397c478bd9Sstevel@tonic-gate 			if (doomed > 0) {
540f6db9f27Scf46844 				int cind = cindent();
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 				physdc(cind, cind + doomed);
5437c478bd9Sstevel@tonic-gate 				doomed = 0;
5447c478bd9Sstevel@tonic-gate 			}
5457c478bd9Sstevel@tonic-gate 			if(MB_CUR_MAX > 1)
5467c478bd9Sstevel@tonic-gate 				rewrite = _ON;
5477c478bd9Sstevel@tonic-gate 			i = vreopen(LINE(vcline), lineDOT(), vcline);
5487c478bd9Sstevel@tonic-gate 			if(MB_CUR_MAX > 1)
5497c478bd9Sstevel@tonic-gate 				rewrite = _OFF;
5507c478bd9Sstevel@tonic-gate #ifdef TRACE
5517c478bd9Sstevel@tonic-gate 			if (trace)
5527c478bd9Sstevel@tonic-gate 				fprintf(trace, "restoring doomed from %d to %d\n", doomed, savedoomed);
5537c478bd9Sstevel@tonic-gate #endif
5547c478bd9Sstevel@tonic-gate 			if (ch == 'R')
5557c478bd9Sstevel@tonic-gate 				doomed = savedoomed;
5567c478bd9Sstevel@tonic-gate 		}
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 		/*
559bbfd0aa6Scf46844 		 * Unless we are continuing on to another line
560bbfd0aa6Scf46844 		 * (got a NL), break out of the for loop (got
561bbfd0aa6Scf46844 		 * an ESCAPE).
5627c478bd9Sstevel@tonic-gate 		 */
5637c478bd9Sstevel@tonic-gate 		if (escape != '\n') {
5647c478bd9Sstevel@tonic-gate 			vshowmode("");
5657c478bd9Sstevel@tonic-gate 			break;
5667c478bd9Sstevel@tonic-gate 		}
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 		/*
5697c478bd9Sstevel@tonic-gate 		 * Set up for the new line.
5707c478bd9Sstevel@tonic-gate 		 * First save the current line, then construct a new
5717c478bd9Sstevel@tonic-gate 		 * first image for the continuation line consisting
5727c478bd9Sstevel@tonic-gate 		 * of any new autoindent plus the pushed ahead text.
5737c478bd9Sstevel@tonic-gate 		 */
5747c478bd9Sstevel@tonic-gate 		killU();
5757c478bd9Sstevel@tonic-gate 		addtext(gobblebl ? " " : "\n");
576bbfd0aa6Scf46844 		/* save vutmp (for undo state) into temp file */
5777c478bd9Sstevel@tonic-gate 		vsave();
5787c478bd9Sstevel@tonic-gate 		cnt = 1;
5797c478bd9Sstevel@tonic-gate 		if (value(vi_AUTOINDENT)) {
5807c478bd9Sstevel@tonic-gate 			if (value(vi_LISP))
5817c478bd9Sstevel@tonic-gate 				indent = lindent(dot + 1);
5827c478bd9Sstevel@tonic-gate 			else
5837c478bd9Sstevel@tonic-gate 			     if (!HADUP && vaifirst)
5847c478bd9Sstevel@tonic-gate 				indent = whitecnt(linebuf);
5857c478bd9Sstevel@tonic-gate 			vaifirst = 0;
5867c478bd9Sstevel@tonic-gate 			strcLIN(vpastwh(gcursor + 1));
5877c478bd9Sstevel@tonic-gate 			gcursor = genindent(indent);
5887c478bd9Sstevel@tonic-gate 			*gcursor = 0;
5897c478bd9Sstevel@tonic-gate 			if (gcursor + strlen(linebuf) > &genbuf[LBSIZE - 2])
5907c478bd9Sstevel@tonic-gate 				gcursor = genbuf;
5917c478bd9Sstevel@tonic-gate 			CP(gcursor, linebuf);
5927c478bd9Sstevel@tonic-gate 		} else {
593bbfd0aa6Scf46844 			/*
594bbfd0aa6Scf46844 			 * Put gcursor at start of genbuf to wipe
595bbfd0aa6Scf46844 			 * out previous line in preparation for
596bbfd0aa6Scf46844 			 * the next vgetline() loop.
597bbfd0aa6Scf46844 			 */
5987c478bd9Sstevel@tonic-gate 			CP(genbuf, gcursor + 1);
5997c478bd9Sstevel@tonic-gate 			gcursor = genbuf;
6007c478bd9Sstevel@tonic-gate 		}
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 		/*
6037c478bd9Sstevel@tonic-gate 		 * If we started out as a single line operation and are now
6047c478bd9Sstevel@tonic-gate 		 * turning into a multi-line change, then we had better yank
6057c478bd9Sstevel@tonic-gate 		 * out dot before it changes so that undo will work
6067c478bd9Sstevel@tonic-gate 		 * correctly later.
6077c478bd9Sstevel@tonic-gate 		 */
6087c478bd9Sstevel@tonic-gate 		if (FIXUNDO && vundkind == VCHNG) {
6097c478bd9Sstevel@tonic-gate 			vremote(1, yank, 0);
6107c478bd9Sstevel@tonic-gate 			undap1--;
6117c478bd9Sstevel@tonic-gate 		}
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 		/*
6147c478bd9Sstevel@tonic-gate 		 * Now do the append of the new line in the buffer,
615bbfd0aa6Scf46844 		 * and update the display, ie: append genbuf to
616bbfd0aa6Scf46844 		 * the file after dot.  If slowopen
6177c478bd9Sstevel@tonic-gate 		 * we don't do very much.
6187c478bd9Sstevel@tonic-gate 		 */
6197c478bd9Sstevel@tonic-gate 		vdoappend(genbuf);
6207c478bd9Sstevel@tonic-gate 		vundkind = VMANYINS;
6217c478bd9Sstevel@tonic-gate 		vcline++;
6227c478bd9Sstevel@tonic-gate 		if (state != VISUAL)
6237c478bd9Sstevel@tonic-gate 			vshow(dot, NOLINE);
6247c478bd9Sstevel@tonic-gate 		else {
6257c478bd9Sstevel@tonic-gate 			i += LINE(vcline - 1);
6267c478bd9Sstevel@tonic-gate 			vopen(dot, i);
6277c478bd9Sstevel@tonic-gate 			if (value(vi_SLOWOPEN))
6287c478bd9Sstevel@tonic-gate 				vscrap();
6297c478bd9Sstevel@tonic-gate 			else
6307c478bd9Sstevel@tonic-gate 				vsync1(LINE(vcline));
6317c478bd9Sstevel@tonic-gate 		}
6327c478bd9Sstevel@tonic-gate 		switch (ch) {
6337c478bd9Sstevel@tonic-gate 		case 'r':
6347c478bd9Sstevel@tonic-gate 			break;
6357c478bd9Sstevel@tonic-gate 		case 'a':
6367c478bd9Sstevel@tonic-gate 			if (value(vi_TERSE)) {
6377c478bd9Sstevel@tonic-gate 				vshowmode(gettext("A"));
6387c478bd9Sstevel@tonic-gate 			} else {
6397c478bd9Sstevel@tonic-gate 				vshowmode(gettext("APPEND MODE"));
6407c478bd9Sstevel@tonic-gate 			}
6417c478bd9Sstevel@tonic-gate 			break;
6427c478bd9Sstevel@tonic-gate 		case 's':
6437c478bd9Sstevel@tonic-gate 			if (value(vi_TERSE)) {
6447c478bd9Sstevel@tonic-gate 				vshowmode(gettext("S"));
6457c478bd9Sstevel@tonic-gate 			} else {
6467c478bd9Sstevel@tonic-gate 				vshowmode(gettext("SUBSTITUTE MODE"));
6477c478bd9Sstevel@tonic-gate 			}
6487c478bd9Sstevel@tonic-gate 			break;
6497c478bd9Sstevel@tonic-gate 		case 'c':
6507c478bd9Sstevel@tonic-gate 			if (value(vi_TERSE)) {
6517c478bd9Sstevel@tonic-gate 				vshowmode(gettext("C"));
6527c478bd9Sstevel@tonic-gate 			} else {
6537c478bd9Sstevel@tonic-gate 				vshowmode(gettext("CHANGE MODE"));
6547c478bd9Sstevel@tonic-gate 			}
6557c478bd9Sstevel@tonic-gate 			break;
6567c478bd9Sstevel@tonic-gate 		case 'R':
6577c478bd9Sstevel@tonic-gate 			if (value(vi_TERSE)) {
6587c478bd9Sstevel@tonic-gate 				vshowmode(gettext("R"));
6597c478bd9Sstevel@tonic-gate 			} else {
6607c478bd9Sstevel@tonic-gate 				vshowmode(gettext("REPLACE MODE"));
6617c478bd9Sstevel@tonic-gate 			}
6627c478bd9Sstevel@tonic-gate 			break;
6637c478bd9Sstevel@tonic-gate 		case 'i':
6647c478bd9Sstevel@tonic-gate 			if (value(vi_TERSE)) {
6657c478bd9Sstevel@tonic-gate 				vshowmode(gettext("I"));
6667c478bd9Sstevel@tonic-gate 			} else {
6677c478bd9Sstevel@tonic-gate 				vshowmode(gettext("INSERT MODE"));
6687c478bd9Sstevel@tonic-gate 			}
6697c478bd9Sstevel@tonic-gate 			break;
6707c478bd9Sstevel@tonic-gate 		case 'o':
6717c478bd9Sstevel@tonic-gate 			if (value(vi_TERSE)) {
6727c478bd9Sstevel@tonic-gate 				vshowmode(gettext("O"));
6737c478bd9Sstevel@tonic-gate 			} else {
6747c478bd9Sstevel@tonic-gate 				vshowmode(gettext("OPEN MODE"));
6757c478bd9Sstevel@tonic-gate 			}
6767c478bd9Sstevel@tonic-gate 			break;
6777c478bd9Sstevel@tonic-gate 		default:
6787c478bd9Sstevel@tonic-gate 			if (value(vi_TERSE)) {
6797c478bd9Sstevel@tonic-gate 				vshowmode(gettext("I"));
6807c478bd9Sstevel@tonic-gate 			} else {
6817c478bd9Sstevel@tonic-gate 				vshowmode(gettext("INPUT MODE"));
6827c478bd9Sstevel@tonic-gate 			}
6837c478bd9Sstevel@tonic-gate 		}
6847c478bd9Sstevel@tonic-gate 		strcLIN(gcursor);
685bbfd0aa6Scf46844 		/* zero genbuf */
6867c478bd9Sstevel@tonic-gate 		*gcursor = 0;
6877c478bd9Sstevel@tonic-gate 		cursor = linebuf;
6887c478bd9Sstevel@tonic-gate 		vgotoCL(nqcolumn(cursor - 1, genbuf));
6893a5240e9Scf46844 	} /* end for (;;) loop in vappend() */
6903a5240e9Scf46844 
6913a5240e9Scf46844 	if (imultlinecnt && gotNL) {
6923a5240e9Scf46844 		imultlinerep(savecnt, startsrcline, startsrccol, endsrccol);
6933a5240e9Scf46844 	} else if (omultlinecnt) {
6943a5240e9Scf46844 		omultlinerep(savecnt, startsrcline, endsrccol);
695bbfd0aa6Scf46844 #ifdef XPG6
696bbfd0aa6Scf46844 	} else if (savecnt > 1 && ch == 'r' && gotNL) {
697bbfd0aa6Scf46844 		/*
698bbfd0aa6Scf46844 		 * XPG6 assertion 313 & 254 : Position cursor for [count]r\n
699bbfd0aa6Scf46844 		 * then insert [count -1] newlines.
700bbfd0aa6Scf46844 		 */
701bbfd0aa6Scf46844 		endsrccol = gcursor - genbuf - 1;
702bbfd0aa6Scf46844 		rmultlinerep(savecnt, endsrccol);
703bbfd0aa6Scf46844 #endif /* XPG6 */
7047c478bd9Sstevel@tonic-gate 	}
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	/*
7077c478bd9Sstevel@tonic-gate 	 * All done with insertion, position the cursor
7087c478bd9Sstevel@tonic-gate 	 * and sync the screen.
7097c478bd9Sstevel@tonic-gate 	 */
7107c478bd9Sstevel@tonic-gate 	hold = oldhold;
7113a5240e9Scf46844 	if ((imultlinecnt && gotNL) || omultlinecnt) {
7123a5240e9Scf46844 		fixdisplay();
713bbfd0aa6Scf46844 #ifdef XPG6
714bbfd0aa6Scf46844 	} else if (savecnt > 1 && ch == 'r' && gotNL) {
715bbfd0aa6Scf46844 		fixdisplay();
716bbfd0aa6Scf46844 		/*
717bbfd0aa6Scf46844 		 * XPG6 assertion 313 & 254 [count]r\n : Set flag to call
718bbfd0aa6Scf46844 		 * fixdisplay() after operate() has finished.  To be sure that
719bbfd0aa6Scf46844 		 * the text (after the last \n followed by an indent) is always
720bbfd0aa6Scf46844 		 * displayed, fixdisplay() is called right before getting
721bbfd0aa6Scf46844 		 * the next command.
722bbfd0aa6Scf46844 		 */
723bbfd0aa6Scf46844 		redisplay = 1;
724bbfd0aa6Scf46844 #endif /* XPG6 */
7253a5240e9Scf46844 	} else if (cursor > linebuf) {
7267c478bd9Sstevel@tonic-gate 		cursor = lastchr(linebuf, cursor);
727bbfd0aa6Scf46844 #ifdef XPG6
728bbfd0aa6Scf46844 		/*
729bbfd0aa6Scf46844 		 * XPG6 assertion 313 & 254 [count]r\n :
730bbfd0aa6Scf46844 		 * For 'r' command, when the replacement char causes new
731bbfd0aa6Scf46844 		 * lines to be created, point cursor to first non-blank.
732bbfd0aa6Scf46844 		 * The old code, ie: cursor = lastchr(linebuf, cursor);
733bbfd0aa6Scf46844 		 * set cursor to the blank before the first non-blank
734bbfd0aa6Scf46844 		 * for r\n
735bbfd0aa6Scf46844 		 */
736bbfd0aa6Scf46844 		if (ch == 'r' && gotNL && isblank((int)*cursor))
737bbfd0aa6Scf46844 			++cursor;
738bbfd0aa6Scf46844 #endif /* XPG6 */
7393a5240e9Scf46844 	}
7407c478bd9Sstevel@tonic-gate 	if (state != HARDOPEN)
7417c478bd9Sstevel@tonic-gate 		vsyncCL();
7427c478bd9Sstevel@tonic-gate 	else if (cursor > linebuf)
7437c478bd9Sstevel@tonic-gate 		back1();
7447c478bd9Sstevel@tonic-gate 	doomed = 0;
7457c478bd9Sstevel@tonic-gate 	wcursor = cursor;
746f6db9f27Scf46844 	(void) vmove();
7477c478bd9Sstevel@tonic-gate }
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate /*
7503a5240e9Scf46844  * XPG6
7513a5240e9Scf46844  * To repeat multi-line input for [count]a, [count]A, [count]i, [count]I,
7523a5240e9Scf46844  * or a subsequent [count]. :
7533a5240e9Scf46844  * insert input count-1 more times.
7543a5240e9Scf46844  */
7553a5240e9Scf46844 
7563a5240e9Scf46844 static void
7573a5240e9Scf46844 imultlinerep(int savecnt, line *startsrcline, int startsrccol, int endsrccol)
7583a5240e9Scf46844 {
7593a5240e9Scf46844 	int tmpcnt = 2;	/* 1st insert counts as 1 repeat */
7603a5240e9Scf46844 	line *srcline, *endsrcline;
7613a5240e9Scf46844 	size_t destsize = LBSIZE - endsrccol - 1;
7623a5240e9Scf46844 
7633a5240e9Scf46844 	endsrcline = dot;
7643a5240e9Scf46844 
7653a5240e9Scf46844 	/* Save linebuf into temp file before moving off the line. */
7663a5240e9Scf46844 	vsave();
7673a5240e9Scf46844 
7683a5240e9Scf46844 	/*
7693a5240e9Scf46844 	 * At this point the temp file contains the first iteration of
7703a5240e9Scf46844 	 * a multi-line insert, and we need to repeat it savecnt - 1
7713a5240e9Scf46844 	 * more times in the temp file.  dot is the last line in the
7723a5240e9Scf46844 	 * first iteration of the insert.  Decrement dot so that
7733a5240e9Scf46844 	 * vdoappend() will append each new line before the last line.
7743a5240e9Scf46844 	 */
7753a5240e9Scf46844 	--dot;
7763a5240e9Scf46844 	--vcline;
7773a5240e9Scf46844 	/*
7783a5240e9Scf46844 	 * Use genbuf to rebuild the last line in the 1st iteration
7793a5240e9Scf46844 	 * of the repeated insert, then copy this line to the temp file.
7803a5240e9Scf46844 	 */
7813a5240e9Scf46844 	(void) strlcpy((char *)genbuf, (char *)linebuf, sizeof (genbuf));
782*23a1cceaSRoger A. Faulkner 	getaline(*startsrcline);
7833a5240e9Scf46844 	if (strlcpy((char *)(genbuf + endsrccol + 1),
7843a5240e9Scf46844 	    (char *)(linebuf + startsrccol), destsize) >= destsize) {
7853a5240e9Scf46844 		error(gettext("Line too long"));
7863a5240e9Scf46844 	}
7873a5240e9Scf46844 	vdoappend(genbuf);
7883a5240e9Scf46844 	vcline++;
7893a5240e9Scf46844 	/*
7903a5240e9Scf46844 	 * Loop from the second line of the first iteration
7913a5240e9Scf46844 	 * through endsrcline, appending after dot.
7923a5240e9Scf46844 	 */
7933a5240e9Scf46844 	++startsrcline;
7943a5240e9Scf46844 
7953a5240e9Scf46844 	while (tmpcnt <= savecnt) {
7963a5240e9Scf46844 		for (srcline = startsrcline; srcline <= endsrcline;
7973a5240e9Scf46844 		    ++srcline) {
7983a5240e9Scf46844 			if ((tmpcnt == savecnt) &&
7993a5240e9Scf46844 			    (srcline == endsrcline)) {
8003a5240e9Scf46844 				/*
8013a5240e9Scf46844 				 * The last line is already in place,
8023a5240e9Scf46844 				 * just make it the current line.
8033a5240e9Scf46844 				 */
8043a5240e9Scf46844 				vcline++;
8053a5240e9Scf46844 				dot++;
8063a5240e9Scf46844 				getDOT();
8073a5240e9Scf46844 				cursor = linebuf + endsrccol;
8083a5240e9Scf46844 			} else {
809*23a1cceaSRoger A. Faulkner 				getaline(*srcline);
8103a5240e9Scf46844 				/* copy linebuf to temp file */
8113a5240e9Scf46844 				vdoappend(linebuf);
8123a5240e9Scf46844 				vcline++;
8133a5240e9Scf46844 			}
8143a5240e9Scf46844 		}
8153a5240e9Scf46844 		++tmpcnt;
8163a5240e9Scf46844 	}
8173a5240e9Scf46844 }
8183a5240e9Scf46844 
8193a5240e9Scf46844 /*
8203a5240e9Scf46844  * To repeat input for [count]o, [count]O, or a subsequent [count]. :
8213a5240e9Scf46844  * append input count-1 more times to the end of the already added
8223a5240e9Scf46844  * text, each time starting on a new line.
8233a5240e9Scf46844  */
8243a5240e9Scf46844 
8253a5240e9Scf46844 static void
8263a5240e9Scf46844 omultlinerep(int savecnt, line *startsrcline, int endsrccol)
8273a5240e9Scf46844 {
8283a5240e9Scf46844 	int tmpcnt = 2;	/* 1st insert counts as 1 repeat */
8293a5240e9Scf46844 	line *srcline, *endsrcline;
8303a5240e9Scf46844 
8313a5240e9Scf46844 	endsrcline = dot;
8323a5240e9Scf46844 	/* Save linebuf into temp file before moving off the line. */
8333a5240e9Scf46844 	vsave();
8343a5240e9Scf46844 
8353a5240e9Scf46844 	/*
8363a5240e9Scf46844 	 * Loop from the first line of the first iteration
8373a5240e9Scf46844 	 * through endsrcline, appending after dot.
8383a5240e9Scf46844 	 */
8393a5240e9Scf46844 	while (tmpcnt <= savecnt) {
8403a5240e9Scf46844 		for (srcline = startsrcline; srcline <= endsrcline; ++srcline) {
841*23a1cceaSRoger A. Faulkner 			getaline(*srcline);
8423a5240e9Scf46844 			/* copy linebuf to temp file */
8433a5240e9Scf46844 			vdoappend(linebuf);
8443a5240e9Scf46844 			vcline++;
8453a5240e9Scf46844 		}
8463a5240e9Scf46844 		++tmpcnt;
8473a5240e9Scf46844 	}
8483a5240e9Scf46844 	cursor = linebuf + endsrccol;
8493a5240e9Scf46844 }
8503a5240e9Scf46844 
851bbfd0aa6Scf46844 #ifdef XPG6
852bbfd0aa6Scf46844 /*
853bbfd0aa6Scf46844  * XPG6 assertion 313 & 254 : To repeat '\n' for [count]r\n
854bbfd0aa6Scf46844  * insert '\n' savecnt-1 more times before the already added '\n'.
855bbfd0aa6Scf46844  */
856bbfd0aa6Scf46844 
857bbfd0aa6Scf46844 static void
858bbfd0aa6Scf46844 rmultlinerep(int savecnt, int endsrccol)
859bbfd0aa6Scf46844 {
860bbfd0aa6Scf46844 	int tmpcnt = 2;	/* 1st replacement counts as 1 repeat */
861bbfd0aa6Scf46844 
862bbfd0aa6Scf46844 	/* Save linebuf into temp file before moving off the line. */
863bbfd0aa6Scf46844 	vsave();
864bbfd0aa6Scf46844 	/*
865bbfd0aa6Scf46844 	 * At this point the temp file contains the line followed by '\n',
866bbfd0aa6Scf46844 	 * which is preceded by indentation if autoindent is set.
867bbfd0aa6Scf46844 	 * '\n' must be repeated [savecnt - 1] more times in the temp file.
868bbfd0aa6Scf46844 	 * dot is the current line containing the '\n'.  Decrement dot so that
869bbfd0aa6Scf46844 	 * vdoappend() will append each '\n' before the current '\n'.
870bbfd0aa6Scf46844 	 * This will allow only the last line to contain any autoindent
871bbfd0aa6Scf46844 	 * characters.
872bbfd0aa6Scf46844 	 */
873bbfd0aa6Scf46844 	--dot;
874bbfd0aa6Scf46844 	--vcline;
875bbfd0aa6Scf46844 
876bbfd0aa6Scf46844 	/*
877bbfd0aa6Scf46844 	 * Append after dot.
878bbfd0aa6Scf46844 	 */
879bbfd0aa6Scf46844 	while (tmpcnt <= savecnt) {
880bbfd0aa6Scf46844 		linebuf[0] = '\0';
881bbfd0aa6Scf46844 		/* append linebuf below current line in temp file */
882bbfd0aa6Scf46844 		vdoappend(linebuf);
883bbfd0aa6Scf46844 		vcline++;
884bbfd0aa6Scf46844 		++tmpcnt;
885bbfd0aa6Scf46844 	}
886bbfd0aa6Scf46844 	/* set the current line to the line after the last '\n' */
887bbfd0aa6Scf46844 	++dot;
888bbfd0aa6Scf46844 	++vcline;
889bbfd0aa6Scf46844 	/* point cursor after (linebuf + endsrccol) */
890bbfd0aa6Scf46844 	vcursaft(linebuf + endsrccol);
891bbfd0aa6Scf46844 }
892bbfd0aa6Scf46844 #endif /* XPG6 */
893bbfd0aa6Scf46844 
8943a5240e9Scf46844 /*
8953a5240e9Scf46844  * Similiar to a ctrl-l, however always vrepaint() in case the last line
8963a5240e9Scf46844  * of the repeat would exceed the bottom of the screen.
8973a5240e9Scf46844  */
8983a5240e9Scf46844 
899bbfd0aa6Scf46844 void
9003a5240e9Scf46844 fixdisplay(void)
9013a5240e9Scf46844 {
9023a5240e9Scf46844 	vclear();
9033a5240e9Scf46844 	vdirty(0, vcnt);
9043a5240e9Scf46844 	if (state != VISUAL) {
9053a5240e9Scf46844 		vclean();
9063a5240e9Scf46844 		vcnt = 0;
9073a5240e9Scf46844 		vmoveto(dot, cursor, 0);
9083a5240e9Scf46844 	} else {
9093a5240e9Scf46844 		vredraw(WTOP);
9103a5240e9Scf46844 		vrepaint(cursor);
9113a5240e9Scf46844 		vfixcurs();
9123a5240e9Scf46844 	}
9133a5240e9Scf46844 }
9143a5240e9Scf46844 
9153a5240e9Scf46844 /*
9167c478bd9Sstevel@tonic-gate  * Subroutine for vgetline to back up a single character position,
9177c478bd9Sstevel@tonic-gate  * backwards around end of lines (vgoto can't hack columns which are
9187c478bd9Sstevel@tonic-gate  * less than 0 in general).
9197c478bd9Sstevel@tonic-gate  */
920f6db9f27Scf46844 void
921f6db9f27Scf46844 back1(void)
9227c478bd9Sstevel@tonic-gate {
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate 	vgoto(destline - 1, WCOLS + destcol - 1);
9257c478bd9Sstevel@tonic-gate }
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate /*
9287c478bd9Sstevel@tonic-gate  * Get a line into genbuf after gcursor.
9297c478bd9Sstevel@tonic-gate  * Cnt limits the number of input characters
9307c478bd9Sstevel@tonic-gate  * accepted and is used for handling the replace
9317c478bd9Sstevel@tonic-gate  * single character command.  Aescaped is the location
9327c478bd9Sstevel@tonic-gate  * where we stick a termination indicator (whether we
9337c478bd9Sstevel@tonic-gate  * ended with an ESCAPE or a newline/return.
9347c478bd9Sstevel@tonic-gate  *
9357c478bd9Sstevel@tonic-gate  * We do erase-kill type processing here and also
9367c478bd9Sstevel@tonic-gate  * are careful about the way we do this so that it is
9377c478bd9Sstevel@tonic-gate  * repeatable.  (I.e. so that your kill doesn't happen,
9387c478bd9Sstevel@tonic-gate  * when you repeat an insert if it was escaped with \ the
9397c478bd9Sstevel@tonic-gate  * first time you did it.  commch is the command character
9407c478bd9Sstevel@tonic-gate  * involved, including the prompt for readline.
9417c478bd9Sstevel@tonic-gate  */
9427c478bd9Sstevel@tonic-gate unsigned char *
9437c478bd9Sstevel@tonic-gate vgetline(cnt, gcursor, aescaped, commch)
9447c478bd9Sstevel@tonic-gate 	int cnt;
945f6db9f27Scf46844 	unsigned char *gcursor;
9467c478bd9Sstevel@tonic-gate 	bool *aescaped;
9477c478bd9Sstevel@tonic-gate 	unsigned char commch;
9487c478bd9Sstevel@tonic-gate {
949f6db9f27Scf46844 	int c, ch;
950f6db9f27Scf46844 	unsigned char *cp, *pcp;
9517c478bd9Sstevel@tonic-gate 	int x, y, iwhite, backsl=0;
9527c478bd9Sstevel@tonic-gate 	unsigned char *iglobp;
9537c478bd9Sstevel@tonic-gate 	int (*OO)() = Outchar;
9547c478bd9Sstevel@tonic-gate 	int length, width;
9557c478bd9Sstevel@tonic-gate 	unsigned char multic[MULTI_BYTE_MAX+1];
9567c478bd9Sstevel@tonic-gate 	wchar_t wchar = 0;
9577c478bd9Sstevel@tonic-gate 	unsigned char	*p;
9587c478bd9Sstevel@tonic-gate 	int	len;
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 	/*
9627c478bd9Sstevel@tonic-gate 	 * Clear the output state and counters
9637c478bd9Sstevel@tonic-gate 	 * for autoindent backwards motion (counts of ^D, etc.)
9647c478bd9Sstevel@tonic-gate 	 * Remember how much white space at beginning of line so
9657c478bd9Sstevel@tonic-gate 	 * as not to allow backspace over autoindent.
9667c478bd9Sstevel@tonic-gate 	 */
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 	*aescaped = 0;
9697c478bd9Sstevel@tonic-gate 	ogcursor = gcursor;
9707c478bd9Sstevel@tonic-gate 	flusho();
9717c478bd9Sstevel@tonic-gate 	CDCNT = 0;
9727c478bd9Sstevel@tonic-gate 	HADUP = 0;
9737c478bd9Sstevel@tonic-gate 	HADZERO = 0;
9747c478bd9Sstevel@tonic-gate 	gobbled = 0;
9757c478bd9Sstevel@tonic-gate 	iwhite = whitecnt(genbuf);
9767c478bd9Sstevel@tonic-gate 	iglobp = vglobp;
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 	/*
9797c478bd9Sstevel@tonic-gate 	 * Clear abbreviation recursive-use count
9807c478bd9Sstevel@tonic-gate 	 */
9817c478bd9Sstevel@tonic-gate 	abbrepcnt = 0;
9827c478bd9Sstevel@tonic-gate 	/*
9837c478bd9Sstevel@tonic-gate 	 * Carefully avoid using vinschar in the echo area.
9847c478bd9Sstevel@tonic-gate 	 */
9857c478bd9Sstevel@tonic-gate 	if (splitw)
9867c478bd9Sstevel@tonic-gate 		Outchar = vputchar;
9877c478bd9Sstevel@tonic-gate 	else {
9887c478bd9Sstevel@tonic-gate 		Outchar = vinschar;
9897c478bd9Sstevel@tonic-gate 		vprepins();
9907c478bd9Sstevel@tonic-gate 	}
9917c478bd9Sstevel@tonic-gate 	for (;;) {
9927c478bd9Sstevel@tonic-gate 		length = 0;
9937c478bd9Sstevel@tonic-gate 		backsl = 0;
9947c478bd9Sstevel@tonic-gate 		if (gobblebl)
9957c478bd9Sstevel@tonic-gate 			gobblebl--;
9967c478bd9Sstevel@tonic-gate 		if (cnt != 0) {
9977c478bd9Sstevel@tonic-gate 			cnt--;
9987c478bd9Sstevel@tonic-gate 			if (cnt == 0)
9997c478bd9Sstevel@tonic-gate 				goto vadone;
10007c478bd9Sstevel@tonic-gate 		}
10017c478bd9Sstevel@tonic-gate 		c = getkey();
10027c478bd9Sstevel@tonic-gate 		if (c != ATTN)
10037c478bd9Sstevel@tonic-gate 			c &= 0377;
10047c478bd9Sstevel@tonic-gate 		ch = c;
10057c478bd9Sstevel@tonic-gate 		maphopcnt = 0;
10067c478bd9Sstevel@tonic-gate 		if (vglobp == 0 && Peekkey == 0 && commch != 'r')
10077c478bd9Sstevel@tonic-gate 			while ((ch = map(c, immacs, commch)) != c) {
10087c478bd9Sstevel@tonic-gate 				c = ch;
10097c478bd9Sstevel@tonic-gate 				if (!value(vi_REMAP))
10107c478bd9Sstevel@tonic-gate 					break;
10117c478bd9Sstevel@tonic-gate 				if (++maphopcnt > 256)
10127c478bd9Sstevel@tonic-gate 					error(gettext("Infinite macro loop"));
10137c478bd9Sstevel@tonic-gate 			}
10147c478bd9Sstevel@tonic-gate 		if (!iglobp) {
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate 			/*
10177c478bd9Sstevel@tonic-gate 			 * Erase-kill type processing.
10187c478bd9Sstevel@tonic-gate 			 * Only happens if we were not reading
10197c478bd9Sstevel@tonic-gate 			 * from untyped input when we started.
10207c478bd9Sstevel@tonic-gate 			 * Map users erase to ^H, kill to -1 for switch.
10217c478bd9Sstevel@tonic-gate 			 */
10227c478bd9Sstevel@tonic-gate 			if (c == tty.c_cc[VERASE])
10237c478bd9Sstevel@tonic-gate 				c = CTRL('h');
10247c478bd9Sstevel@tonic-gate 			else if (c == tty.c_cc[VKILL])
10257c478bd9Sstevel@tonic-gate 				c = -1;
10267c478bd9Sstevel@tonic-gate 			switch (c) {
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate 			/*
10297c478bd9Sstevel@tonic-gate 			 * ^?		Interrupt drops you back to visual
10307c478bd9Sstevel@tonic-gate 			 *		command mode with an unread interrupt
10317c478bd9Sstevel@tonic-gate 			 *		still in the input buffer.
10327c478bd9Sstevel@tonic-gate 			 *
10337c478bd9Sstevel@tonic-gate 			 * ^\		Quit does the same as interrupt.
10347c478bd9Sstevel@tonic-gate 			 *		If you are a ex command rather than
10357c478bd9Sstevel@tonic-gate 			 *		a vi command this will drop you
10367c478bd9Sstevel@tonic-gate 			 *		back to command mode for sure.
10377c478bd9Sstevel@tonic-gate 			 */
10387c478bd9Sstevel@tonic-gate 			case ATTN:
10397c478bd9Sstevel@tonic-gate 			case QUIT:
10407c478bd9Sstevel@tonic-gate 				ungetkey(c);
10417c478bd9Sstevel@tonic-gate 				goto vadone;
10427c478bd9Sstevel@tonic-gate 
10437c478bd9Sstevel@tonic-gate 			/*
10447c478bd9Sstevel@tonic-gate 			 * ^H		Backs up a character in the input.
10457c478bd9Sstevel@tonic-gate 			 *
10467c478bd9Sstevel@tonic-gate 			 * BUG:		Can't back around line boundaries.
10477c478bd9Sstevel@tonic-gate 			 *		This is hard because stuff has
10487c478bd9Sstevel@tonic-gate 			 *		already been saved for repeat.
10497c478bd9Sstevel@tonic-gate 			 */
10507c478bd9Sstevel@tonic-gate 			case CTRL('h'):
10517c478bd9Sstevel@tonic-gate bakchar:
10527c478bd9Sstevel@tonic-gate 				cp = lastchr(ogcursor, gcursor);
10537c478bd9Sstevel@tonic-gate 				if (cp < ogcursor) {
10547c478bd9Sstevel@tonic-gate 					if (splitw) {
10557c478bd9Sstevel@tonic-gate 						/*
10567c478bd9Sstevel@tonic-gate 						 * Backspacing over readecho
10577c478bd9Sstevel@tonic-gate 						 * prompt. Pretend delete but
10587c478bd9Sstevel@tonic-gate 						 * don't beep.
10597c478bd9Sstevel@tonic-gate 						 */
10607c478bd9Sstevel@tonic-gate 						ungetkey(c);
10617c478bd9Sstevel@tonic-gate 						goto vadone;
10627c478bd9Sstevel@tonic-gate 					}
1063f6db9f27Scf46844 					(void) beep();
10647c478bd9Sstevel@tonic-gate 					continue;
10657c478bd9Sstevel@tonic-gate 				}
10667c478bd9Sstevel@tonic-gate 				goto vbackup;
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 			/*
10697c478bd9Sstevel@tonic-gate 			 * ^W		Back up a white/non-white word.
10707c478bd9Sstevel@tonic-gate 			 */
10717c478bd9Sstevel@tonic-gate 			case CTRL('w'):
10727c478bd9Sstevel@tonic-gate 				wdkind = 1;
10737c478bd9Sstevel@tonic-gate 				for (cp = gcursor; cp > ogcursor && isspace(cp[-1]); cp--)
10747c478bd9Sstevel@tonic-gate 					continue;
10757c478bd9Sstevel@tonic-gate 				pcp = lastchr(ogcursor, cp);
10767c478bd9Sstevel@tonic-gate 				for (c = wordch(pcp);
10777c478bd9Sstevel@tonic-gate 				    cp > ogcursor && wordof(c, pcp); cp = pcp, pcp = lastchr(ogcursor, cp))
10787c478bd9Sstevel@tonic-gate 					continue;
10797c478bd9Sstevel@tonic-gate 				goto vbackup;
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 			/*
10827c478bd9Sstevel@tonic-gate 			 * users kill	Kill input on this line, back to
10837c478bd9Sstevel@tonic-gate 			 *		the autoindent.
10847c478bd9Sstevel@tonic-gate 			 */
10857c478bd9Sstevel@tonic-gate 			case -1:
10867c478bd9Sstevel@tonic-gate 				cp = ogcursor;
10877c478bd9Sstevel@tonic-gate vbackup:
10887c478bd9Sstevel@tonic-gate 				if (cp == gcursor) {
1089f6db9f27Scf46844 					(void) beep();
10907c478bd9Sstevel@tonic-gate 					continue;
10917c478bd9Sstevel@tonic-gate 				}
10927c478bd9Sstevel@tonic-gate 				endim();
10937c478bd9Sstevel@tonic-gate 				*cp = 0;
10947c478bd9Sstevel@tonic-gate 				c = cindent();
10957c478bd9Sstevel@tonic-gate 				vgotoCL(nqcolumn(lastchr(linebuf, cursor), genbuf));
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate 				if (doomed >= 0)
10987c478bd9Sstevel@tonic-gate 					doomed += c - cindent();
10997c478bd9Sstevel@tonic-gate 				gcursor = cp;
11007c478bd9Sstevel@tonic-gate 				continue;
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 			/*
11037c478bd9Sstevel@tonic-gate 			 * \		Followed by erase or kill
11047c478bd9Sstevel@tonic-gate 			 *		maps to just the erase or kill.
11057c478bd9Sstevel@tonic-gate 			 */
11067c478bd9Sstevel@tonic-gate 			case '\\':
11077c478bd9Sstevel@tonic-gate 				x = destcol, y = destline;
11087c478bd9Sstevel@tonic-gate 				putchar('\\');
11097c478bd9Sstevel@tonic-gate 				vcsync();
11107c478bd9Sstevel@tonic-gate 				c = getkey();
11117c478bd9Sstevel@tonic-gate 				if (c == tty.c_cc[VERASE]
11127c478bd9Sstevel@tonic-gate 				    || c == tty.c_cc[VKILL])
11137c478bd9Sstevel@tonic-gate 				{
11147c478bd9Sstevel@tonic-gate 					vgoto(y, x);
11157c478bd9Sstevel@tonic-gate 					if (doomed >= 0)
11167c478bd9Sstevel@tonic-gate 						doomed++;
11177c478bd9Sstevel@tonic-gate 					multic[0] = wchar = c;
11187c478bd9Sstevel@tonic-gate 					length = 1;
11197c478bd9Sstevel@tonic-gate 					goto def;
11207c478bd9Sstevel@tonic-gate 				}
11217c478bd9Sstevel@tonic-gate 				ungetkey(c), c = '\\';
11227c478bd9Sstevel@tonic-gate 				backsl = 1;
11237c478bd9Sstevel@tonic-gate 				break;
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 			/*
11267c478bd9Sstevel@tonic-gate 			 * ^Q		Super quote following character
11277c478bd9Sstevel@tonic-gate 			 *		Only ^@ is verboten (trapped at
11287c478bd9Sstevel@tonic-gate 			 *		a lower level) and \n forces a line
11297c478bd9Sstevel@tonic-gate 			 *		split so doesn't really go in.
11307c478bd9Sstevel@tonic-gate 			 *
11317c478bd9Sstevel@tonic-gate 			 * ^V		Synonym for ^Q
11327c478bd9Sstevel@tonic-gate 			 */
11337c478bd9Sstevel@tonic-gate 			case CTRL('q'):
11347c478bd9Sstevel@tonic-gate 			case CTRL('v'):
11357c478bd9Sstevel@tonic-gate 				x = destcol, y = destline;
11367c478bd9Sstevel@tonic-gate 				putchar('^');
11377c478bd9Sstevel@tonic-gate 				vgoto(y, x);
11387c478bd9Sstevel@tonic-gate 				c = getkey();
11397c478bd9Sstevel@tonic-gate #ifdef USG
11407c478bd9Sstevel@tonic-gate 				if (c == ATTN)
11417c478bd9Sstevel@tonic-gate 					c = tty.c_cc[VINTR];
11427c478bd9Sstevel@tonic-gate #endif
11437c478bd9Sstevel@tonic-gate 				if (c != NL) {
11447c478bd9Sstevel@tonic-gate 					if (doomed >= 0)
11457c478bd9Sstevel@tonic-gate 						doomed++;
11467c478bd9Sstevel@tonic-gate 					multic[0] = wchar = c;
11477c478bd9Sstevel@tonic-gate 					length = 1;
11487c478bd9Sstevel@tonic-gate 					goto def;
11497c478bd9Sstevel@tonic-gate 				}
11507c478bd9Sstevel@tonic-gate 				break;
11517c478bd9Sstevel@tonic-gate 			}
11527c478bd9Sstevel@tonic-gate 		}
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate 		/*
11557c478bd9Sstevel@tonic-gate 		 * If we get a blank not in the echo area
11567c478bd9Sstevel@tonic-gate 		 * consider splitting the window in the wrapmargin.
11577c478bd9Sstevel@tonic-gate 		 */
11587c478bd9Sstevel@tonic-gate 		if(!backsl) {
11597c478bd9Sstevel@tonic-gate 			ungetkey(c);
11607c478bd9Sstevel@tonic-gate 			if((length = _mbftowc((char *)multic, &wchar, getkey, &Peekkey)) <= 0) {
1161f6db9f27Scf46844 				(void) beep();
11627c478bd9Sstevel@tonic-gate 				continue;
11637c478bd9Sstevel@tonic-gate 			}
11647c478bd9Sstevel@tonic-gate 		} else {
11657c478bd9Sstevel@tonic-gate 			length = 1;
11667c478bd9Sstevel@tonic-gate 			multic[0] = '\\';
11677c478bd9Sstevel@tonic-gate 		}
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate 		if (c != NL && !splitw) {
11707c478bd9Sstevel@tonic-gate 			if (c == ' ' && gobblebl) {
11717c478bd9Sstevel@tonic-gate 				gobbled = 1;
11727c478bd9Sstevel@tonic-gate 				continue;
11737c478bd9Sstevel@tonic-gate 			}
11747c478bd9Sstevel@tonic-gate 			if ((width = wcwidth(wchar)) <= 0)
11757c478bd9Sstevel@tonic-gate 				width = (wchar <= 0177 ? 1 : 4);
11767c478bd9Sstevel@tonic-gate 			if (value(vi_WRAPMARGIN) &&
11777c478bd9Sstevel@tonic-gate 				(outcol + width - 1 >= OCOLUMNS - value(vi_WRAPMARGIN) ||
11787c478bd9Sstevel@tonic-gate 				 backsl && outcol==0) &&
11797c478bd9Sstevel@tonic-gate 				commch != 'r') {
11807c478bd9Sstevel@tonic-gate 				/*
11817c478bd9Sstevel@tonic-gate 				 * At end of word and hit wrapmargin.
11827c478bd9Sstevel@tonic-gate 				 * Move the word to next line and keep going.
11837c478bd9Sstevel@tonic-gate 				 */
11847c478bd9Sstevel@tonic-gate 				unsigned char *wp;
11857c478bd9Sstevel@tonic-gate 				int bytelength;
11867c478bd9Sstevel@tonic-gate #ifndef PRESUNEUC
11877c478bd9Sstevel@tonic-gate 				unsigned char *tgcursor;
11887c478bd9Sstevel@tonic-gate 				wchar_t wc1, wc2;
11897c478bd9Sstevel@tonic-gate 				tgcursor = gcursor;
11907c478bd9Sstevel@tonic-gate #endif /* PRESUNEUC */
11917c478bd9Sstevel@tonic-gate 				wdkind = 1;
11927c478bd9Sstevel@tonic-gate 				strncpy(gcursor, multic, length);
11937c478bd9Sstevel@tonic-gate 				gcursor += length;
11947c478bd9Sstevel@tonic-gate 				if (backsl) {
11957c478bd9Sstevel@tonic-gate #ifdef PRESUNEUC
11967c478bd9Sstevel@tonic-gate 					if((length = mbftowc((char *)multic, &wchar, getkey, &Peekkey)) <= 0) {
11977c478bd9Sstevel@tonic-gate #else
11987c478bd9Sstevel@tonic-gate 					if((length = _mbftowc((char *)multic, &wchar, getkey, &Peekkey)) <= 0) {
11997c478bd9Sstevel@tonic-gate #endif /* PRESUNEUC */
1200f6db9f27Scf46844 						(void) beep();
12017c478bd9Sstevel@tonic-gate 						continue;
12027c478bd9Sstevel@tonic-gate 					}
12037c478bd9Sstevel@tonic-gate 					strncpy(gcursor, multic, length);
12047c478bd9Sstevel@tonic-gate 					gcursor += length;
12057c478bd9Sstevel@tonic-gate 				}
12067c478bd9Sstevel@tonic-gate 				*gcursor = 0;
12077c478bd9Sstevel@tonic-gate 				/*
12087c478bd9Sstevel@tonic-gate 				 * Find end of previous word if we are past it.
12097c478bd9Sstevel@tonic-gate 				 */
12107c478bd9Sstevel@tonic-gate 				for (cp=gcursor; cp>ogcursor && isspace(cp[-1]); cp--)
12117c478bd9Sstevel@tonic-gate 					;
12127c478bd9Sstevel@tonic-gate #ifdef PRESUNEUC
12137c478bd9Sstevel@tonic-gate 				/* find screen width of previous word */
12147c478bd9Sstevel@tonic-gate 				width = 0;
12157c478bd9Sstevel@tonic-gate 				for(wp = cp; *wp; )
12167c478bd9Sstevel@tonic-gate #else
12177c478bd9Sstevel@tonic-gate 				/* count screen width of pending characters */
12187c478bd9Sstevel@tonic-gate 				width = 0;
12197c478bd9Sstevel@tonic-gate 				for(wp = tgcursor; wp < cp;)
12207c478bd9Sstevel@tonic-gate #endif /* PRESUNEUC */
12217c478bd9Sstevel@tonic-gate 					if((bytelength = mbtowc(&wchar, (char *)wp, MULTI_BYTE_MAX)) < 0) {
12227c478bd9Sstevel@tonic-gate 						width+=4;
12237c478bd9Sstevel@tonic-gate 						wp++;
12247c478bd9Sstevel@tonic-gate 					} else {
12257c478bd9Sstevel@tonic-gate 						int curwidth = wcwidth(wchar);
12267c478bd9Sstevel@tonic-gate 						if(curwidth <= 0)
12277c478bd9Sstevel@tonic-gate 							width += (*wp < 0200 ? 2 : 4);
12287c478bd9Sstevel@tonic-gate 						else
12297c478bd9Sstevel@tonic-gate 							width += curwidth;
12307c478bd9Sstevel@tonic-gate 						wp += bytelength;
12317c478bd9Sstevel@tonic-gate 					}
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate #ifdef PRESUNEUC
12347c478bd9Sstevel@tonic-gate 				if (outcol+(backsl?OCOLUMNS:0) - width >= OCOLUMNS - value(vi_WRAPMARGIN)) {
12357c478bd9Sstevel@tonic-gate #else
12367c478bd9Sstevel@tonic-gate 				if (outcol+(backsl?OCOLUMNS:0) + width -1 >= OCOLUMNS - value(vi_WRAPMARGIN)) {
12377c478bd9Sstevel@tonic-gate #endif /* PRESUNEUC */
12387c478bd9Sstevel@tonic-gate 					/*
12397c478bd9Sstevel@tonic-gate 					 * Find beginning of previous word.
12407c478bd9Sstevel@tonic-gate 					 */
12417c478bd9Sstevel@tonic-gate #ifdef PRESUNEUC
12427c478bd9Sstevel@tonic-gate 					for (; cp>ogcursor && !isspace(cp[-1]); cp--)
12437c478bd9Sstevel@tonic-gate 						;
12447c478bd9Sstevel@tonic-gate #else
12457c478bd9Sstevel@tonic-gate 					wc1 = wc2 = 0;
12467c478bd9Sstevel@tonic-gate 					while (cp>ogcursor) {
12477c478bd9Sstevel@tonic-gate 						if (isspace(cp[-1])) {
12487c478bd9Sstevel@tonic-gate 							break;
12497c478bd9Sstevel@tonic-gate 						}
12507c478bd9Sstevel@tonic-gate 						if (!multibyte) {
12517c478bd9Sstevel@tonic-gate 							cp--;
12527c478bd9Sstevel@tonic-gate 							continue;
12537c478bd9Sstevel@tonic-gate 						}
12547c478bd9Sstevel@tonic-gate 						wp = (unsigned char *)(cp -
12557c478bd9Sstevel@tonic-gate 							MB_CUR_MAX);
12567c478bd9Sstevel@tonic-gate 						if (wp < ogcursor)
12577c478bd9Sstevel@tonic-gate 							wp = ogcursor;
12587c478bd9Sstevel@tonic-gate 						while (cp > wp) {
12597c478bd9Sstevel@tonic-gate /* 7tabs */if (wc2) {
12607c478bd9Sstevel@tonic-gate /* 7tabs */	if ((bytelength = mbtowc(&wc1, (char *)wp, cp-wp)) != cp-wp) {
12617c478bd9Sstevel@tonic-gate /* 7tabs */		wp++;
12627c478bd9Sstevel@tonic-gate /* 7tabs */		wc1 = 0;
12637c478bd9Sstevel@tonic-gate /* 7tabs */		continue;
12647c478bd9Sstevel@tonic-gate /* 7tabs */	}
12657c478bd9Sstevel@tonic-gate /* 7tabs */} else {
12667c478bd9Sstevel@tonic-gate /* 7tabs */	if ((bytelength = mbtowc(&wc2, (char *)wp, cp-wp)) != cp-wp) {
12677c478bd9Sstevel@tonic-gate /* 7tabs */		wp++;
12687c478bd9Sstevel@tonic-gate /* 7tabs */		wc2 = 0;
12697c478bd9Sstevel@tonic-gate /* 7tabs */		continue;
12707c478bd9Sstevel@tonic-gate /* 7tabs */	}
12717c478bd9Sstevel@tonic-gate /* 7tabs */}
12727c478bd9Sstevel@tonic-gate /* 7tabs */if (wc1) {
12737c478bd9Sstevel@tonic-gate /* 7tabs */	if (wdbdg && (!iswascii(wc1) || !iswascii(wc2))) {
12747c478bd9Sstevel@tonic-gate /* 7tabs */		if ((*wdbdg)(wc1, wc2, 2) < 5) {
12757c478bd9Sstevel@tonic-gate /* 7tabs */			goto ws;
12767c478bd9Sstevel@tonic-gate /* 7tabs */		}
12777c478bd9Sstevel@tonic-gate /* 7tabs */	}
12787c478bd9Sstevel@tonic-gate /* 7tabs */	wc2 = wc1;
12797c478bd9Sstevel@tonic-gate /* 7tabs */	wc1 = 0;
12807c478bd9Sstevel@tonic-gate /* 7tabs */	cp -= bytelength - 1;
12817c478bd9Sstevel@tonic-gate /* 7tabs */	break;
12827c478bd9Sstevel@tonic-gate /* 7tabs */} else {
12837c478bd9Sstevel@tonic-gate /* 7tabs */	cp -= bytelength - 1;
12847c478bd9Sstevel@tonic-gate /* 7tabs */	break;
12857c478bd9Sstevel@tonic-gate /* 7tabs */}
12867c478bd9Sstevel@tonic-gate 						}
12877c478bd9Sstevel@tonic-gate 						cp--;
12887c478bd9Sstevel@tonic-gate 					}
12897c478bd9Sstevel@tonic-gate ws:
12907c478bd9Sstevel@tonic-gate #endif /* PRESUNEUC */
12917c478bd9Sstevel@tonic-gate 					if (cp <= ogcursor) {
12927c478bd9Sstevel@tonic-gate 						/*
12937c478bd9Sstevel@tonic-gate 						 * There is a single word that
12947c478bd9Sstevel@tonic-gate 						 * is too long to fit.  Just
12957c478bd9Sstevel@tonic-gate 						 * let it pass, but beep for
12967c478bd9Sstevel@tonic-gate 						 * each new letter to warn
12977c478bd9Sstevel@tonic-gate 						 * the luser.
12987c478bd9Sstevel@tonic-gate 						 */
12997c478bd9Sstevel@tonic-gate 						gcursor -= length;
13007c478bd9Sstevel@tonic-gate 						c = *gcursor;
13017c478bd9Sstevel@tonic-gate 						*gcursor = 0;
1302f6db9f27Scf46844 						(void) beep();
13037c478bd9Sstevel@tonic-gate 						goto dontbreak;
13047c478bd9Sstevel@tonic-gate 					}
13057c478bd9Sstevel@tonic-gate 					/*
13067c478bd9Sstevel@tonic-gate 					 * Save it for next line.
13077c478bd9Sstevel@tonic-gate 					 */
13087c478bd9Sstevel@tonic-gate 					macpush(cp, 0);
13097c478bd9Sstevel@tonic-gate #ifdef PRESUNEUC
13107c478bd9Sstevel@tonic-gate 					cp--;
13117c478bd9Sstevel@tonic-gate #endif /* PRESUNEUC */
13127c478bd9Sstevel@tonic-gate 				}
13137c478bd9Sstevel@tonic-gate 				macpush("\n", 0);
13147c478bd9Sstevel@tonic-gate 				/*
13157c478bd9Sstevel@tonic-gate 				 * Erase white space before the word.
13167c478bd9Sstevel@tonic-gate 				 */
13177c478bd9Sstevel@tonic-gate 				while (cp > ogcursor && isspace(cp[-1]))
13187c478bd9Sstevel@tonic-gate 					cp--;	/* skip blank */
13197c478bd9Sstevel@tonic-gate 				gobblebl = 3;
13207c478bd9Sstevel@tonic-gate 				goto vbackup;
13217c478bd9Sstevel@tonic-gate 			}
13227c478bd9Sstevel@tonic-gate 		dontbreak:;
13237c478bd9Sstevel@tonic-gate 		}
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate 		/*
13267c478bd9Sstevel@tonic-gate 		 * Word abbreviation mode.
13277c478bd9Sstevel@tonic-gate 		 */
13287c478bd9Sstevel@tonic-gate 		if (anyabbrs && gcursor > ogcursor && !wordch(multic) && wordch(lastchr(ogcursor, gcursor))) {
13297c478bd9Sstevel@tonic-gate 				int wdtype, abno;
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 				multic[length] = 0;
13327c478bd9Sstevel@tonic-gate 				wdkind = 1;
13337c478bd9Sstevel@tonic-gate 				cp = lastchr(ogcursor, gcursor);
13347c478bd9Sstevel@tonic-gate 				pcp = lastchr(ogcursor, cp);
13357c478bd9Sstevel@tonic-gate 				for (wdtype = wordch(pcp);
13367c478bd9Sstevel@tonic-gate 				    cp > ogcursor && wordof(wdtype, pcp); cp = pcp, pcp = lastchr(ogcursor, pcp))
13377c478bd9Sstevel@tonic-gate 					;
13387c478bd9Sstevel@tonic-gate 				*gcursor = 0;
13397c478bd9Sstevel@tonic-gate 				for (abno=0; abbrevs[abno].mapto; abno++) {
13407c478bd9Sstevel@tonic-gate 					if (eq(cp, abbrevs[abno].cap)) {
13417c478bd9Sstevel@tonic-gate 						if(abbrepcnt == 0) {
13427c478bd9Sstevel@tonic-gate 							if(reccnt(abbrevs[abno].cap, abbrevs[abno].mapto))
13437c478bd9Sstevel@tonic-gate 								abbrepcnt = 1;
13447c478bd9Sstevel@tonic-gate 							macpush(multic, 0);
13457c478bd9Sstevel@tonic-gate 							macpush(abbrevs[abno].mapto);
13467c478bd9Sstevel@tonic-gate 							goto vbackup;
13477c478bd9Sstevel@tonic-gate 						} else
13487c478bd9Sstevel@tonic-gate 							abbrepcnt = 0;
13497c478bd9Sstevel@tonic-gate 					}
13507c478bd9Sstevel@tonic-gate 				}
13517c478bd9Sstevel@tonic-gate 		}
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 		switch (c) {
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 		/*
13567c478bd9Sstevel@tonic-gate 		 * ^M		Except in repeat maps to \n.
13577c478bd9Sstevel@tonic-gate 		 */
13587c478bd9Sstevel@tonic-gate 		case CR:
13597c478bd9Sstevel@tonic-gate 			if (vglobp) {
13607c478bd9Sstevel@tonic-gate 				multic[0] = wchar = c;
13617c478bd9Sstevel@tonic-gate 				length = 1;
13627c478bd9Sstevel@tonic-gate 				goto def;
13637c478bd9Sstevel@tonic-gate 			}
13647c478bd9Sstevel@tonic-gate 			c = '\n';
13657c478bd9Sstevel@tonic-gate 			/* presto chango ... */
13667c478bd9Sstevel@tonic-gate 
13677c478bd9Sstevel@tonic-gate 		/*
13687c478bd9Sstevel@tonic-gate 		 * \n		Start new line.
13697c478bd9Sstevel@tonic-gate 		 */
13707c478bd9Sstevel@tonic-gate 		case NL:
13717c478bd9Sstevel@tonic-gate 			*aescaped = c;
13727c478bd9Sstevel@tonic-gate 			goto vadone;
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate 		/*
13757c478bd9Sstevel@tonic-gate 		 * escape	End insert unless repeat and more to repeat.
13767c478bd9Sstevel@tonic-gate 		 */
13777c478bd9Sstevel@tonic-gate 		case ESCAPE:
13787c478bd9Sstevel@tonic-gate 			if (lastvgk) {
13797c478bd9Sstevel@tonic-gate 				multic[0] = wchar = c;
13807c478bd9Sstevel@tonic-gate 				length = 1;
13817c478bd9Sstevel@tonic-gate 				goto def;
13827c478bd9Sstevel@tonic-gate 			}
13837c478bd9Sstevel@tonic-gate 			goto vadone;
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 		/*
13867c478bd9Sstevel@tonic-gate 		 * ^D		Backtab.
13877c478bd9Sstevel@tonic-gate 		 * ^T		Software forward tab.
13887c478bd9Sstevel@tonic-gate 		 *
13897c478bd9Sstevel@tonic-gate 		 *		Unless in repeat where this means these
13907c478bd9Sstevel@tonic-gate 		 *		were superquoted in.
13917c478bd9Sstevel@tonic-gate 		 */
13927c478bd9Sstevel@tonic-gate 		case CTRL('t'):
13937c478bd9Sstevel@tonic-gate 			if (vglobp) {
13947c478bd9Sstevel@tonic-gate 				multic[0] = wchar = c;
13957c478bd9Sstevel@tonic-gate 				length = 1;
13967c478bd9Sstevel@tonic-gate 				goto def;
13977c478bd9Sstevel@tonic-gate 			}
13987c478bd9Sstevel@tonic-gate 			/* fall into ... */
13997c478bd9Sstevel@tonic-gate 
14007c478bd9Sstevel@tonic-gate 			*gcursor = 0;
14017c478bd9Sstevel@tonic-gate 			cp = vpastwh(genbuf);
14027c478bd9Sstevel@tonic-gate 			c = whitecnt(genbuf);
14037c478bd9Sstevel@tonic-gate 			if (ch == CTRL('t')) {
14047c478bd9Sstevel@tonic-gate 				/*
14057c478bd9Sstevel@tonic-gate 				 * ^t just generates new indent replacing
14067c478bd9Sstevel@tonic-gate 				 * current white space rounded up to soft
14077c478bd9Sstevel@tonic-gate 				 * tab stop increment.
14087c478bd9Sstevel@tonic-gate 				 */
14097c478bd9Sstevel@tonic-gate 				if (cp != gcursor)
14107c478bd9Sstevel@tonic-gate 					/*
14117c478bd9Sstevel@tonic-gate 					 * BUG:		Don't hack ^T except
14127c478bd9Sstevel@tonic-gate 					 *		right after initial
14137c478bd9Sstevel@tonic-gate 					 *		white space.
14147c478bd9Sstevel@tonic-gate 					 */
14157c478bd9Sstevel@tonic-gate 					continue;
14167c478bd9Sstevel@tonic-gate 				cp = genindent(iwhite = backtab(c + value(vi_SHIFTWIDTH) + 1));
14177c478bd9Sstevel@tonic-gate 				ogcursor = cp;
14187c478bd9Sstevel@tonic-gate 				goto vbackup;
14197c478bd9Sstevel@tonic-gate 			}
14207c478bd9Sstevel@tonic-gate 			/*
14217c478bd9Sstevel@tonic-gate 			 * ^D works only if we are at the (end of) the
14227c478bd9Sstevel@tonic-gate 			 * generated autoindent.  We count the ^D for repeat
14237c478bd9Sstevel@tonic-gate 			 * purposes.
14247c478bd9Sstevel@tonic-gate 			 */
14257c478bd9Sstevel@tonic-gate 		case CTRL('d'):
14267c478bd9Sstevel@tonic-gate 			/* check if ^d was superquoted in */
14277c478bd9Sstevel@tonic-gate 			if(vglobp && inscdcnt <= 0) {
14287c478bd9Sstevel@tonic-gate 				multic[0] = wchar = c;
14297c478bd9Sstevel@tonic-gate 				length = 1;
14307c478bd9Sstevel@tonic-gate 				goto def;
14317c478bd9Sstevel@tonic-gate 			}
14327c478bd9Sstevel@tonic-gate 			if(vglobp)
14337c478bd9Sstevel@tonic-gate 				inscdcnt--;
14347c478bd9Sstevel@tonic-gate 			*gcursor = 0;
14357c478bd9Sstevel@tonic-gate 			cp = vpastwh(genbuf);
14367c478bd9Sstevel@tonic-gate 			c = whitecnt(genbuf);
14377c478bd9Sstevel@tonic-gate 			if (c == iwhite && c != 0)
14387c478bd9Sstevel@tonic-gate 				if (cp == gcursor) {
14397c478bd9Sstevel@tonic-gate 					iwhite = backtab(c);
14407c478bd9Sstevel@tonic-gate 					CDCNT++;
14417c478bd9Sstevel@tonic-gate 					ogcursor = cp = genindent(iwhite);
14427c478bd9Sstevel@tonic-gate 					goto vbackup;
14437c478bd9Sstevel@tonic-gate 				} else if (&cp[1] == gcursor &&
14447c478bd9Sstevel@tonic-gate 				    (*cp == '^' || *cp == '0')) {
14457c478bd9Sstevel@tonic-gate 					/*
14467c478bd9Sstevel@tonic-gate 					 * ^^D moves to margin, then back
14477c478bd9Sstevel@tonic-gate 					 * to current indent on next line.
14487c478bd9Sstevel@tonic-gate 					 *
14497c478bd9Sstevel@tonic-gate 					 * 0^D moves to margin and then
14507c478bd9Sstevel@tonic-gate 					 * stays there.
14517c478bd9Sstevel@tonic-gate 					 */
14527c478bd9Sstevel@tonic-gate 					HADZERO = *cp == '0';
14537c478bd9Sstevel@tonic-gate 					ogcursor = cp = genbuf;
14547c478bd9Sstevel@tonic-gate 					HADUP = 1 - HADZERO;
14557c478bd9Sstevel@tonic-gate 					CDCNT = 1;
14567c478bd9Sstevel@tonic-gate 					endim();
14577c478bd9Sstevel@tonic-gate 					back1();
1458f6db9f27Scf46844 					(void) vputchar(' ');
14597c478bd9Sstevel@tonic-gate 					goto vbackup;
14607c478bd9Sstevel@tonic-gate 				}
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate 			if (vglobp && vglobp - iglobp >= 2) {
14637c478bd9Sstevel@tonic-gate 				if ((p = vglobp - MB_CUR_MAX) < iglobp)
14647c478bd9Sstevel@tonic-gate 					p = iglobp;
14657c478bd9Sstevel@tonic-gate 				for ( ; p < &vglobp[-2]; p += len) {
14667c478bd9Sstevel@tonic-gate 					if ((len = mblen((char *)p, MB_CUR_MAX)) <= 0)
14677c478bd9Sstevel@tonic-gate 						len = 1;
14687c478bd9Sstevel@tonic-gate 				}
14697c478bd9Sstevel@tonic-gate 				if ((p == &vglobp[-2]) &&
14707c478bd9Sstevel@tonic-gate 			            (*p == '^' || *p == '0') &&
14717c478bd9Sstevel@tonic-gate 			            gcursor == ogcursor + 1)
14727c478bd9Sstevel@tonic-gate 					goto bakchar;
14737c478bd9Sstevel@tonic-gate 			}
14747c478bd9Sstevel@tonic-gate 			continue;
14757c478bd9Sstevel@tonic-gate 
14767c478bd9Sstevel@tonic-gate 		default:
14777c478bd9Sstevel@tonic-gate 			/*
14787c478bd9Sstevel@tonic-gate 			 * Possibly discard control inputs.
14797c478bd9Sstevel@tonic-gate 			 */
14807c478bd9Sstevel@tonic-gate 			if (!vglobp && junk(c)) {
1481f6db9f27Scf46844 				(void) beep();
14827c478bd9Sstevel@tonic-gate 				continue;
14837c478bd9Sstevel@tonic-gate 			}
14847c478bd9Sstevel@tonic-gate def:
14857c478bd9Sstevel@tonic-gate 			if (!backsl) {
14867c478bd9Sstevel@tonic-gate 				putchar(wchar);
14877c478bd9Sstevel@tonic-gate 				flush();
14887c478bd9Sstevel@tonic-gate 			}
14897c478bd9Sstevel@tonic-gate 			if (gcursor + length - 1 > &genbuf[LBSIZE - 2])
14907c478bd9Sstevel@tonic-gate 				error(gettext("Line too long"));
14917c478bd9Sstevel@tonic-gate 			(void)strncpy(gcursor, multic, length);
14927c478bd9Sstevel@tonic-gate 			gcursor += length;
14937c478bd9Sstevel@tonic-gate 			vcsync();
14947c478bd9Sstevel@tonic-gate 			if (value(vi_SHOWMATCH) && !iglobp)
14957c478bd9Sstevel@tonic-gate 				if (c == ')' || c == '}')
14967c478bd9Sstevel@tonic-gate 					lsmatch(gcursor);
14977c478bd9Sstevel@tonic-gate 			continue;
14987c478bd9Sstevel@tonic-gate 		}
14997c478bd9Sstevel@tonic-gate 	}
15007c478bd9Sstevel@tonic-gate vadone:
15017c478bd9Sstevel@tonic-gate 	*gcursor = 0;
15027c478bd9Sstevel@tonic-gate 	if (Outchar != termchar)
15037c478bd9Sstevel@tonic-gate 		Outchar = OO;
15047c478bd9Sstevel@tonic-gate 	endim();
15057c478bd9Sstevel@tonic-gate 	return (gcursor);
15067c478bd9Sstevel@tonic-gate }
15077c478bd9Sstevel@tonic-gate 
15087c478bd9Sstevel@tonic-gate int	vgetsplit();
15097c478bd9Sstevel@tonic-gate unsigned char	*vsplitpt;
15107c478bd9Sstevel@tonic-gate 
15117c478bd9Sstevel@tonic-gate /*
15127c478bd9Sstevel@tonic-gate  * Append the line in buffer at lp
15137c478bd9Sstevel@tonic-gate  * to the buffer after dot.
15147c478bd9Sstevel@tonic-gate  */
1515f6db9f27Scf46844 void
1516f6db9f27Scf46844 vdoappend(unsigned char *lp)
15177c478bd9Sstevel@tonic-gate {
1518f6db9f27Scf46844 	int oing = inglobal;
15197c478bd9Sstevel@tonic-gate 
15207c478bd9Sstevel@tonic-gate 	vsplitpt = lp;
15217c478bd9Sstevel@tonic-gate 	inglobal = 1;
15227c478bd9Sstevel@tonic-gate 	(void)append(vgetsplit, dot);
15237c478bd9Sstevel@tonic-gate 	inglobal = oing;
15247c478bd9Sstevel@tonic-gate }
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate /*
15277c478bd9Sstevel@tonic-gate  * Subroutine for vdoappend to pass to append.
15287c478bd9Sstevel@tonic-gate  */
1529f6db9f27Scf46844 int
1530f6db9f27Scf46844 vgetsplit(void)
15317c478bd9Sstevel@tonic-gate {
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate 	if (vsplitpt == 0)
15347c478bd9Sstevel@tonic-gate 		return (EOF);
15357c478bd9Sstevel@tonic-gate 	strcLIN(vsplitpt);
15367c478bd9Sstevel@tonic-gate 	vsplitpt = 0;
15377c478bd9Sstevel@tonic-gate 	return (0);
15387c478bd9Sstevel@tonic-gate }
15397c478bd9Sstevel@tonic-gate 
15407c478bd9Sstevel@tonic-gate /*
15417c478bd9Sstevel@tonic-gate  * Vmaxrep determines the maximum repetition factor
15427c478bd9Sstevel@tonic-gate  * allowed that will yield total line length less than
15437c478bd9Sstevel@tonic-gate  * LBSIZE characters and also does hacks for the R command.
15447c478bd9Sstevel@tonic-gate  */
1545f6db9f27Scf46844 int
1546f6db9f27Scf46844 vmaxrep(unsigned char ch, int cnt)
15477c478bd9Sstevel@tonic-gate {
1548f6db9f27Scf46844 	int len;
15497c478bd9Sstevel@tonic-gate 	unsigned char *cp;
15507c478bd9Sstevel@tonic-gate 	int repcnt, oldcnt, replen;
15517c478bd9Sstevel@tonic-gate 	if (cnt > LBSIZE - 2)
15527c478bd9Sstevel@tonic-gate 		cnt = LBSIZE - 2;
15537c478bd9Sstevel@tonic-gate 	if (ch == 'R') {
15547c478bd9Sstevel@tonic-gate 		len = strlen(cursor);
15557c478bd9Sstevel@tonic-gate 		oldcnt = 0;
15567c478bd9Sstevel@tonic-gate 		for(cp = cursor; *cp; ) {
15577c478bd9Sstevel@tonic-gate 			oldcnt++;
15587c478bd9Sstevel@tonic-gate 			cp = nextchr(cp);
15597c478bd9Sstevel@tonic-gate 		}
15607c478bd9Sstevel@tonic-gate 		repcnt = 0;
15617c478bd9Sstevel@tonic-gate 		for(cp = genbuf; *cp; ) {
15627c478bd9Sstevel@tonic-gate 			repcnt++;
15637c478bd9Sstevel@tonic-gate 			cp = nextchr(cp);
15647c478bd9Sstevel@tonic-gate 		}
15657c478bd9Sstevel@tonic-gate 		/*
15667c478bd9Sstevel@tonic-gate 		 * if number of characters in replacement string
15677c478bd9Sstevel@tonic-gate 		 * (repcnt) is less than number of characters following
15687c478bd9Sstevel@tonic-gate 		 * cursor (oldcnt), find end of repcnt
15697c478bd9Sstevel@tonic-gate 		 * characters after cursor
15707c478bd9Sstevel@tonic-gate 		 */
15717c478bd9Sstevel@tonic-gate 		if(repcnt < oldcnt) {
15727c478bd9Sstevel@tonic-gate 			for(cp = cursor; repcnt > 0; repcnt--)
15737c478bd9Sstevel@tonic-gate 				cp = nextchr(cp);
15747c478bd9Sstevel@tonic-gate 			len = cp - cursor;
15757c478bd9Sstevel@tonic-gate 		}
15767c478bd9Sstevel@tonic-gate 		CP(cursor, cursor + len);
15777c478bd9Sstevel@tonic-gate 		vUD2 += len;
15787c478bd9Sstevel@tonic-gate 	}
15797c478bd9Sstevel@tonic-gate 	len = strlen(linebuf);
15807c478bd9Sstevel@tonic-gate 	replen = strlen(genbuf);
15817c478bd9Sstevel@tonic-gate 	if (len + cnt * replen <= LBSIZE - 2)
15827c478bd9Sstevel@tonic-gate 		return (cnt);
15837c478bd9Sstevel@tonic-gate 	cnt = (LBSIZE - 2 - len) / replen;
15847c478bd9Sstevel@tonic-gate 	if (cnt == 0) {
15857c478bd9Sstevel@tonic-gate 		vsave();
15867c478bd9Sstevel@tonic-gate 		error(gettext("Line too long"));
15877c478bd9Sstevel@tonic-gate 	}
15887c478bd9Sstevel@tonic-gate 	return (cnt);
15897c478bd9Sstevel@tonic-gate }
15907c478bd9Sstevel@tonic-gate 
15917c478bd9Sstevel@tonic-gate /*
15927c478bd9Sstevel@tonic-gate  * Determine how many occurrences of word 'CAP' are in 'MAPTO'.  To be
15937c478bd9Sstevel@tonic-gate  * considered an occurrence there must be both a nonword-prefix, a
15947c478bd9Sstevel@tonic-gate  * complete match of 'CAP' within 'MAPTO', and a nonword-suffix.
15957c478bd9Sstevel@tonic-gate  * Note that the beginning and end of 'MAPTO' are considered to be
15967c478bd9Sstevel@tonic-gate  * valid nonword delimiters.
15977c478bd9Sstevel@tonic-gate  */
1598f6db9f27Scf46844 int
1599f6db9f27Scf46844 reccnt(unsigned char *cap, unsigned char *mapto)
16007c478bd9Sstevel@tonic-gate {
1601f6db9f27Scf46844 	int i, cnt, final;
16027c478bd9Sstevel@tonic-gate 
16037c478bd9Sstevel@tonic-gate 	cnt = 0;
16047c478bd9Sstevel@tonic-gate 	final = strlen(mapto) - strlen(cap);
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate 	for (i=0; i <= final; i++)
16077c478bd9Sstevel@tonic-gate 	  if ((strncmp(cap, mapto+i, strlen(cap)) == 0)       /* match */
16087c478bd9Sstevel@tonic-gate 	  && (i == 0     || !wordch(&mapto[i-1]))	      /* prefix ok */
16097c478bd9Sstevel@tonic-gate 	  && (i == final || !wordch(&mapto[i+strlen(cap)])))  /* suffix ok */
16107c478bd9Sstevel@tonic-gate 		cnt++;
16117c478bd9Sstevel@tonic-gate 	return (cnt);
16127c478bd9Sstevel@tonic-gate }
16137c478bd9Sstevel@tonic-gate 
1614