xref: /onnv-gate/usr/src/cmd/vi/port/ex_vops2.c (revision 802:73b56fb6544b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*802Scf46844  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
280Sstevel@tonic-gate /*	  All Rights Reserved  	*/
290Sstevel@tonic-gate 
300Sstevel@tonic-gate 
310Sstevel@tonic-gate /* Copyright (c) 1981 Regents of the University of California */
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include "ex.h"
360Sstevel@tonic-gate #include "ex_tty.h"
370Sstevel@tonic-gate #include "ex_vis.h"
380Sstevel@tonic-gate #ifndef PRESUNEUC
390Sstevel@tonic-gate #include <wctype.h>
400Sstevel@tonic-gate /* Undef putchar/getchar if they're defined. */
410Sstevel@tonic-gate #ifdef putchar
420Sstevel@tonic-gate #	undef putchar
430Sstevel@tonic-gate #endif
440Sstevel@tonic-gate #ifdef getchar
450Sstevel@tonic-gate #	undef getchar
460Sstevel@tonic-gate #endif
470Sstevel@tonic-gate #endif /* PRESUNEUC */
480Sstevel@tonic-gate 
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate  * Low level routines for operations sequences,
510Sstevel@tonic-gate  * and mostly, insert mode (and a subroutine
520Sstevel@tonic-gate  * to read an input line, including in the echo area.)
530Sstevel@tonic-gate  */
540Sstevel@tonic-gate extern unsigned char	*vUA1, *vUA2;		/* extern; also in ex_vops.c */
550Sstevel@tonic-gate extern unsigned char	*vUD1, *vUD2;		/* extern; also in ex_vops.c */
560Sstevel@tonic-gate 
57*802Scf46844 int vmaxrep(unsigned char, int);
58*802Scf46844 
590Sstevel@tonic-gate /*
600Sstevel@tonic-gate  * Obleeperate characters in hardcopy
610Sstevel@tonic-gate  * open with \'s.
620Sstevel@tonic-gate  */
63*802Scf46844 void
64*802Scf46844 bleep(int i, unsigned char *cp)
650Sstevel@tonic-gate {
660Sstevel@tonic-gate 
670Sstevel@tonic-gate 	i -= lcolumn(nextchr(cp));
680Sstevel@tonic-gate 	do
690Sstevel@tonic-gate 		putchar('\\' | QUOTE);
700Sstevel@tonic-gate 	while (--i >= 0);
710Sstevel@tonic-gate 	rubble = 1;
720Sstevel@tonic-gate }
730Sstevel@tonic-gate 
740Sstevel@tonic-gate /*
750Sstevel@tonic-gate  * Common code for middle part of delete
760Sstevel@tonic-gate  * and change operating on parts of lines.
770Sstevel@tonic-gate  */
78*802Scf46844 int
79*802Scf46844 vdcMID(void)
800Sstevel@tonic-gate {
81*802Scf46844 	unsigned char *cp;
820Sstevel@tonic-gate 
830Sstevel@tonic-gate 	squish();
840Sstevel@tonic-gate 	setLAST();
850Sstevel@tonic-gate 	if (FIXUNDO)
860Sstevel@tonic-gate 		vundkind = VCHNG, CP(vutmp, linebuf);
870Sstevel@tonic-gate 	if (wcursor < cursor)
880Sstevel@tonic-gate 		cp = wcursor, wcursor = cursor, cursor = cp;
890Sstevel@tonic-gate 	vUD1 = vUA1 = vUA2 = cursor; vUD2 = wcursor;
900Sstevel@tonic-gate 	return (lcolumn(wcursor));
910Sstevel@tonic-gate }
920Sstevel@tonic-gate 
930Sstevel@tonic-gate /*
940Sstevel@tonic-gate  * Take text from linebuf and stick it
950Sstevel@tonic-gate  * in the VBSIZE buffer BUF.  Used to save
960Sstevel@tonic-gate  * deleted text of part of line.
970Sstevel@tonic-gate  */
98*802Scf46844 void
99*802Scf46844 takeout(unsigned char *BUF)
1000Sstevel@tonic-gate {
101*802Scf46844 	unsigned char *cp;
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 	if (wcursor < linebuf)
1040Sstevel@tonic-gate 		wcursor = linebuf;
1050Sstevel@tonic-gate 	if (cursor == wcursor) {
106*802Scf46844 		(void) beep();
1070Sstevel@tonic-gate 		return;
1080Sstevel@tonic-gate 	}
1090Sstevel@tonic-gate 	if (wcursor < cursor) {
1100Sstevel@tonic-gate 		cp = wcursor;
1110Sstevel@tonic-gate 		wcursor = cursor;
1120Sstevel@tonic-gate 		cursor = cp;
1130Sstevel@tonic-gate 	}
1140Sstevel@tonic-gate 	setBUF(BUF);
1150Sstevel@tonic-gate 	if ((unsigned char)BUF[128] == 0200)
116*802Scf46844 		(void) beep();
1170Sstevel@tonic-gate }
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate /*
1200Sstevel@tonic-gate  * Are we at the end of the printed representation of the
1210Sstevel@tonic-gate  * line?  Used internally in hardcopy open.
1220Sstevel@tonic-gate  */
123*802Scf46844 int
124*802Scf46844 ateopr(void)
1250Sstevel@tonic-gate {
126*802Scf46844 	wchar_t i, c;
127*802Scf46844 	wchar_t *cp = vtube[destline] + destcol;
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 	for (i = WCOLS - destcol; i > 0; i--) {
1300Sstevel@tonic-gate 		c = *cp++;
1310Sstevel@tonic-gate 		if (c == 0) {
1320Sstevel@tonic-gate 			/*
1330Sstevel@tonic-gate 			 * Optimization to consider returning early, saving
1340Sstevel@tonic-gate 			 * CPU time.  We have to make a special check that
1350Sstevel@tonic-gate 			 * we aren't missing a mode indicator.
1360Sstevel@tonic-gate 			 */
1370Sstevel@tonic-gate 			if (destline == WECHO && destcol < WCOLS-11 && vtube[WECHO][WCOLS-20])
1380Sstevel@tonic-gate 				return 0;
1390Sstevel@tonic-gate 			return (1);
1400Sstevel@tonic-gate 		}
1410Sstevel@tonic-gate 		if (c != ' ' && (c & QUOTE) == 0)
1420Sstevel@tonic-gate 			return (0);
1430Sstevel@tonic-gate 	}
1440Sstevel@tonic-gate 	return (1);
1450Sstevel@tonic-gate }
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate /*
1480Sstevel@tonic-gate  * Append.
1490Sstevel@tonic-gate  *
1500Sstevel@tonic-gate  * This routine handles the top level append, doing work
1510Sstevel@tonic-gate  * as each new line comes in, and arranging repeatability.
1520Sstevel@tonic-gate  * It also handles append with repeat counts, and calculation
1530Sstevel@tonic-gate  * of autoindents for new lines.
1540Sstevel@tonic-gate  */
1550Sstevel@tonic-gate bool	vaifirst;
1560Sstevel@tonic-gate bool	gobbled;
1570Sstevel@tonic-gate unsigned char	*ogcursor;
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate static int 	INSCDCNT; /* number of ^D's (backtabs) in insertion buffer */
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate static int 	inscdcnt; /*
1620Sstevel@tonic-gate 			   * count of ^D's (backtabs) not seen yet when doing
1630Sstevel@tonic-gate 		 	   * repeat of insertion
1640Sstevel@tonic-gate 			   */
1650Sstevel@tonic-gate 
166*802Scf46844 void
167*802Scf46844 vappend(int ch, int cnt, int indent)
1680Sstevel@tonic-gate {
169*802Scf46844 	int i;
170*802Scf46844 	unsigned char *gcursor;
1710Sstevel@tonic-gate 	bool escape;
1720Sstevel@tonic-gate 	int repcnt, savedoomed;
1730Sstevel@tonic-gate 	short oldhold = hold;
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	/*
1760Sstevel@tonic-gate 	 * Before a move in hardopen when the line is dirty
1770Sstevel@tonic-gate 	 * or we are in the middle of the printed representation,
1780Sstevel@tonic-gate 	 * we retype the line to the left of the cursor so the
1790Sstevel@tonic-gate 	 * insert looks clean.
1800Sstevel@tonic-gate 	 */
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	if (ch != 'o' && state == HARDOPEN && (rubble || !ateopr())) {
1830Sstevel@tonic-gate 		rubble = 1;
1840Sstevel@tonic-gate 		gcursor = cursor;
1850Sstevel@tonic-gate 		i = *gcursor;
1860Sstevel@tonic-gate 		*gcursor = ' ';
1870Sstevel@tonic-gate 		wcursor = gcursor;
188*802Scf46844 		(void) vmove();
1890Sstevel@tonic-gate 		*gcursor = i;
1900Sstevel@tonic-gate 	}
1910Sstevel@tonic-gate 	vaifirst = indent == 0;
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	/*
1940Sstevel@tonic-gate 	 * Handle replace character by (eventually)
1950Sstevel@tonic-gate 	 * limiting the number of input characters allowed
1960Sstevel@tonic-gate 	 * in the vgetline routine.
1970Sstevel@tonic-gate 	 */
1980Sstevel@tonic-gate 	if (ch == 'r')
1990Sstevel@tonic-gate 		repcnt = 2;
2000Sstevel@tonic-gate 	else
2010Sstevel@tonic-gate 		repcnt = 0;
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	/*
2040Sstevel@tonic-gate 	 * If an autoindent is specified, then
2050Sstevel@tonic-gate 	 * generate a mixture of blanks to tabs to implement
2060Sstevel@tonic-gate 	 * it and place the cursor after the indent.
2070Sstevel@tonic-gate 	 * Text read by the vgetline routine will be placed in genbuf,
2080Sstevel@tonic-gate 	 * so the indent is generated there.
2090Sstevel@tonic-gate 	 */
2100Sstevel@tonic-gate 	if (value(vi_AUTOINDENT) && indent != 0) {
2110Sstevel@tonic-gate 		unsigned char x;
2120Sstevel@tonic-gate 		gcursor = genindent(indent);
2130Sstevel@tonic-gate 		*gcursor = 0;
2140Sstevel@tonic-gate 		vgotoCL(nqcolumn(lastchr(linebuf, cursor), genbuf));
2150Sstevel@tonic-gate 	} else {
2160Sstevel@tonic-gate 		gcursor = genbuf;
2170Sstevel@tonic-gate 		*gcursor = 0;
2180Sstevel@tonic-gate 		if (ch == 'o')
2190Sstevel@tonic-gate 			vfixcurs();
2200Sstevel@tonic-gate 	}
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 	/*
2230Sstevel@tonic-gate 	 * Prepare for undo.  Pointers delimit inserted portion of line.
2240Sstevel@tonic-gate 	 */
2250Sstevel@tonic-gate 	vUA1 = vUA2 = cursor;
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	/*
2280Sstevel@tonic-gate 	 * If we are not in a repeated command and a ^@ comes in
2290Sstevel@tonic-gate 	 * then this means the previous inserted text.
2300Sstevel@tonic-gate 	 * If there is none or it was too long to be saved,
2310Sstevel@tonic-gate 	 * then beep() and also arrange to undo any damage done
2320Sstevel@tonic-gate 	 * so far (e.g. if we are a change.)
2330Sstevel@tonic-gate 	 */
2340Sstevel@tonic-gate 	switch (ch) {
2350Sstevel@tonic-gate 	case 'r':
2360Sstevel@tonic-gate 		break;
2370Sstevel@tonic-gate 	case 'a':
2380Sstevel@tonic-gate 		/*
2390Sstevel@tonic-gate 		 * TRANSLATION_NOTE
2400Sstevel@tonic-gate 		 *	"A" is a terse mode message corresponding to
2410Sstevel@tonic-gate 		 *	"APPEND MODE".
2420Sstevel@tonic-gate 		 *	Translated message of "A" must be 1 character (not byte).
2430Sstevel@tonic-gate 		 *	Or, just leave it.
2440Sstevel@tonic-gate 		 */
2450Sstevel@tonic-gate 		if (value(vi_TERSE)) {
2460Sstevel@tonic-gate 			vshowmode(gettext("A"));
2470Sstevel@tonic-gate 		} else {
2480Sstevel@tonic-gate 			vshowmode(gettext("APPEND MODE"));
2490Sstevel@tonic-gate 		}
2500Sstevel@tonic-gate 		break;
2510Sstevel@tonic-gate 	case 's':
2520Sstevel@tonic-gate 		/*
2530Sstevel@tonic-gate 		 * TRANSLATION_NOTE
2540Sstevel@tonic-gate 		 *	"S" is a terse mode message corresponding to
2550Sstevel@tonic-gate 		 *	"SUBSTITUTE MODE".
2560Sstevel@tonic-gate 		 *	Translated message of "S" must be 1 character (not byte).
2570Sstevel@tonic-gate 		 *	Or, just leave it.
2580Sstevel@tonic-gate 		 */
2590Sstevel@tonic-gate 		if (value(vi_TERSE)) {
2600Sstevel@tonic-gate 			vshowmode(gettext("S"));
2610Sstevel@tonic-gate 		} else {
2620Sstevel@tonic-gate 			vshowmode(gettext("SUBSTITUTE MODE"));
2630Sstevel@tonic-gate 		}
2640Sstevel@tonic-gate 		break;
2650Sstevel@tonic-gate 	case 'c':
2660Sstevel@tonic-gate 		/*
2670Sstevel@tonic-gate 		 * TRANSLATION_NOTE
2680Sstevel@tonic-gate 		 *	"C" is a terse mode message corresponding to
2690Sstevel@tonic-gate 		 *	"CHANGE MODE".
2700Sstevel@tonic-gate 		 *	Translated message of "C" must be 1 character (not byte).
2710Sstevel@tonic-gate 		 *	Or, just leave it.
2720Sstevel@tonic-gate 		 */
2730Sstevel@tonic-gate 		if (value(vi_TERSE)) {
2740Sstevel@tonic-gate 			vshowmode(gettext("C"));
2750Sstevel@tonic-gate 		} else {
2760Sstevel@tonic-gate 			vshowmode(gettext("CHANGE MODE"));
2770Sstevel@tonic-gate 		}
2780Sstevel@tonic-gate 		break;
2790Sstevel@tonic-gate 	case 'R':
2800Sstevel@tonic-gate 		/*
2810Sstevel@tonic-gate 		 * TRANSLATION_NOTE
2820Sstevel@tonic-gate 		 *	"R" is a terse mode message corresponding to
2830Sstevel@tonic-gate 		 *	"REPLACE MODE".
2840Sstevel@tonic-gate 		 *	Translated message of "R" must be 1 character (not byte).
2850Sstevel@tonic-gate 		 *	Or, just leave it.
2860Sstevel@tonic-gate 		 */
2870Sstevel@tonic-gate 		if (value(vi_TERSE)) {
2880Sstevel@tonic-gate 			vshowmode(gettext("R"));
2890Sstevel@tonic-gate 		} else {
2900Sstevel@tonic-gate 			vshowmode(gettext("REPLACE MODE"));
2910Sstevel@tonic-gate 		}
2920Sstevel@tonic-gate 		break;
2930Sstevel@tonic-gate 	case 'o':
2940Sstevel@tonic-gate 		/*
2950Sstevel@tonic-gate 		 * TRANSLATION_NOTE
2960Sstevel@tonic-gate 		 *	"O" is a terse mode message corresponding to
2970Sstevel@tonic-gate 		 *	"OPEN MODE".
2980Sstevel@tonic-gate 		 *	Translated message of "O" must be 1 character (not byte).
2990Sstevel@tonic-gate 		 *	Or, just leave it.
3000Sstevel@tonic-gate 		 */
3010Sstevel@tonic-gate 		if (value(vi_TERSE)) {
3020Sstevel@tonic-gate 			vshowmode(gettext("O"));
3030Sstevel@tonic-gate 		} else {
3040Sstevel@tonic-gate 			vshowmode(gettext("OPEN MODE"));
3050Sstevel@tonic-gate 		}
3060Sstevel@tonic-gate 		break;
3070Sstevel@tonic-gate 	case 'i':
3080Sstevel@tonic-gate 		/*
3090Sstevel@tonic-gate 		 * TRANSLATION_NOTE
3100Sstevel@tonic-gate 		 *	"I" is a terse mode message corresponding to
3110Sstevel@tonic-gate 		 *	"INSERT MODE" and the following "INPUT MODE".
3120Sstevel@tonic-gate 		 *	Translated message of "I" must be 1 character (not byte).
3130Sstevel@tonic-gate 		 *	Or, just leave it.
3140Sstevel@tonic-gate 		 */
3150Sstevel@tonic-gate 		if (value(vi_TERSE)) {
3160Sstevel@tonic-gate 			vshowmode(gettext("I"));
3170Sstevel@tonic-gate 		} else {
3180Sstevel@tonic-gate 			vshowmode(gettext("INSERT MODE"));
3190Sstevel@tonic-gate 		}
3200Sstevel@tonic-gate 		break;
3210Sstevel@tonic-gate 	default:
3220Sstevel@tonic-gate 		/*
3230Sstevel@tonic-gate 		 * TRANSLATION_NOTE
3240Sstevel@tonic-gate 		 *	"I" is a terse mode message corresponding to
3250Sstevel@tonic-gate 		 *	"INPUT MODE" and the previous "INSERT MODE".
3260Sstevel@tonic-gate 		 *	Translated message of "I" must be 1 character (not byte).
3270Sstevel@tonic-gate 		 *	Or, just leave it.
3280Sstevel@tonic-gate 		 */
3290Sstevel@tonic-gate 		if (value(vi_TERSE)) {
3300Sstevel@tonic-gate 			vshowmode(gettext("I"));
3310Sstevel@tonic-gate 		} else {
3320Sstevel@tonic-gate 			vshowmode(gettext("INPUT MODE"));
3330Sstevel@tonic-gate 		}
3340Sstevel@tonic-gate 	}
3350Sstevel@tonic-gate 	ixlatctl(1);
3360Sstevel@tonic-gate 	if ((vglobp && *vglobp == 0) || peekbr()) {
3370Sstevel@tonic-gate 		if (INS[128] == 0200) {
338*802Scf46844 			(void) beep();
3390Sstevel@tonic-gate 			if (!splitw)
3400Sstevel@tonic-gate 				ungetkey('u');
3410Sstevel@tonic-gate 			doomed = 0;
3420Sstevel@tonic-gate 			hold = oldhold;
3430Sstevel@tonic-gate 			return;
3440Sstevel@tonic-gate 		}
3450Sstevel@tonic-gate 		/*
3460Sstevel@tonic-gate 		 * Unread input from INS.
3470Sstevel@tonic-gate 		 * An escape will be generated at end of string.
3480Sstevel@tonic-gate 		 * Hold off n^^2 type update on dumb terminals.
3490Sstevel@tonic-gate 		 */
3500Sstevel@tonic-gate 		vglobp = INS;
3510Sstevel@tonic-gate 		inscdcnt = INSCDCNT;
3520Sstevel@tonic-gate 		hold |= HOLDQIK;
3530Sstevel@tonic-gate 	} else if (vglobp == 0) {
3540Sstevel@tonic-gate 		/*
3550Sstevel@tonic-gate 		 * Not a repeated command, get
3560Sstevel@tonic-gate 		 * a new inserted text for repeat.
3570Sstevel@tonic-gate 		 */
3580Sstevel@tonic-gate 		INS[0] = 0;
3590Sstevel@tonic-gate 		INS[128] = 0;
3600Sstevel@tonic-gate 		INSCDCNT = 0;
3610Sstevel@tonic-gate 	}
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 	/*
3640Sstevel@tonic-gate 	 * For wrapmargin to hack away second space after a '.'
3650Sstevel@tonic-gate 	 * when the first space caused a line break we keep
3660Sstevel@tonic-gate 	 * track that this happened in gobblebl, which says
3670Sstevel@tonic-gate 	 * to gobble up a blank silently.
3680Sstevel@tonic-gate 	 */
3690Sstevel@tonic-gate 	gobblebl = 0;
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	/*
3720Sstevel@tonic-gate 	 * Text gathering loop.
3730Sstevel@tonic-gate 	 * New text goes into genbuf starting at gcursor.
3740Sstevel@tonic-gate 	 * cursor preserves place in linebuf where text will eventually go.
3750Sstevel@tonic-gate 	 */
3760Sstevel@tonic-gate 	if (*cursor == 0 || state == CRTOPEN)
3770Sstevel@tonic-gate 		hold |= HOLDROL;
3780Sstevel@tonic-gate 	for (;;) {
3790Sstevel@tonic-gate 		if (ch == 'r' && repcnt == 0)
3800Sstevel@tonic-gate 			escape = 0;
3810Sstevel@tonic-gate 		else {
3820Sstevel@tonic-gate 			ixlatctl(1);
3830Sstevel@tonic-gate 			gcursor = vgetline(repcnt, gcursor, &escape, ch);
3840Sstevel@tonic-gate 			ixlatctl(0);
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 			/*
3870Sstevel@tonic-gate 			 * After an append, stick information
3880Sstevel@tonic-gate 			 * about the ^D's and ^^D's and 0^D's in
3890Sstevel@tonic-gate 			 * the repeated text buffer so repeated
3900Sstevel@tonic-gate 			 * inserts of stuff indented with ^D as backtab's
3910Sstevel@tonic-gate 			 * can work.
3920Sstevel@tonic-gate 			 */
3930Sstevel@tonic-gate 			if (HADUP)
3940Sstevel@tonic-gate 				addtext("^");
3950Sstevel@tonic-gate 			else if (HADZERO)
3960Sstevel@tonic-gate 				addtext("0");
3970Sstevel@tonic-gate 			if(!vglobp)
3980Sstevel@tonic-gate 				INSCDCNT = CDCNT;
3990Sstevel@tonic-gate 			while (CDCNT > 0) {
4000Sstevel@tonic-gate 				addtext("\004");
4010Sstevel@tonic-gate 				CDCNT--;
4020Sstevel@tonic-gate 			}
4030Sstevel@tonic-gate 			if (gobbled)
4040Sstevel@tonic-gate 				addtext(" ");
4050Sstevel@tonic-gate 			addtext(ogcursor);
4060Sstevel@tonic-gate 		}
4070Sstevel@tonic-gate 		repcnt = 0;
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 		/*
4100Sstevel@tonic-gate 		 * Smash the generated and preexisting indents together
4110Sstevel@tonic-gate 		 * and generate one cleanly made out of tabs and spaces
4120Sstevel@tonic-gate 		 * if we are using autoindent.
4130Sstevel@tonic-gate 		 */
4140Sstevel@tonic-gate 		if (!vaifirst && value(vi_AUTOINDENT)) {
4150Sstevel@tonic-gate 			i = fixindent(indent);
4160Sstevel@tonic-gate 			if (!HADUP)
4170Sstevel@tonic-gate 				indent = i;
4180Sstevel@tonic-gate 			gcursor = strend(genbuf);
4190Sstevel@tonic-gate 		}
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 		/*
4220Sstevel@tonic-gate 		 * Limit the repetition count based on maximum
4230Sstevel@tonic-gate 		 * possible line length; do output implied
4240Sstevel@tonic-gate 		 * by further count (> 1) and cons up the new line
4250Sstevel@tonic-gate 		 * in linebuf.
4260Sstevel@tonic-gate 		 */
4270Sstevel@tonic-gate 		cnt = vmaxrep(ch, cnt);
4280Sstevel@tonic-gate 		CP(gcursor + 1, cursor);
4290Sstevel@tonic-gate 		do {
4300Sstevel@tonic-gate 			CP(cursor, genbuf);
4310Sstevel@tonic-gate 			if (cnt > 1) {
4320Sstevel@tonic-gate 				int oldhold = hold;
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 				Outchar = vinschar;
4350Sstevel@tonic-gate 				hold |= HOLDQIK;
436*802Scf46844 				viprintf("%s", genbuf);
4370Sstevel@tonic-gate 				hold = oldhold;
4380Sstevel@tonic-gate 				Outchar = vputchar;
4390Sstevel@tonic-gate 			}
4400Sstevel@tonic-gate 			cursor += gcursor - genbuf;
4410Sstevel@tonic-gate 		} while (--cnt > 0);
4420Sstevel@tonic-gate 		endim();
4430Sstevel@tonic-gate 		vUA2 = cursor;
4440Sstevel@tonic-gate 		if (escape != '\n')
4450Sstevel@tonic-gate 			CP(cursor, gcursor + 1);
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 		/*
4480Sstevel@tonic-gate 		 * If doomed characters remain, clobber them,
4490Sstevel@tonic-gate 		 * and reopen the line to get the display exact.
4500Sstevel@tonic-gate 		 */
4510Sstevel@tonic-gate 		if (state != HARDOPEN) {
4520Sstevel@tonic-gate 			DEPTH(vcline) = 0;
4530Sstevel@tonic-gate 			savedoomed = doomed;
4540Sstevel@tonic-gate 			if (doomed > 0) {
455*802Scf46844 				int cind = cindent();
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 				physdc(cind, cind + doomed);
4580Sstevel@tonic-gate 				doomed = 0;
4590Sstevel@tonic-gate 			}
4600Sstevel@tonic-gate 			if(MB_CUR_MAX > 1)
4610Sstevel@tonic-gate 				rewrite = _ON;
4620Sstevel@tonic-gate 			i = vreopen(LINE(vcline), lineDOT(), vcline);
4630Sstevel@tonic-gate 			if(MB_CUR_MAX > 1)
4640Sstevel@tonic-gate 				rewrite = _OFF;
4650Sstevel@tonic-gate #ifdef TRACE
4660Sstevel@tonic-gate 			if (trace)
4670Sstevel@tonic-gate 				fprintf(trace, "restoring doomed from %d to %d\n", doomed, savedoomed);
4680Sstevel@tonic-gate #endif
4690Sstevel@tonic-gate 			if (ch == 'R')
4700Sstevel@tonic-gate 				doomed = savedoomed;
4710Sstevel@tonic-gate 		}
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 		/*
4740Sstevel@tonic-gate 		 * All done unless we are continuing on to another line.
4750Sstevel@tonic-gate 		 */
4760Sstevel@tonic-gate 		if (escape != '\n') {
4770Sstevel@tonic-gate 			vshowmode("");
4780Sstevel@tonic-gate 			break;
4790Sstevel@tonic-gate 		}
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 		/*
4820Sstevel@tonic-gate 		 * Set up for the new line.
4830Sstevel@tonic-gate 		 * First save the current line, then construct a new
4840Sstevel@tonic-gate 		 * first image for the continuation line consisting
4850Sstevel@tonic-gate 		 * of any new autoindent plus the pushed ahead text.
4860Sstevel@tonic-gate 		 */
4870Sstevel@tonic-gate 		killU();
4880Sstevel@tonic-gate 		addtext(gobblebl ? " " : "\n");
4890Sstevel@tonic-gate 		vsave();
4900Sstevel@tonic-gate 		cnt = 1;
4910Sstevel@tonic-gate 		if (value(vi_AUTOINDENT)) {
4920Sstevel@tonic-gate 			if (value(vi_LISP))
4930Sstevel@tonic-gate 				indent = lindent(dot + 1);
4940Sstevel@tonic-gate 			else
4950Sstevel@tonic-gate 			     if (!HADUP && vaifirst)
4960Sstevel@tonic-gate 				indent = whitecnt(linebuf);
4970Sstevel@tonic-gate 			vaifirst = 0;
4980Sstevel@tonic-gate 			strcLIN(vpastwh(gcursor + 1));
4990Sstevel@tonic-gate 			gcursor = genindent(indent);
5000Sstevel@tonic-gate 			*gcursor = 0;
5010Sstevel@tonic-gate 			if (gcursor + strlen(linebuf) > &genbuf[LBSIZE - 2])
5020Sstevel@tonic-gate 				gcursor = genbuf;
5030Sstevel@tonic-gate 			CP(gcursor, linebuf);
5040Sstevel@tonic-gate 		} else {
5050Sstevel@tonic-gate 			CP(genbuf, gcursor + 1);
5060Sstevel@tonic-gate 			gcursor = genbuf;
5070Sstevel@tonic-gate 		}
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 		/*
5100Sstevel@tonic-gate 		 * If we started out as a single line operation and are now
5110Sstevel@tonic-gate 		 * turning into a multi-line change, then we had better yank
5120Sstevel@tonic-gate 		 * out dot before it changes so that undo will work
5130Sstevel@tonic-gate 		 * correctly later.
5140Sstevel@tonic-gate 		 */
5150Sstevel@tonic-gate 		if (FIXUNDO && vundkind == VCHNG) {
5160Sstevel@tonic-gate 			vremote(1, yank, 0);
5170Sstevel@tonic-gate 			undap1--;
5180Sstevel@tonic-gate 		}
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 		/*
5210Sstevel@tonic-gate 		 * Now do the append of the new line in the buffer,
5220Sstevel@tonic-gate 		 * and update the display.  If slowopen
5230Sstevel@tonic-gate 		 * we don't do very much.
5240Sstevel@tonic-gate 		 */
5250Sstevel@tonic-gate 		vdoappend(genbuf);
5260Sstevel@tonic-gate 		vundkind = VMANYINS;
5270Sstevel@tonic-gate 		vcline++;
5280Sstevel@tonic-gate 		if (state != VISUAL)
5290Sstevel@tonic-gate 			vshow(dot, NOLINE);
5300Sstevel@tonic-gate 		else {
5310Sstevel@tonic-gate 			i += LINE(vcline - 1);
5320Sstevel@tonic-gate 			vopen(dot, i);
5330Sstevel@tonic-gate 			if (value(vi_SLOWOPEN))
5340Sstevel@tonic-gate 				vscrap();
5350Sstevel@tonic-gate 			else
5360Sstevel@tonic-gate 				vsync1(LINE(vcline));
5370Sstevel@tonic-gate 		}
5380Sstevel@tonic-gate 		switch (ch) {
5390Sstevel@tonic-gate 		case 'r':
5400Sstevel@tonic-gate 			break;
5410Sstevel@tonic-gate 		case 'a':
5420Sstevel@tonic-gate 			if (value(vi_TERSE)) {
5430Sstevel@tonic-gate 				vshowmode(gettext("A"));
5440Sstevel@tonic-gate 			} else {
5450Sstevel@tonic-gate 				vshowmode(gettext("APPEND MODE"));
5460Sstevel@tonic-gate 			}
5470Sstevel@tonic-gate 			break;
5480Sstevel@tonic-gate 		case 's':
5490Sstevel@tonic-gate 			if (value(vi_TERSE)) {
5500Sstevel@tonic-gate 				vshowmode(gettext("S"));
5510Sstevel@tonic-gate 			} else {
5520Sstevel@tonic-gate 				vshowmode(gettext("SUBSTITUTE MODE"));
5530Sstevel@tonic-gate 			}
5540Sstevel@tonic-gate 			break;
5550Sstevel@tonic-gate 		case 'c':
5560Sstevel@tonic-gate 			if (value(vi_TERSE)) {
5570Sstevel@tonic-gate 				vshowmode(gettext("C"));
5580Sstevel@tonic-gate 			} else {
5590Sstevel@tonic-gate 				vshowmode(gettext("CHANGE MODE"));
5600Sstevel@tonic-gate 			}
5610Sstevel@tonic-gate 			break;
5620Sstevel@tonic-gate 		case 'R':
5630Sstevel@tonic-gate 			if (value(vi_TERSE)) {
5640Sstevel@tonic-gate 				vshowmode(gettext("R"));
5650Sstevel@tonic-gate 			} else {
5660Sstevel@tonic-gate 				vshowmode(gettext("REPLACE MODE"));
5670Sstevel@tonic-gate 			}
5680Sstevel@tonic-gate 			break;
5690Sstevel@tonic-gate 		case 'i':
5700Sstevel@tonic-gate 			if (value(vi_TERSE)) {
5710Sstevel@tonic-gate 				vshowmode(gettext("I"));
5720Sstevel@tonic-gate 			} else {
5730Sstevel@tonic-gate 				vshowmode(gettext("INSERT MODE"));
5740Sstevel@tonic-gate 			}
5750Sstevel@tonic-gate 			break;
5760Sstevel@tonic-gate 		case 'o':
5770Sstevel@tonic-gate 			if (value(vi_TERSE)) {
5780Sstevel@tonic-gate 				vshowmode(gettext("O"));
5790Sstevel@tonic-gate 			} else {
5800Sstevel@tonic-gate 				vshowmode(gettext("OPEN MODE"));
5810Sstevel@tonic-gate 			}
5820Sstevel@tonic-gate 			break;
5830Sstevel@tonic-gate 		default:
5840Sstevel@tonic-gate 			if (value(vi_TERSE)) {
5850Sstevel@tonic-gate 				vshowmode(gettext("I"));
5860Sstevel@tonic-gate 			} else {
5870Sstevel@tonic-gate 				vshowmode(gettext("INPUT MODE"));
5880Sstevel@tonic-gate 			}
5890Sstevel@tonic-gate 		}
5900Sstevel@tonic-gate 		strcLIN(gcursor);
5910Sstevel@tonic-gate 		*gcursor = 0;
5920Sstevel@tonic-gate 		cursor = linebuf;
5930Sstevel@tonic-gate 		vgotoCL(nqcolumn(cursor - 1, genbuf));
5940Sstevel@tonic-gate 	}
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 	/*
5970Sstevel@tonic-gate 	 * All done with insertion, position the cursor
5980Sstevel@tonic-gate 	 * and sync the screen.
5990Sstevel@tonic-gate 	 */
6000Sstevel@tonic-gate 	hold = oldhold;
6010Sstevel@tonic-gate 	if (cursor > linebuf)
6020Sstevel@tonic-gate 		cursor = lastchr(linebuf, cursor);
6030Sstevel@tonic-gate 	if (state != HARDOPEN)
6040Sstevel@tonic-gate 		vsyncCL();
6050Sstevel@tonic-gate 	else if (cursor > linebuf)
6060Sstevel@tonic-gate 		back1();
6070Sstevel@tonic-gate 	doomed = 0;
6080Sstevel@tonic-gate 	wcursor = cursor;
609*802Scf46844 	(void) vmove();
6100Sstevel@tonic-gate }
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate /*
6130Sstevel@tonic-gate  * Subroutine for vgetline to back up a single character position,
6140Sstevel@tonic-gate  * backwards around end of lines (vgoto can't hack columns which are
6150Sstevel@tonic-gate  * less than 0 in general).
6160Sstevel@tonic-gate  */
617*802Scf46844 void
618*802Scf46844 back1(void)
6190Sstevel@tonic-gate {
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	vgoto(destline - 1, WCOLS + destcol - 1);
6220Sstevel@tonic-gate }
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate /*
6250Sstevel@tonic-gate  * Get a line into genbuf after gcursor.
6260Sstevel@tonic-gate  * Cnt limits the number of input characters
6270Sstevel@tonic-gate  * accepted and is used for handling the replace
6280Sstevel@tonic-gate  * single character command.  Aescaped is the location
6290Sstevel@tonic-gate  * where we stick a termination indicator (whether we
6300Sstevel@tonic-gate  * ended with an ESCAPE or a newline/return.
6310Sstevel@tonic-gate  *
6320Sstevel@tonic-gate  * We do erase-kill type processing here and also
6330Sstevel@tonic-gate  * are careful about the way we do this so that it is
6340Sstevel@tonic-gate  * repeatable.  (I.e. so that your kill doesn't happen,
6350Sstevel@tonic-gate  * when you repeat an insert if it was escaped with \ the
6360Sstevel@tonic-gate  * first time you did it.  commch is the command character
6370Sstevel@tonic-gate  * involved, including the prompt for readline.
6380Sstevel@tonic-gate  */
6390Sstevel@tonic-gate unsigned char *
6400Sstevel@tonic-gate vgetline(cnt, gcursor, aescaped, commch)
6410Sstevel@tonic-gate 	int cnt;
642*802Scf46844 	unsigned char *gcursor;
6430Sstevel@tonic-gate 	bool *aescaped;
6440Sstevel@tonic-gate 	unsigned char commch;
6450Sstevel@tonic-gate {
646*802Scf46844 	int c, ch;
647*802Scf46844 	unsigned char *cp, *pcp;
6480Sstevel@tonic-gate 	int x, y, iwhite, backsl=0;
6490Sstevel@tonic-gate 	unsigned char *iglobp;
6500Sstevel@tonic-gate 	int (*OO)() = Outchar;
6510Sstevel@tonic-gate 	int length, width;
6520Sstevel@tonic-gate 	unsigned char multic[MULTI_BYTE_MAX+1];
6530Sstevel@tonic-gate 	wchar_t wchar = 0;
6540Sstevel@tonic-gate 	unsigned char	*p;
6550Sstevel@tonic-gate 	int	len;
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 	/*
6590Sstevel@tonic-gate 	 * Clear the output state and counters
6600Sstevel@tonic-gate 	 * for autoindent backwards motion (counts of ^D, etc.)
6610Sstevel@tonic-gate 	 * Remember how much white space at beginning of line so
6620Sstevel@tonic-gate 	 * as not to allow backspace over autoindent.
6630Sstevel@tonic-gate 	 */
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 	*aescaped = 0;
6660Sstevel@tonic-gate 	ogcursor = gcursor;
6670Sstevel@tonic-gate 	flusho();
6680Sstevel@tonic-gate 	CDCNT = 0;
6690Sstevel@tonic-gate 	HADUP = 0;
6700Sstevel@tonic-gate 	HADZERO = 0;
6710Sstevel@tonic-gate 	gobbled = 0;
6720Sstevel@tonic-gate 	iwhite = whitecnt(genbuf);
6730Sstevel@tonic-gate 	iglobp = vglobp;
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	/*
6760Sstevel@tonic-gate 	 * Clear abbreviation recursive-use count
6770Sstevel@tonic-gate 	 */
6780Sstevel@tonic-gate 	abbrepcnt = 0;
6790Sstevel@tonic-gate 	/*
6800Sstevel@tonic-gate 	 * Carefully avoid using vinschar in the echo area.
6810Sstevel@tonic-gate 	 */
6820Sstevel@tonic-gate 	if (splitw)
6830Sstevel@tonic-gate 		Outchar = vputchar;
6840Sstevel@tonic-gate 	else {
6850Sstevel@tonic-gate 		Outchar = vinschar;
6860Sstevel@tonic-gate 		vprepins();
6870Sstevel@tonic-gate 	}
6880Sstevel@tonic-gate 	for (;;) {
6890Sstevel@tonic-gate 		length = 0;
6900Sstevel@tonic-gate 		backsl = 0;
6910Sstevel@tonic-gate 		if (gobblebl)
6920Sstevel@tonic-gate 			gobblebl--;
6930Sstevel@tonic-gate 		if (cnt != 0) {
6940Sstevel@tonic-gate 			cnt--;
6950Sstevel@tonic-gate 			if (cnt == 0)
6960Sstevel@tonic-gate 				goto vadone;
6970Sstevel@tonic-gate 		}
6980Sstevel@tonic-gate 		c = getkey();
6990Sstevel@tonic-gate 		if (c != ATTN)
7000Sstevel@tonic-gate 			c &= 0377;
7010Sstevel@tonic-gate 		ch = c;
7020Sstevel@tonic-gate 		maphopcnt = 0;
7030Sstevel@tonic-gate 		if (vglobp == 0 && Peekkey == 0 && commch != 'r')
7040Sstevel@tonic-gate 			while ((ch = map(c, immacs, commch)) != c) {
7050Sstevel@tonic-gate 				c = ch;
7060Sstevel@tonic-gate 				if (!value(vi_REMAP))
7070Sstevel@tonic-gate 					break;
7080Sstevel@tonic-gate 				if (++maphopcnt > 256)
7090Sstevel@tonic-gate 					error(gettext("Infinite macro loop"));
7100Sstevel@tonic-gate 			}
7110Sstevel@tonic-gate 		if (!iglobp) {
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 			/*
7140Sstevel@tonic-gate 			 * Erase-kill type processing.
7150Sstevel@tonic-gate 			 * Only happens if we were not reading
7160Sstevel@tonic-gate 			 * from untyped input when we started.
7170Sstevel@tonic-gate 			 * Map users erase to ^H, kill to -1 for switch.
7180Sstevel@tonic-gate 			 */
7190Sstevel@tonic-gate 			if (c == tty.c_cc[VERASE])
7200Sstevel@tonic-gate 				c = CTRL('h');
7210Sstevel@tonic-gate 			else if (c == tty.c_cc[VKILL])
7220Sstevel@tonic-gate 				c = -1;
7230Sstevel@tonic-gate 			switch (c) {
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 			/*
7260Sstevel@tonic-gate 			 * ^?		Interrupt drops you back to visual
7270Sstevel@tonic-gate 			 *		command mode with an unread interrupt
7280Sstevel@tonic-gate 			 *		still in the input buffer.
7290Sstevel@tonic-gate 			 *
7300Sstevel@tonic-gate 			 * ^\		Quit does the same as interrupt.
7310Sstevel@tonic-gate 			 *		If you are a ex command rather than
7320Sstevel@tonic-gate 			 *		a vi command this will drop you
7330Sstevel@tonic-gate 			 *		back to command mode for sure.
7340Sstevel@tonic-gate 			 */
7350Sstevel@tonic-gate 			case ATTN:
7360Sstevel@tonic-gate 			case QUIT:
7370Sstevel@tonic-gate 				ungetkey(c);
7380Sstevel@tonic-gate 				goto vadone;
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 			/*
7410Sstevel@tonic-gate 			 * ^H		Backs up a character in the input.
7420Sstevel@tonic-gate 			 *
7430Sstevel@tonic-gate 			 * BUG:		Can't back around line boundaries.
7440Sstevel@tonic-gate 			 *		This is hard because stuff has
7450Sstevel@tonic-gate 			 *		already been saved for repeat.
7460Sstevel@tonic-gate 			 */
7470Sstevel@tonic-gate 			case CTRL('h'):
7480Sstevel@tonic-gate bakchar:
7490Sstevel@tonic-gate 				cp = lastchr(ogcursor, gcursor);
7500Sstevel@tonic-gate 				if (cp < ogcursor) {
7510Sstevel@tonic-gate 					if (splitw) {
7520Sstevel@tonic-gate 						/*
7530Sstevel@tonic-gate 						 * Backspacing over readecho
7540Sstevel@tonic-gate 						 * prompt. Pretend delete but
7550Sstevel@tonic-gate 						 * don't beep.
7560Sstevel@tonic-gate 						 */
7570Sstevel@tonic-gate 						ungetkey(c);
7580Sstevel@tonic-gate 						goto vadone;
7590Sstevel@tonic-gate 					}
760*802Scf46844 					(void) beep();
7610Sstevel@tonic-gate 					continue;
7620Sstevel@tonic-gate 				}
7630Sstevel@tonic-gate 				goto vbackup;
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 			/*
7660Sstevel@tonic-gate 			 * ^W		Back up a white/non-white word.
7670Sstevel@tonic-gate 			 */
7680Sstevel@tonic-gate 			case CTRL('w'):
7690Sstevel@tonic-gate 				wdkind = 1;
7700Sstevel@tonic-gate 				for (cp = gcursor; cp > ogcursor && isspace(cp[-1]); cp--)
7710Sstevel@tonic-gate 					continue;
7720Sstevel@tonic-gate 				pcp = lastchr(ogcursor, cp);
7730Sstevel@tonic-gate 				for (c = wordch(pcp);
7740Sstevel@tonic-gate 				    cp > ogcursor && wordof(c, pcp); cp = pcp, pcp = lastchr(ogcursor, cp))
7750Sstevel@tonic-gate 					continue;
7760Sstevel@tonic-gate 				goto vbackup;
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 			/*
7790Sstevel@tonic-gate 			 * users kill	Kill input on this line, back to
7800Sstevel@tonic-gate 			 *		the autoindent.
7810Sstevel@tonic-gate 			 */
7820Sstevel@tonic-gate 			case -1:
7830Sstevel@tonic-gate 				cp = ogcursor;
7840Sstevel@tonic-gate vbackup:
7850Sstevel@tonic-gate 				if (cp == gcursor) {
786*802Scf46844 					(void) beep();
7870Sstevel@tonic-gate 					continue;
7880Sstevel@tonic-gate 				}
7890Sstevel@tonic-gate 				endim();
7900Sstevel@tonic-gate 				*cp = 0;
7910Sstevel@tonic-gate 				c = cindent();
7920Sstevel@tonic-gate 				vgotoCL(nqcolumn(lastchr(linebuf, cursor), genbuf));
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 				if (doomed >= 0)
7950Sstevel@tonic-gate 					doomed += c - cindent();
7960Sstevel@tonic-gate 				gcursor = cp;
7970Sstevel@tonic-gate 				continue;
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 			/*
8000Sstevel@tonic-gate 			 * \		Followed by erase or kill
8010Sstevel@tonic-gate 			 *		maps to just the erase or kill.
8020Sstevel@tonic-gate 			 */
8030Sstevel@tonic-gate 			case '\\':
8040Sstevel@tonic-gate 				x = destcol, y = destline;
8050Sstevel@tonic-gate 				putchar('\\');
8060Sstevel@tonic-gate 				vcsync();
8070Sstevel@tonic-gate 				c = getkey();
8080Sstevel@tonic-gate 				if (c == tty.c_cc[VERASE]
8090Sstevel@tonic-gate 				    || c == tty.c_cc[VKILL])
8100Sstevel@tonic-gate 				{
8110Sstevel@tonic-gate 					vgoto(y, x);
8120Sstevel@tonic-gate 					if (doomed >= 0)
8130Sstevel@tonic-gate 						doomed++;
8140Sstevel@tonic-gate 					multic[0] = wchar = c;
8150Sstevel@tonic-gate 					length = 1;
8160Sstevel@tonic-gate 					goto def;
8170Sstevel@tonic-gate 				}
8180Sstevel@tonic-gate 				ungetkey(c), c = '\\';
8190Sstevel@tonic-gate 				backsl = 1;
8200Sstevel@tonic-gate 				break;
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate 			/*
8230Sstevel@tonic-gate 			 * ^Q		Super quote following character
8240Sstevel@tonic-gate 			 *		Only ^@ is verboten (trapped at
8250Sstevel@tonic-gate 			 *		a lower level) and \n forces a line
8260Sstevel@tonic-gate 			 *		split so doesn't really go in.
8270Sstevel@tonic-gate 			 *
8280Sstevel@tonic-gate 			 * ^V		Synonym for ^Q
8290Sstevel@tonic-gate 			 */
8300Sstevel@tonic-gate 			case CTRL('q'):
8310Sstevel@tonic-gate 			case CTRL('v'):
8320Sstevel@tonic-gate 				x = destcol, y = destline;
8330Sstevel@tonic-gate 				putchar('^');
8340Sstevel@tonic-gate 				vgoto(y, x);
8350Sstevel@tonic-gate 				c = getkey();
8360Sstevel@tonic-gate #ifdef USG
8370Sstevel@tonic-gate 				if (c == ATTN)
8380Sstevel@tonic-gate 					c = tty.c_cc[VINTR];
8390Sstevel@tonic-gate #endif
8400Sstevel@tonic-gate 				if (c != NL) {
8410Sstevel@tonic-gate 					if (doomed >= 0)
8420Sstevel@tonic-gate 						doomed++;
8430Sstevel@tonic-gate 					multic[0] = wchar = c;
8440Sstevel@tonic-gate 					length = 1;
8450Sstevel@tonic-gate 					goto def;
8460Sstevel@tonic-gate 				}
8470Sstevel@tonic-gate 				break;
8480Sstevel@tonic-gate 			}
8490Sstevel@tonic-gate 		}
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 		/*
8520Sstevel@tonic-gate 		 * If we get a blank not in the echo area
8530Sstevel@tonic-gate 		 * consider splitting the window in the wrapmargin.
8540Sstevel@tonic-gate 		 */
8550Sstevel@tonic-gate 		if(!backsl) {
8560Sstevel@tonic-gate 			ungetkey(c);
8570Sstevel@tonic-gate 			if((length = _mbftowc((char *)multic, &wchar, getkey, &Peekkey)) <= 0) {
858*802Scf46844 				(void) beep();
8590Sstevel@tonic-gate 				continue;
8600Sstevel@tonic-gate 			}
8610Sstevel@tonic-gate 		} else {
8620Sstevel@tonic-gate 			length = 1;
8630Sstevel@tonic-gate 			multic[0] = '\\';
8640Sstevel@tonic-gate 		}
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 		if (c != NL && !splitw) {
8670Sstevel@tonic-gate 			if (c == ' ' && gobblebl) {
8680Sstevel@tonic-gate 				gobbled = 1;
8690Sstevel@tonic-gate 				continue;
8700Sstevel@tonic-gate 			}
8710Sstevel@tonic-gate 			if ((width = wcwidth(wchar)) <= 0)
8720Sstevel@tonic-gate 				width = (wchar <= 0177 ? 1 : 4);
8730Sstevel@tonic-gate 			if (value(vi_WRAPMARGIN) &&
8740Sstevel@tonic-gate 				(outcol + width - 1 >= OCOLUMNS - value(vi_WRAPMARGIN) ||
8750Sstevel@tonic-gate 				 backsl && outcol==0) &&
8760Sstevel@tonic-gate 				commch != 'r') {
8770Sstevel@tonic-gate 				/*
8780Sstevel@tonic-gate 				 * At end of word and hit wrapmargin.
8790Sstevel@tonic-gate 				 * Move the word to next line and keep going.
8800Sstevel@tonic-gate 				 */
8810Sstevel@tonic-gate 				unsigned char *wp;
8820Sstevel@tonic-gate 				int bytelength;
8830Sstevel@tonic-gate #ifndef PRESUNEUC
8840Sstevel@tonic-gate 				unsigned char *tgcursor;
8850Sstevel@tonic-gate 				wchar_t wc1, wc2;
8860Sstevel@tonic-gate 				tgcursor = gcursor;
8870Sstevel@tonic-gate #endif /* PRESUNEUC */
8880Sstevel@tonic-gate 				wdkind = 1;
8890Sstevel@tonic-gate 				strncpy(gcursor, multic, length);
8900Sstevel@tonic-gate 				gcursor += length;
8910Sstevel@tonic-gate 				if (backsl) {
8920Sstevel@tonic-gate #ifdef PRESUNEUC
8930Sstevel@tonic-gate 					if((length = mbftowc((char *)multic, &wchar, getkey, &Peekkey)) <= 0) {
8940Sstevel@tonic-gate #else
8950Sstevel@tonic-gate 					if((length = _mbftowc((char *)multic, &wchar, getkey, &Peekkey)) <= 0) {
8960Sstevel@tonic-gate #endif /* PRESUNEUC */
897*802Scf46844 						(void) beep();
8980Sstevel@tonic-gate 						continue;
8990Sstevel@tonic-gate 					}
9000Sstevel@tonic-gate 					strncpy(gcursor, multic, length);
9010Sstevel@tonic-gate 					gcursor += length;
9020Sstevel@tonic-gate 				}
9030Sstevel@tonic-gate 				*gcursor = 0;
9040Sstevel@tonic-gate 				/*
9050Sstevel@tonic-gate 				 * Find end of previous word if we are past it.
9060Sstevel@tonic-gate 				 */
9070Sstevel@tonic-gate 				for (cp=gcursor; cp>ogcursor && isspace(cp[-1]); cp--)
9080Sstevel@tonic-gate 					;
9090Sstevel@tonic-gate #ifdef PRESUNEUC
9100Sstevel@tonic-gate 				/* find screen width of previous word */
9110Sstevel@tonic-gate 				width = 0;
9120Sstevel@tonic-gate 				for(wp = cp; *wp; )
9130Sstevel@tonic-gate #else
9140Sstevel@tonic-gate 				/* count screen width of pending characters */
9150Sstevel@tonic-gate 				width = 0;
9160Sstevel@tonic-gate 				for(wp = tgcursor; wp < cp;)
9170Sstevel@tonic-gate #endif /* PRESUNEUC */
9180Sstevel@tonic-gate 					if((bytelength = mbtowc(&wchar, (char *)wp, MULTI_BYTE_MAX)) < 0) {
9190Sstevel@tonic-gate 						width+=4;
9200Sstevel@tonic-gate 						wp++;
9210Sstevel@tonic-gate 					} else {
9220Sstevel@tonic-gate 						int curwidth = wcwidth(wchar);
9230Sstevel@tonic-gate 						if(curwidth <= 0)
9240Sstevel@tonic-gate 							width += (*wp < 0200 ? 2 : 4);
9250Sstevel@tonic-gate 						else
9260Sstevel@tonic-gate 							width += curwidth;
9270Sstevel@tonic-gate 						wp += bytelength;
9280Sstevel@tonic-gate 					}
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate #ifdef PRESUNEUC
9310Sstevel@tonic-gate 				if (outcol+(backsl?OCOLUMNS:0) - width >= OCOLUMNS - value(vi_WRAPMARGIN)) {
9320Sstevel@tonic-gate #else
9330Sstevel@tonic-gate 				if (outcol+(backsl?OCOLUMNS:0) + width -1 >= OCOLUMNS - value(vi_WRAPMARGIN)) {
9340Sstevel@tonic-gate #endif /* PRESUNEUC */
9350Sstevel@tonic-gate 					/*
9360Sstevel@tonic-gate 					 * Find beginning of previous word.
9370Sstevel@tonic-gate 					 */
9380Sstevel@tonic-gate #ifdef PRESUNEUC
9390Sstevel@tonic-gate 					for (; cp>ogcursor && !isspace(cp[-1]); cp--)
9400Sstevel@tonic-gate 						;
9410Sstevel@tonic-gate #else
9420Sstevel@tonic-gate 					wc1 = wc2 = 0;
9430Sstevel@tonic-gate 					while (cp>ogcursor) {
9440Sstevel@tonic-gate 						if (isspace(cp[-1])) {
9450Sstevel@tonic-gate 							break;
9460Sstevel@tonic-gate 						}
9470Sstevel@tonic-gate 						if (!multibyte) {
9480Sstevel@tonic-gate 							cp--;
9490Sstevel@tonic-gate 							continue;
9500Sstevel@tonic-gate 						}
9510Sstevel@tonic-gate 						wp = (unsigned char *)(cp -
9520Sstevel@tonic-gate 							MB_CUR_MAX);
9530Sstevel@tonic-gate 						if (wp < ogcursor)
9540Sstevel@tonic-gate 							wp = ogcursor;
9550Sstevel@tonic-gate 						while (cp > wp) {
9560Sstevel@tonic-gate /* 7tabs */if (wc2) {
9570Sstevel@tonic-gate /* 7tabs */	if ((bytelength = mbtowc(&wc1, (char *)wp, cp-wp)) != cp-wp) {
9580Sstevel@tonic-gate /* 7tabs */		wp++;
9590Sstevel@tonic-gate /* 7tabs */		wc1 = 0;
9600Sstevel@tonic-gate /* 7tabs */		continue;
9610Sstevel@tonic-gate /* 7tabs */	}
9620Sstevel@tonic-gate /* 7tabs */} else {
9630Sstevel@tonic-gate /* 7tabs */	if ((bytelength = mbtowc(&wc2, (char *)wp, cp-wp)) != cp-wp) {
9640Sstevel@tonic-gate /* 7tabs */		wp++;
9650Sstevel@tonic-gate /* 7tabs */		wc2 = 0;
9660Sstevel@tonic-gate /* 7tabs */		continue;
9670Sstevel@tonic-gate /* 7tabs */	}
9680Sstevel@tonic-gate /* 7tabs */}
9690Sstevel@tonic-gate /* 7tabs */if (wc1) {
9700Sstevel@tonic-gate /* 7tabs */	if (wdbdg && (!iswascii(wc1) || !iswascii(wc2))) {
9710Sstevel@tonic-gate /* 7tabs */		if ((*wdbdg)(wc1, wc2, 2) < 5) {
9720Sstevel@tonic-gate /* 7tabs */			goto ws;
9730Sstevel@tonic-gate /* 7tabs */		}
9740Sstevel@tonic-gate /* 7tabs */	}
9750Sstevel@tonic-gate /* 7tabs */	wc2 = wc1;
9760Sstevel@tonic-gate /* 7tabs */	wc1 = 0;
9770Sstevel@tonic-gate /* 7tabs */	cp -= bytelength - 1;
9780Sstevel@tonic-gate /* 7tabs */	break;
9790Sstevel@tonic-gate /* 7tabs */} else {
9800Sstevel@tonic-gate /* 7tabs */	cp -= bytelength - 1;
9810Sstevel@tonic-gate /* 7tabs */	break;
9820Sstevel@tonic-gate /* 7tabs */}
9830Sstevel@tonic-gate 						}
9840Sstevel@tonic-gate 						cp--;
9850Sstevel@tonic-gate 					}
9860Sstevel@tonic-gate ws:
9870Sstevel@tonic-gate #endif /* PRESUNEUC */
9880Sstevel@tonic-gate 					if (cp <= ogcursor) {
9890Sstevel@tonic-gate 						/*
9900Sstevel@tonic-gate 						 * There is a single word that
9910Sstevel@tonic-gate 						 * is too long to fit.  Just
9920Sstevel@tonic-gate 						 * let it pass, but beep for
9930Sstevel@tonic-gate 						 * each new letter to warn
9940Sstevel@tonic-gate 						 * the luser.
9950Sstevel@tonic-gate 						 */
9960Sstevel@tonic-gate 						gcursor -= length;
9970Sstevel@tonic-gate 						c = *gcursor;
9980Sstevel@tonic-gate 						*gcursor = 0;
999*802Scf46844 						(void) beep();
10000Sstevel@tonic-gate 						goto dontbreak;
10010Sstevel@tonic-gate 					}
10020Sstevel@tonic-gate 					/*
10030Sstevel@tonic-gate 					 * Save it for next line.
10040Sstevel@tonic-gate 					 */
10050Sstevel@tonic-gate 					macpush(cp, 0);
10060Sstevel@tonic-gate #ifdef PRESUNEUC
10070Sstevel@tonic-gate 					cp--;
10080Sstevel@tonic-gate #endif /* PRESUNEUC */
10090Sstevel@tonic-gate 				}
10100Sstevel@tonic-gate 				macpush("\n", 0);
10110Sstevel@tonic-gate 				/*
10120Sstevel@tonic-gate 				 * Erase white space before the word.
10130Sstevel@tonic-gate 				 */
10140Sstevel@tonic-gate 				while (cp > ogcursor && isspace(cp[-1]))
10150Sstevel@tonic-gate 					cp--;	/* skip blank */
10160Sstevel@tonic-gate 				gobblebl = 3;
10170Sstevel@tonic-gate 				goto vbackup;
10180Sstevel@tonic-gate 			}
10190Sstevel@tonic-gate 		dontbreak:;
10200Sstevel@tonic-gate 		}
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 		/*
10230Sstevel@tonic-gate 		 * Word abbreviation mode.
10240Sstevel@tonic-gate 		 */
10250Sstevel@tonic-gate 		if (anyabbrs && gcursor > ogcursor && !wordch(multic) && wordch(lastchr(ogcursor, gcursor))) {
10260Sstevel@tonic-gate 				int wdtype, abno;
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 				multic[length] = 0;
10290Sstevel@tonic-gate 				wdkind = 1;
10300Sstevel@tonic-gate 				cp = lastchr(ogcursor, gcursor);
10310Sstevel@tonic-gate 				pcp = lastchr(ogcursor, cp);
10320Sstevel@tonic-gate 				for (wdtype = wordch(pcp);
10330Sstevel@tonic-gate 				    cp > ogcursor && wordof(wdtype, pcp); cp = pcp, pcp = lastchr(ogcursor, pcp))
10340Sstevel@tonic-gate 					;
10350Sstevel@tonic-gate 				*gcursor = 0;
10360Sstevel@tonic-gate 				for (abno=0; abbrevs[abno].mapto; abno++) {
10370Sstevel@tonic-gate 					if (eq(cp, abbrevs[abno].cap)) {
10380Sstevel@tonic-gate 						if(abbrepcnt == 0) {
10390Sstevel@tonic-gate 							if(reccnt(abbrevs[abno].cap, abbrevs[abno].mapto))
10400Sstevel@tonic-gate 								abbrepcnt = 1;
10410Sstevel@tonic-gate 							macpush(multic, 0);
10420Sstevel@tonic-gate 							macpush(abbrevs[abno].mapto);
10430Sstevel@tonic-gate 							goto vbackup;
10440Sstevel@tonic-gate 						} else
10450Sstevel@tonic-gate 							abbrepcnt = 0;
10460Sstevel@tonic-gate 					}
10470Sstevel@tonic-gate 				}
10480Sstevel@tonic-gate 		}
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 		switch (c) {
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate 		/*
10530Sstevel@tonic-gate 		 * ^M		Except in repeat maps to \n.
10540Sstevel@tonic-gate 		 */
10550Sstevel@tonic-gate 		case CR:
10560Sstevel@tonic-gate 			if (vglobp) {
10570Sstevel@tonic-gate 				multic[0] = wchar = c;
10580Sstevel@tonic-gate 				length = 1;
10590Sstevel@tonic-gate 				goto def;
10600Sstevel@tonic-gate 			}
10610Sstevel@tonic-gate 			c = '\n';
10620Sstevel@tonic-gate 			/* presto chango ... */
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 		/*
10650Sstevel@tonic-gate 		 * \n		Start new line.
10660Sstevel@tonic-gate 		 */
10670Sstevel@tonic-gate 		case NL:
10680Sstevel@tonic-gate 			*aescaped = c;
10690Sstevel@tonic-gate 			goto vadone;
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 		/*
10720Sstevel@tonic-gate 		 * escape	End insert unless repeat and more to repeat.
10730Sstevel@tonic-gate 		 */
10740Sstevel@tonic-gate 		case ESCAPE:
10750Sstevel@tonic-gate 			if (lastvgk) {
10760Sstevel@tonic-gate 				multic[0] = wchar = c;
10770Sstevel@tonic-gate 				length = 1;
10780Sstevel@tonic-gate 				goto def;
10790Sstevel@tonic-gate 			}
10800Sstevel@tonic-gate 			goto vadone;
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 		/*
10830Sstevel@tonic-gate 		 * ^D		Backtab.
10840Sstevel@tonic-gate 		 * ^T		Software forward tab.
10850Sstevel@tonic-gate 		 *
10860Sstevel@tonic-gate 		 *		Unless in repeat where this means these
10870Sstevel@tonic-gate 		 *		were superquoted in.
10880Sstevel@tonic-gate 		 */
10890Sstevel@tonic-gate 		case CTRL('t'):
10900Sstevel@tonic-gate 			if (vglobp) {
10910Sstevel@tonic-gate 				multic[0] = wchar = c;
10920Sstevel@tonic-gate 				length = 1;
10930Sstevel@tonic-gate 				goto def;
10940Sstevel@tonic-gate 			}
10950Sstevel@tonic-gate 			/* fall into ... */
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 			*gcursor = 0;
10980Sstevel@tonic-gate 			cp = vpastwh(genbuf);
10990Sstevel@tonic-gate 			c = whitecnt(genbuf);
11000Sstevel@tonic-gate 			if (ch == CTRL('t')) {
11010Sstevel@tonic-gate 				/*
11020Sstevel@tonic-gate 				 * ^t just generates new indent replacing
11030Sstevel@tonic-gate 				 * current white space rounded up to soft
11040Sstevel@tonic-gate 				 * tab stop increment.
11050Sstevel@tonic-gate 				 */
11060Sstevel@tonic-gate 				if (cp != gcursor)
11070Sstevel@tonic-gate 					/*
11080Sstevel@tonic-gate 					 * BUG:		Don't hack ^T except
11090Sstevel@tonic-gate 					 *		right after initial
11100Sstevel@tonic-gate 					 *		white space.
11110Sstevel@tonic-gate 					 */
11120Sstevel@tonic-gate 					continue;
11130Sstevel@tonic-gate 				cp = genindent(iwhite = backtab(c + value(vi_SHIFTWIDTH) + 1));
11140Sstevel@tonic-gate 				ogcursor = cp;
11150Sstevel@tonic-gate 				goto vbackup;
11160Sstevel@tonic-gate 			}
11170Sstevel@tonic-gate 			/*
11180Sstevel@tonic-gate 			 * ^D works only if we are at the (end of) the
11190Sstevel@tonic-gate 			 * generated autoindent.  We count the ^D for repeat
11200Sstevel@tonic-gate 			 * purposes.
11210Sstevel@tonic-gate 			 */
11220Sstevel@tonic-gate 		case CTRL('d'):
11230Sstevel@tonic-gate 			/* check if ^d was superquoted in */
11240Sstevel@tonic-gate 			if(vglobp && inscdcnt <= 0) {
11250Sstevel@tonic-gate 				multic[0] = wchar = c;
11260Sstevel@tonic-gate 				length = 1;
11270Sstevel@tonic-gate 				goto def;
11280Sstevel@tonic-gate 			}
11290Sstevel@tonic-gate 			if(vglobp)
11300Sstevel@tonic-gate 				inscdcnt--;
11310Sstevel@tonic-gate 			*gcursor = 0;
11320Sstevel@tonic-gate 			cp = vpastwh(genbuf);
11330Sstevel@tonic-gate 			c = whitecnt(genbuf);
11340Sstevel@tonic-gate 			if (c == iwhite && c != 0)
11350Sstevel@tonic-gate 				if (cp == gcursor) {
11360Sstevel@tonic-gate 					iwhite = backtab(c);
11370Sstevel@tonic-gate 					CDCNT++;
11380Sstevel@tonic-gate 					ogcursor = cp = genindent(iwhite);
11390Sstevel@tonic-gate 					goto vbackup;
11400Sstevel@tonic-gate 				} else if (&cp[1] == gcursor &&
11410Sstevel@tonic-gate 				    (*cp == '^' || *cp == '0')) {
11420Sstevel@tonic-gate 					/*
11430Sstevel@tonic-gate 					 * ^^D moves to margin, then back
11440Sstevel@tonic-gate 					 * to current indent on next line.
11450Sstevel@tonic-gate 					 *
11460Sstevel@tonic-gate 					 * 0^D moves to margin and then
11470Sstevel@tonic-gate 					 * stays there.
11480Sstevel@tonic-gate 					 */
11490Sstevel@tonic-gate 					HADZERO = *cp == '0';
11500Sstevel@tonic-gate 					ogcursor = cp = genbuf;
11510Sstevel@tonic-gate 					HADUP = 1 - HADZERO;
11520Sstevel@tonic-gate 					CDCNT = 1;
11530Sstevel@tonic-gate 					endim();
11540Sstevel@tonic-gate 					back1();
1155*802Scf46844 					(void) vputchar(' ');
11560Sstevel@tonic-gate 					goto vbackup;
11570Sstevel@tonic-gate 				}
11580Sstevel@tonic-gate 
11590Sstevel@tonic-gate 			if (vglobp && vglobp - iglobp >= 2) {
11600Sstevel@tonic-gate 				if ((p = vglobp - MB_CUR_MAX) < iglobp)
11610Sstevel@tonic-gate 					p = iglobp;
11620Sstevel@tonic-gate 				for ( ; p < &vglobp[-2]; p += len) {
11630Sstevel@tonic-gate 					if ((len = mblen((char *)p, MB_CUR_MAX)) <= 0)
11640Sstevel@tonic-gate 						len = 1;
11650Sstevel@tonic-gate 				}
11660Sstevel@tonic-gate 				if ((p == &vglobp[-2]) &&
11670Sstevel@tonic-gate 			            (*p == '^' || *p == '0') &&
11680Sstevel@tonic-gate 			            gcursor == ogcursor + 1)
11690Sstevel@tonic-gate 					goto bakchar;
11700Sstevel@tonic-gate 			}
11710Sstevel@tonic-gate 			continue;
11720Sstevel@tonic-gate 
11730Sstevel@tonic-gate 		default:
11740Sstevel@tonic-gate 			/*
11750Sstevel@tonic-gate 			 * Possibly discard control inputs.
11760Sstevel@tonic-gate 			 */
11770Sstevel@tonic-gate 			if (!vglobp && junk(c)) {
1178*802Scf46844 				(void) beep();
11790Sstevel@tonic-gate 				continue;
11800Sstevel@tonic-gate 			}
11810Sstevel@tonic-gate def:
11820Sstevel@tonic-gate 			if (!backsl) {
11830Sstevel@tonic-gate 				putchar(wchar);
11840Sstevel@tonic-gate 				flush();
11850Sstevel@tonic-gate 			}
11860Sstevel@tonic-gate 			if (gcursor + length - 1 > &genbuf[LBSIZE - 2])
11870Sstevel@tonic-gate 				error(gettext("Line too long"));
11880Sstevel@tonic-gate 			(void)strncpy(gcursor, multic, length);
11890Sstevel@tonic-gate 			gcursor += length;
11900Sstevel@tonic-gate 			vcsync();
11910Sstevel@tonic-gate 			if (value(vi_SHOWMATCH) && !iglobp)
11920Sstevel@tonic-gate 				if (c == ')' || c == '}')
11930Sstevel@tonic-gate 					lsmatch(gcursor);
11940Sstevel@tonic-gate 			continue;
11950Sstevel@tonic-gate 		}
11960Sstevel@tonic-gate 	}
11970Sstevel@tonic-gate vadone:
11980Sstevel@tonic-gate 	*gcursor = 0;
11990Sstevel@tonic-gate 	if (Outchar != termchar)
12000Sstevel@tonic-gate 		Outchar = OO;
12010Sstevel@tonic-gate 	endim();
12020Sstevel@tonic-gate 	return (gcursor);
12030Sstevel@tonic-gate }
12040Sstevel@tonic-gate 
12050Sstevel@tonic-gate int	vgetsplit();
12060Sstevel@tonic-gate unsigned char	*vsplitpt;
12070Sstevel@tonic-gate 
12080Sstevel@tonic-gate /*
12090Sstevel@tonic-gate  * Append the line in buffer at lp
12100Sstevel@tonic-gate  * to the buffer after dot.
12110Sstevel@tonic-gate  */
1212*802Scf46844 void
1213*802Scf46844 vdoappend(unsigned char *lp)
12140Sstevel@tonic-gate {
1215*802Scf46844 	int oing = inglobal;
12160Sstevel@tonic-gate 
12170Sstevel@tonic-gate 	vsplitpt = lp;
12180Sstevel@tonic-gate 	inglobal = 1;
12190Sstevel@tonic-gate 	(void)append(vgetsplit, dot);
12200Sstevel@tonic-gate 	inglobal = oing;
12210Sstevel@tonic-gate }
12220Sstevel@tonic-gate 
12230Sstevel@tonic-gate /*
12240Sstevel@tonic-gate  * Subroutine for vdoappend to pass to append.
12250Sstevel@tonic-gate  */
1226*802Scf46844 int
1227*802Scf46844 vgetsplit(void)
12280Sstevel@tonic-gate {
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate 	if (vsplitpt == 0)
12310Sstevel@tonic-gate 		return (EOF);
12320Sstevel@tonic-gate 	strcLIN(vsplitpt);
12330Sstevel@tonic-gate 	vsplitpt = 0;
12340Sstevel@tonic-gate 	return (0);
12350Sstevel@tonic-gate }
12360Sstevel@tonic-gate 
12370Sstevel@tonic-gate /*
12380Sstevel@tonic-gate  * Vmaxrep determines the maximum repetition factor
12390Sstevel@tonic-gate  * allowed that will yield total line length less than
12400Sstevel@tonic-gate  * LBSIZE characters and also does hacks for the R command.
12410Sstevel@tonic-gate  */
1242*802Scf46844 int
1243*802Scf46844 vmaxrep(unsigned char ch, int cnt)
12440Sstevel@tonic-gate {
1245*802Scf46844 	int len;
12460Sstevel@tonic-gate 	unsigned char *cp;
12470Sstevel@tonic-gate 	int repcnt, oldcnt, replen;
12480Sstevel@tonic-gate 	if (cnt > LBSIZE - 2)
12490Sstevel@tonic-gate 		cnt = LBSIZE - 2;
12500Sstevel@tonic-gate 	if (ch == 'R') {
12510Sstevel@tonic-gate 		len = strlen(cursor);
12520Sstevel@tonic-gate 		oldcnt = 0;
12530Sstevel@tonic-gate 		for(cp = cursor; *cp; ) {
12540Sstevel@tonic-gate 			oldcnt++;
12550Sstevel@tonic-gate 			cp = nextchr(cp);
12560Sstevel@tonic-gate 		}
12570Sstevel@tonic-gate 		repcnt = 0;
12580Sstevel@tonic-gate 		for(cp = genbuf; *cp; ) {
12590Sstevel@tonic-gate 			repcnt++;
12600Sstevel@tonic-gate 			cp = nextchr(cp);
12610Sstevel@tonic-gate 		}
12620Sstevel@tonic-gate 		/*
12630Sstevel@tonic-gate 		 * if number of characters in replacement string
12640Sstevel@tonic-gate 		 * (repcnt) is less than number of characters following
12650Sstevel@tonic-gate 		 * cursor (oldcnt), find end of repcnt
12660Sstevel@tonic-gate 		 * characters after cursor
12670Sstevel@tonic-gate 		 */
12680Sstevel@tonic-gate 		if(repcnt < oldcnt) {
12690Sstevel@tonic-gate 			for(cp = cursor; repcnt > 0; repcnt--)
12700Sstevel@tonic-gate 				cp = nextchr(cp);
12710Sstevel@tonic-gate 			len = cp - cursor;
12720Sstevel@tonic-gate 		}
12730Sstevel@tonic-gate 		CP(cursor, cursor + len);
12740Sstevel@tonic-gate 		vUD2 += len;
12750Sstevel@tonic-gate 	}
12760Sstevel@tonic-gate 	len = strlen(linebuf);
12770Sstevel@tonic-gate 	replen = strlen(genbuf);
12780Sstevel@tonic-gate 	if (len + cnt * replen <= LBSIZE - 2)
12790Sstevel@tonic-gate 		return (cnt);
12800Sstevel@tonic-gate 	cnt = (LBSIZE - 2 - len) / replen;
12810Sstevel@tonic-gate 	if (cnt == 0) {
12820Sstevel@tonic-gate 		vsave();
12830Sstevel@tonic-gate 		error(gettext("Line too long"));
12840Sstevel@tonic-gate 	}
12850Sstevel@tonic-gate 	return (cnt);
12860Sstevel@tonic-gate }
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate /*
12890Sstevel@tonic-gate  * Determine how many occurrences of word 'CAP' are in 'MAPTO'.  To be
12900Sstevel@tonic-gate  * considered an occurrence there must be both a nonword-prefix, a
12910Sstevel@tonic-gate  * complete match of 'CAP' within 'MAPTO', and a nonword-suffix.
12920Sstevel@tonic-gate  * Note that the beginning and end of 'MAPTO' are considered to be
12930Sstevel@tonic-gate  * valid nonword delimiters.
12940Sstevel@tonic-gate  */
1295*802Scf46844 int
1296*802Scf46844 reccnt(unsigned char *cap, unsigned char *mapto)
12970Sstevel@tonic-gate {
1298*802Scf46844 	int i, cnt, final;
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate 	cnt = 0;
13010Sstevel@tonic-gate 	final = strlen(mapto) - strlen(cap);
13020Sstevel@tonic-gate 
13030Sstevel@tonic-gate 	for (i=0; i <= final; i++)
13040Sstevel@tonic-gate 	  if ((strncmp(cap, mapto+i, strlen(cap)) == 0)       /* match */
13050Sstevel@tonic-gate 	  && (i == 0     || !wordch(&mapto[i-1]))	      /* prefix ok */
13060Sstevel@tonic-gate 	  && (i == final || !wordch(&mapto[i+strlen(cap)])))  /* suffix ok */
13070Sstevel@tonic-gate 		cnt++;
13080Sstevel@tonic-gate 	return (cnt);
13090Sstevel@tonic-gate }
13100Sstevel@tonic-gate 
1311