xref: /onnv-gate/usr/src/cmd/vi/port/ex_vops2.c (revision 13093:48f2dbca79a2)
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
53806Scf46844  * Common Development and Distribution License (the "License").
63806Scf46844  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*13093SRoger.Faulkner@Oracle.COM 
220Sstevel@tonic-gate /*
23*13093SRoger.Faulkner@Oracle.COM  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
270Sstevel@tonic-gate /*	  All Rights Reserved  	*/
280Sstevel@tonic-gate 
290Sstevel@tonic-gate 
300Sstevel@tonic-gate /* Copyright (c) 1981 Regents of the University of California */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include "ex.h"
330Sstevel@tonic-gate #include "ex_tty.h"
340Sstevel@tonic-gate #include "ex_vis.h"
350Sstevel@tonic-gate #ifndef PRESUNEUC
360Sstevel@tonic-gate #include <wctype.h>
370Sstevel@tonic-gate /* Undef putchar/getchar if they're defined. */
380Sstevel@tonic-gate #ifdef putchar
390Sstevel@tonic-gate #	undef putchar
400Sstevel@tonic-gate #endif
410Sstevel@tonic-gate #ifdef getchar
420Sstevel@tonic-gate #	undef getchar
430Sstevel@tonic-gate #endif
440Sstevel@tonic-gate #endif /* PRESUNEUC */
450Sstevel@tonic-gate 
461406Scf46844 extern size_t strlcpy(char *, const char *, size_t);
471406Scf46844 
480Sstevel@tonic-gate /*
490Sstevel@tonic-gate  * Low level routines for operations sequences,
500Sstevel@tonic-gate  * and mostly, insert mode (and a subroutine
510Sstevel@tonic-gate  * to read an input line, including in the echo area.)
520Sstevel@tonic-gate  */
530Sstevel@tonic-gate extern unsigned char	*vUA1, *vUA2;		/* extern; also in ex_vops.c */
540Sstevel@tonic-gate extern unsigned char	*vUD1, *vUD2;		/* extern; also in ex_vops.c */
550Sstevel@tonic-gate 
563806Scf46844 #ifdef XPG6
573806Scf46844 /* XPG6 assertion 313 & 254 [count]r\n :  Also used in ex_vmain.c */
583806Scf46844 extern int redisplay;
593806Scf46844 #endif
603806Scf46844 
61802Scf46844 int vmaxrep(unsigned char, int);
621406Scf46844 static void imultlinerep(int, line *, int, int);
631406Scf46844 static void omultlinerep(int, line *, int);
643806Scf46844 #ifdef XPG6
653806Scf46844 static void rmultlinerep(int, int);
663806Scf46844 #endif
673806Scf46844 void fixdisplay(void);
68802Scf46844 
690Sstevel@tonic-gate /*
700Sstevel@tonic-gate  * Obleeperate characters in hardcopy
710Sstevel@tonic-gate  * open with \'s.
720Sstevel@tonic-gate  */
73802Scf46844 void
bleep(int i,unsigned char * cp)74802Scf46844 bleep(int i, unsigned char *cp)
750Sstevel@tonic-gate {
760Sstevel@tonic-gate 
770Sstevel@tonic-gate 	i -= lcolumn(nextchr(cp));
780Sstevel@tonic-gate 	do
790Sstevel@tonic-gate 		putchar('\\' | QUOTE);
800Sstevel@tonic-gate 	while (--i >= 0);
810Sstevel@tonic-gate 	rubble = 1;
820Sstevel@tonic-gate }
830Sstevel@tonic-gate 
840Sstevel@tonic-gate /*
850Sstevel@tonic-gate  * Common code for middle part of delete
860Sstevel@tonic-gate  * and change operating on parts of lines.
870Sstevel@tonic-gate  */
88802Scf46844 int
vdcMID(void)89802Scf46844 vdcMID(void)
900Sstevel@tonic-gate {
91802Scf46844 	unsigned char *cp;
920Sstevel@tonic-gate 
930Sstevel@tonic-gate 	squish();
940Sstevel@tonic-gate 	setLAST();
950Sstevel@tonic-gate 	if (FIXUNDO)
960Sstevel@tonic-gate 		vundkind = VCHNG, CP(vutmp, linebuf);
970Sstevel@tonic-gate 	if (wcursor < cursor)
980Sstevel@tonic-gate 		cp = wcursor, wcursor = cursor, cursor = cp;
990Sstevel@tonic-gate 	vUD1 = vUA1 = vUA2 = cursor; vUD2 = wcursor;
1003806Scf46844 	/*
1013806Scf46844 	 * XPG6 assertion 273: Set vmcurs so that undo positions the
1023806Scf46844 	 * cursor column correctly when we've moved off the initial line
1033806Scf46844 	 * that was changed, as with the C, c, and s commands,
1043806Scf46844 	 * when G has moved us off the line, or when a
1053806Scf46844 	 * multi-line change was done.
1063806Scf46844 	 */
1073806Scf46844 	fixundo();
1080Sstevel@tonic-gate 	return (lcolumn(wcursor));
1090Sstevel@tonic-gate }
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate /*
1120Sstevel@tonic-gate  * Take text from linebuf and stick it
1130Sstevel@tonic-gate  * in the VBSIZE buffer BUF.  Used to save
1140Sstevel@tonic-gate  * deleted text of part of line.
1150Sstevel@tonic-gate  */
116802Scf46844 void
takeout(unsigned char * BUF)117802Scf46844 takeout(unsigned char *BUF)
1180Sstevel@tonic-gate {
119802Scf46844 	unsigned char *cp;
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	if (wcursor < linebuf)
1220Sstevel@tonic-gate 		wcursor = linebuf;
1230Sstevel@tonic-gate 	if (cursor == wcursor) {
124802Scf46844 		(void) beep();
1250Sstevel@tonic-gate 		return;
1260Sstevel@tonic-gate 	}
1270Sstevel@tonic-gate 	if (wcursor < cursor) {
1280Sstevel@tonic-gate 		cp = wcursor;
1290Sstevel@tonic-gate 		wcursor = cursor;
1300Sstevel@tonic-gate 		cursor = cp;
1310Sstevel@tonic-gate 	}
1320Sstevel@tonic-gate 	setBUF(BUF);
1330Sstevel@tonic-gate 	if ((unsigned char)BUF[128] == 0200)
134802Scf46844 		(void) beep();
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate /*
1380Sstevel@tonic-gate  * Are we at the end of the printed representation of the
1390Sstevel@tonic-gate  * line?  Used internally in hardcopy open.
1400Sstevel@tonic-gate  */
141802Scf46844 int
ateopr(void)142802Scf46844 ateopr(void)
1430Sstevel@tonic-gate {
144802Scf46844 	wchar_t i, c;
145802Scf46844 	wchar_t *cp = vtube[destline] + destcol;
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	for (i = WCOLS - destcol; i > 0; i--) {
1480Sstevel@tonic-gate 		c = *cp++;
1490Sstevel@tonic-gate 		if (c == 0) {
1500Sstevel@tonic-gate 			/*
1510Sstevel@tonic-gate 			 * Optimization to consider returning early, saving
1520Sstevel@tonic-gate 			 * CPU time.  We have to make a special check that
1530Sstevel@tonic-gate 			 * we aren't missing a mode indicator.
1540Sstevel@tonic-gate 			 */
1550Sstevel@tonic-gate 			if (destline == WECHO && destcol < WCOLS-11 && vtube[WECHO][WCOLS-20])
1560Sstevel@tonic-gate 				return 0;
1570Sstevel@tonic-gate 			return (1);
1580Sstevel@tonic-gate 		}
1590Sstevel@tonic-gate 		if (c != ' ' && (c & QUOTE) == 0)
1600Sstevel@tonic-gate 			return (0);
1610Sstevel@tonic-gate 	}
1620Sstevel@tonic-gate 	return (1);
1630Sstevel@tonic-gate }
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate /*
1660Sstevel@tonic-gate  * Append.
1670Sstevel@tonic-gate  *
1680Sstevel@tonic-gate  * This routine handles the top level append, doing work
1690Sstevel@tonic-gate  * as each new line comes in, and arranging repeatability.
1700Sstevel@tonic-gate  * It also handles append with repeat counts, and calculation
1710Sstevel@tonic-gate  * of autoindents for new lines.
1720Sstevel@tonic-gate  */
1730Sstevel@tonic-gate bool	vaifirst;
1740Sstevel@tonic-gate bool	gobbled;
1750Sstevel@tonic-gate unsigned char	*ogcursor;
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate static int 	INSCDCNT; /* number of ^D's (backtabs) in insertion buffer */
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate static int 	inscdcnt; /*
1800Sstevel@tonic-gate 			   * count of ^D's (backtabs) not seen yet when doing
1810Sstevel@tonic-gate 		 	   * repeat of insertion
1820Sstevel@tonic-gate 			   */
1830Sstevel@tonic-gate 
184802Scf46844 void
vappend(int ch,int cnt,int indent)185802Scf46844 vappend(int ch, int cnt, int indent)
1860Sstevel@tonic-gate {
187802Scf46844 	int i;
188802Scf46844 	unsigned char *gcursor;
1890Sstevel@tonic-gate 	bool escape;
1900Sstevel@tonic-gate 	int repcnt, savedoomed;
1910Sstevel@tonic-gate 	short oldhold = hold;
1921406Scf46844 	int savecnt = cnt;
1931406Scf46844 	line *startsrcline;
1941406Scf46844 	int startsrccol, endsrccol;
1951406Scf46844 	int gotNL = 0;
1961406Scf46844 	int imultlinecnt = 0;
1971406Scf46844 	int omultlinecnt = 0;
1981406Scf46844 
1991406Scf46844 	if ((savecnt > 1) && (ch == 'o' || ch == 'O')) {
2001406Scf46844 		omultlinecnt = 1;
2011406Scf46844 	}
2021406Scf46844 #ifdef XPG6
2031406Scf46844 	if ((savecnt > 1) && (ch == 'a' || ch == 'A' || ch == 'i' || ch == 'I'))
2041406Scf46844 		imultlinecnt = 1;
2051406Scf46844 #endif /* XPG6 */
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	/*
2080Sstevel@tonic-gate 	 * Before a move in hardopen when the line is dirty
2090Sstevel@tonic-gate 	 * or we are in the middle of the printed representation,
2100Sstevel@tonic-gate 	 * we retype the line to the left of the cursor so the
2110Sstevel@tonic-gate 	 * insert looks clean.
2120Sstevel@tonic-gate 	 */
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 	if (ch != 'o' && state == HARDOPEN && (rubble || !ateopr())) {
2150Sstevel@tonic-gate 		rubble = 1;
2160Sstevel@tonic-gate 		gcursor = cursor;
2170Sstevel@tonic-gate 		i = *gcursor;
2180Sstevel@tonic-gate 		*gcursor = ' ';
2190Sstevel@tonic-gate 		wcursor = gcursor;
220802Scf46844 		(void) vmove();
2210Sstevel@tonic-gate 		*gcursor = i;
2220Sstevel@tonic-gate 	}
2233806Scf46844 	/*
2243806Scf46844 	 * If vrep() passed indent = 0, this is the 'r' command,
2253806Scf46844 	 * so don't autoindent until the last char.
2263806Scf46844 	 */
2270Sstevel@tonic-gate 	vaifirst = indent == 0;
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	/*
2300Sstevel@tonic-gate 	 * Handle replace character by (eventually)
2310Sstevel@tonic-gate 	 * limiting the number of input characters allowed
2320Sstevel@tonic-gate 	 * in the vgetline routine.
2330Sstevel@tonic-gate 	 */
2340Sstevel@tonic-gate 	if (ch == 'r')
2350Sstevel@tonic-gate 		repcnt = 2;
2360Sstevel@tonic-gate 	else
2370Sstevel@tonic-gate 		repcnt = 0;
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 	/*
2400Sstevel@tonic-gate 	 * If an autoindent is specified, then
2410Sstevel@tonic-gate 	 * generate a mixture of blanks to tabs to implement
2420Sstevel@tonic-gate 	 * it and place the cursor after the indent.
2430Sstevel@tonic-gate 	 * Text read by the vgetline routine will be placed in genbuf,
2440Sstevel@tonic-gate 	 * so the indent is generated there.
2450Sstevel@tonic-gate 	 */
2460Sstevel@tonic-gate 	if (value(vi_AUTOINDENT) && indent != 0) {
2470Sstevel@tonic-gate 		unsigned char x;
2480Sstevel@tonic-gate 		gcursor = genindent(indent);
2490Sstevel@tonic-gate 		*gcursor = 0;
2500Sstevel@tonic-gate 		vgotoCL(nqcolumn(lastchr(linebuf, cursor), genbuf));
2510Sstevel@tonic-gate 	} else {
2520Sstevel@tonic-gate 		gcursor = genbuf;
2530Sstevel@tonic-gate 		*gcursor = 0;
2540Sstevel@tonic-gate 		if (ch == 'o')
2550Sstevel@tonic-gate 			vfixcurs();
2560Sstevel@tonic-gate 	}
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	/*
2590Sstevel@tonic-gate 	 * Prepare for undo.  Pointers delimit inserted portion of line.
2600Sstevel@tonic-gate 	 */
2610Sstevel@tonic-gate 	vUA1 = vUA2 = cursor;
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 	/*
2640Sstevel@tonic-gate 	 * If we are not in a repeated command and a ^@ comes in
2650Sstevel@tonic-gate 	 * then this means the previous inserted text.
2660Sstevel@tonic-gate 	 * If there is none or it was too long to be saved,
2670Sstevel@tonic-gate 	 * then beep() and also arrange to undo any damage done
2680Sstevel@tonic-gate 	 * so far (e.g. if we are a change.)
2690Sstevel@tonic-gate 	 */
2700Sstevel@tonic-gate 	switch (ch) {
2710Sstevel@tonic-gate 	case 'r':
2720Sstevel@tonic-gate 		break;
2730Sstevel@tonic-gate 	case 'a':
2740Sstevel@tonic-gate 		/*
2750Sstevel@tonic-gate 		 * TRANSLATION_NOTE
2760Sstevel@tonic-gate 		 *	"A" is a terse mode message corresponding to
2770Sstevel@tonic-gate 		 *	"APPEND MODE".
2780Sstevel@tonic-gate 		 *	Translated message of "A" must be 1 character (not byte).
2790Sstevel@tonic-gate 		 *	Or, just leave it.
2800Sstevel@tonic-gate 		 */
2810Sstevel@tonic-gate 		if (value(vi_TERSE)) {
2820Sstevel@tonic-gate 			vshowmode(gettext("A"));
2830Sstevel@tonic-gate 		} else {
2840Sstevel@tonic-gate 			vshowmode(gettext("APPEND MODE"));
2850Sstevel@tonic-gate 		}
2860Sstevel@tonic-gate 		break;
2870Sstevel@tonic-gate 	case 's':
2880Sstevel@tonic-gate 		/*
2890Sstevel@tonic-gate 		 * TRANSLATION_NOTE
2900Sstevel@tonic-gate 		 *	"S" is a terse mode message corresponding to
2910Sstevel@tonic-gate 		 *	"SUBSTITUTE MODE".
2920Sstevel@tonic-gate 		 *	Translated message of "S" must be 1 character (not byte).
2930Sstevel@tonic-gate 		 *	Or, just leave it.
2940Sstevel@tonic-gate 		 */
2950Sstevel@tonic-gate 		if (value(vi_TERSE)) {
2960Sstevel@tonic-gate 			vshowmode(gettext("S"));
2970Sstevel@tonic-gate 		} else {
2980Sstevel@tonic-gate 			vshowmode(gettext("SUBSTITUTE MODE"));
2990Sstevel@tonic-gate 		}
3000Sstevel@tonic-gate 		break;
3010Sstevel@tonic-gate 	case 'c':
3020Sstevel@tonic-gate 		/*
3030Sstevel@tonic-gate 		 * TRANSLATION_NOTE
3040Sstevel@tonic-gate 		 *	"C" is a terse mode message corresponding to
3050Sstevel@tonic-gate 		 *	"CHANGE MODE".
3060Sstevel@tonic-gate 		 *	Translated message of "C" must be 1 character (not byte).
3070Sstevel@tonic-gate 		 *	Or, just leave it.
3080Sstevel@tonic-gate 		 */
3090Sstevel@tonic-gate 		if (value(vi_TERSE)) {
3100Sstevel@tonic-gate 			vshowmode(gettext("C"));
3110Sstevel@tonic-gate 		} else {
3120Sstevel@tonic-gate 			vshowmode(gettext("CHANGE MODE"));
3130Sstevel@tonic-gate 		}
3140Sstevel@tonic-gate 		break;
3150Sstevel@tonic-gate 	case 'R':
3160Sstevel@tonic-gate 		/*
3170Sstevel@tonic-gate 		 * TRANSLATION_NOTE
3180Sstevel@tonic-gate 		 *	"R" is a terse mode message corresponding to
3190Sstevel@tonic-gate 		 *	"REPLACE MODE".
3200Sstevel@tonic-gate 		 *	Translated message of "R" must be 1 character (not byte).
3210Sstevel@tonic-gate 		 *	Or, just leave it.
3220Sstevel@tonic-gate 		 */
3230Sstevel@tonic-gate 		if (value(vi_TERSE)) {
3240Sstevel@tonic-gate 			vshowmode(gettext("R"));
3250Sstevel@tonic-gate 		} else {
3260Sstevel@tonic-gate 			vshowmode(gettext("REPLACE MODE"));
3270Sstevel@tonic-gate 		}
3280Sstevel@tonic-gate 		break;
3290Sstevel@tonic-gate 	case 'o':
3300Sstevel@tonic-gate 		/*
3310Sstevel@tonic-gate 		 * TRANSLATION_NOTE
3320Sstevel@tonic-gate 		 *	"O" is a terse mode message corresponding to
3330Sstevel@tonic-gate 		 *	"OPEN MODE".
3340Sstevel@tonic-gate 		 *	Translated message of "O" must be 1 character (not byte).
3350Sstevel@tonic-gate 		 *	Or, just leave it.
3360Sstevel@tonic-gate 		 */
3370Sstevel@tonic-gate 		if (value(vi_TERSE)) {
3380Sstevel@tonic-gate 			vshowmode(gettext("O"));
3390Sstevel@tonic-gate 		} else {
3400Sstevel@tonic-gate 			vshowmode(gettext("OPEN MODE"));
3410Sstevel@tonic-gate 		}
3420Sstevel@tonic-gate 		break;
3430Sstevel@tonic-gate 	case 'i':
3440Sstevel@tonic-gate 		/*
3450Sstevel@tonic-gate 		 * TRANSLATION_NOTE
3460Sstevel@tonic-gate 		 *	"I" is a terse mode message corresponding to
3470Sstevel@tonic-gate 		 *	"INSERT MODE" and the following "INPUT MODE".
3480Sstevel@tonic-gate 		 *	Translated message of "I" must be 1 character (not byte).
3490Sstevel@tonic-gate 		 *	Or, just leave it.
3500Sstevel@tonic-gate 		 */
3510Sstevel@tonic-gate 		if (value(vi_TERSE)) {
3520Sstevel@tonic-gate 			vshowmode(gettext("I"));
3530Sstevel@tonic-gate 		} else {
3540Sstevel@tonic-gate 			vshowmode(gettext("INSERT MODE"));
3550Sstevel@tonic-gate 		}
3560Sstevel@tonic-gate 		break;
3570Sstevel@tonic-gate 	default:
3580Sstevel@tonic-gate 		/*
3590Sstevel@tonic-gate 		 * TRANSLATION_NOTE
3600Sstevel@tonic-gate 		 *	"I" is a terse mode message corresponding to
3610Sstevel@tonic-gate 		 *	"INPUT MODE" and the previous "INSERT MODE".
3620Sstevel@tonic-gate 		 *	Translated message of "I" must be 1 character (not byte).
3630Sstevel@tonic-gate 		 *	Or, just leave it.
3640Sstevel@tonic-gate 		 */
3650Sstevel@tonic-gate 		if (value(vi_TERSE)) {
3660Sstevel@tonic-gate 			vshowmode(gettext("I"));
3670Sstevel@tonic-gate 		} else {
3680Sstevel@tonic-gate 			vshowmode(gettext("INPUT MODE"));
3690Sstevel@tonic-gate 		}
3700Sstevel@tonic-gate 	}
3710Sstevel@tonic-gate 	ixlatctl(1);
3720Sstevel@tonic-gate 	if ((vglobp && *vglobp == 0) || peekbr()) {
3730Sstevel@tonic-gate 		if (INS[128] == 0200) {
374802Scf46844 			(void) beep();
3750Sstevel@tonic-gate 			if (!splitw)
3760Sstevel@tonic-gate 				ungetkey('u');
3770Sstevel@tonic-gate 			doomed = 0;
3780Sstevel@tonic-gate 			hold = oldhold;
3790Sstevel@tonic-gate 			return;
3800Sstevel@tonic-gate 		}
3810Sstevel@tonic-gate 		/*
3820Sstevel@tonic-gate 		 * Unread input from INS.
3830Sstevel@tonic-gate 		 * An escape will be generated at end of string.
3840Sstevel@tonic-gate 		 * Hold off n^^2 type update on dumb terminals.
3850Sstevel@tonic-gate 		 */
3860Sstevel@tonic-gate 		vglobp = INS;
3870Sstevel@tonic-gate 		inscdcnt = INSCDCNT;
3880Sstevel@tonic-gate 		hold |= HOLDQIK;
3890Sstevel@tonic-gate 	} else if (vglobp == 0) {
3900Sstevel@tonic-gate 		/*
3910Sstevel@tonic-gate 		 * Not a repeated command, get
3920Sstevel@tonic-gate 		 * a new inserted text for repeat.
3930Sstevel@tonic-gate 		 */
3940Sstevel@tonic-gate 		INS[0] = 0;
3950Sstevel@tonic-gate 		INS[128] = 0;
3960Sstevel@tonic-gate 		INSCDCNT = 0;
3970Sstevel@tonic-gate 	}
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	/*
4000Sstevel@tonic-gate 	 * For wrapmargin to hack away second space after a '.'
4010Sstevel@tonic-gate 	 * when the first space caused a line break we keep
4020Sstevel@tonic-gate 	 * track that this happened in gobblebl, which says
4030Sstevel@tonic-gate 	 * to gobble up a blank silently.
4040Sstevel@tonic-gate 	 */
4050Sstevel@tonic-gate 	gobblebl = 0;
4060Sstevel@tonic-gate 
4071406Scf46844 	startsrcline = dot;
4081406Scf46844 	startsrccol = cursor - linebuf;
4091406Scf46844 
4100Sstevel@tonic-gate 	/*
4110Sstevel@tonic-gate 	 * Text gathering loop.
4120Sstevel@tonic-gate 	 * New text goes into genbuf starting at gcursor.
4130Sstevel@tonic-gate 	 * cursor preserves place in linebuf where text will eventually go.
4140Sstevel@tonic-gate 	 */
4150Sstevel@tonic-gate 	if (*cursor == 0 || state == CRTOPEN)
4160Sstevel@tonic-gate 		hold |= HOLDROL;
4170Sstevel@tonic-gate 	for (;;) {
4180Sstevel@tonic-gate 		if (ch == 'r' && repcnt == 0)
4190Sstevel@tonic-gate 			escape = 0;
4200Sstevel@tonic-gate 		else {
4210Sstevel@tonic-gate 			ixlatctl(1);
4223806Scf46844 			/*
4233806Scf46844 			 * When vgetline() returns, gcursor is
4243806Scf46844 			 * pointing to '\0' and vgetline() has
4253806Scf46844 			 * read an ESCAPE or NL.
4263806Scf46844 			 */
4270Sstevel@tonic-gate 			gcursor = vgetline(repcnt, gcursor, &escape, ch);
4281406Scf46844 			if (escape == '\n') {
4291406Scf46844 				gotNL = 1;
4303806Scf46844 #ifdef XPG6
4313806Scf46844 				if (ch == 'r') {
4323806Scf46844 					/*
4333806Scf46844 					 * XPG6 assertion 313 [count]r\n :
4343806Scf46844 					 * Arrange to set cursor correctly.
4353806Scf46844 					 */
4363806Scf46844 					endsrccol = gcursor - genbuf - 1;
4373806Scf46844 				}
4383806Scf46844 #endif /* XPG6 */
4391406Scf46844 			} else {
4401406Scf46844 				/*
4411406Scf46844 				 * Upon escape, gcursor is pointing to '\0'
4421406Scf46844 				 * terminating the string in genbuf.
4431406Scf46844 				 */
4441406Scf46844 				endsrccol = gcursor - genbuf - 1;
4451406Scf46844 			}
4460Sstevel@tonic-gate 			ixlatctl(0);
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 			/*
4490Sstevel@tonic-gate 			 * After an append, stick information
4500Sstevel@tonic-gate 			 * about the ^D's and ^^D's and 0^D's in
4510Sstevel@tonic-gate 			 * the repeated text buffer so repeated
4520Sstevel@tonic-gate 			 * inserts of stuff indented with ^D as backtab's
4530Sstevel@tonic-gate 			 * can work.
4540Sstevel@tonic-gate 			 */
4550Sstevel@tonic-gate 			if (HADUP)
4560Sstevel@tonic-gate 				addtext("^");
4570Sstevel@tonic-gate 			else if (HADZERO)
4580Sstevel@tonic-gate 				addtext("0");
4590Sstevel@tonic-gate 			if(!vglobp)
4600Sstevel@tonic-gate 				INSCDCNT = CDCNT;
4610Sstevel@tonic-gate 			while (CDCNT > 0) {
4620Sstevel@tonic-gate 				addtext("\004");
4630Sstevel@tonic-gate 				CDCNT--;
4640Sstevel@tonic-gate 			}
4650Sstevel@tonic-gate 			if (gobbled)
4660Sstevel@tonic-gate 				addtext(" ");
4670Sstevel@tonic-gate 			addtext(ogcursor);
4680Sstevel@tonic-gate 		}
4690Sstevel@tonic-gate 		repcnt = 0;
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 		/*
4720Sstevel@tonic-gate 		 * Smash the generated and preexisting indents together
4730Sstevel@tonic-gate 		 * and generate one cleanly made out of tabs and spaces
4743806Scf46844 		 * if we are using autoindent and this isn't 'r' command.
4750Sstevel@tonic-gate 		 */
4760Sstevel@tonic-gate 		if (!vaifirst && value(vi_AUTOINDENT)) {
4770Sstevel@tonic-gate 			i = fixindent(indent);
4780Sstevel@tonic-gate 			if (!HADUP)
4790Sstevel@tonic-gate 				indent = i;
4800Sstevel@tonic-gate 			gcursor = strend(genbuf);
4810Sstevel@tonic-gate 		}
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 		/*
4841406Scf46844 		 * Set cnt to 1 to avoid repeating the text on the same line.
4851406Scf46844 		 * Do this for commands 'i', 'I', 'a', and 'A', if we're
4861406Scf46844 		 * inserting anything with a newline for XPG6.  Always do this
4871406Scf46844 		 * for commands 'o' and 'O'.
4881406Scf46844 		 */
4891406Scf46844 		if ((imultlinecnt && gotNL) || omultlinecnt) {
4901406Scf46844 			cnt = 1;
4911406Scf46844 		}
4921406Scf46844 
4931406Scf46844 		/*
4940Sstevel@tonic-gate 		 * Limit the repetition count based on maximum
4950Sstevel@tonic-gate 		 * possible line length; do output implied
4960Sstevel@tonic-gate 		 * by further count (> 1) and cons up the new line
4970Sstevel@tonic-gate 		 * in linebuf.
4980Sstevel@tonic-gate 		 */
4990Sstevel@tonic-gate 		cnt = vmaxrep(ch, cnt);
5003806Scf46844 		/*
5013806Scf46844 		 * cursor points to linebuf
5023806Scf46844 		 * Copy remaining old text (cursor) in original
5033806Scf46844 		 * line to after new text (gcursor + 1) in genbuf.
5043806Scf46844 		 */
5050Sstevel@tonic-gate 		CP(gcursor + 1, cursor);
5063806Scf46844 		/*
5073806Scf46844 		 * For [count] r \n command, when replacing [count] chars
5083806Scf46844 		 * with '\n', this loop replaces [count] chars with "".
5093806Scf46844 		 */
5100Sstevel@tonic-gate 		do {
5113806Scf46844 			/* cp new text (genbuf) into linebuf (cursor) */
5120Sstevel@tonic-gate 			CP(cursor, genbuf);
5130Sstevel@tonic-gate 			if (cnt > 1) {
5140Sstevel@tonic-gate 				int oldhold = hold;
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 				Outchar = vinschar;
5170Sstevel@tonic-gate 				hold |= HOLDQIK;
518802Scf46844 				viprintf("%s", genbuf);
5190Sstevel@tonic-gate 				hold = oldhold;
5200Sstevel@tonic-gate 				Outchar = vputchar;
5210Sstevel@tonic-gate 			}
5223806Scf46844 			/* point cursor after new text in linebuf */
5230Sstevel@tonic-gate 			cursor += gcursor - genbuf;
5240Sstevel@tonic-gate 		} while (--cnt > 0);
5250Sstevel@tonic-gate 		endim();
5260Sstevel@tonic-gate 		vUA2 = cursor;
5273806Scf46844 		/* add the remaining old text after the cursor */
5280Sstevel@tonic-gate 		if (escape != '\n')
5290Sstevel@tonic-gate 			CP(cursor, gcursor + 1);
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 		/*
5320Sstevel@tonic-gate 		 * If doomed characters remain, clobber them,
5330Sstevel@tonic-gate 		 * and reopen the line to get the display exact.
5343806Scf46844 		 * eg. c$ to change to end of line
5350Sstevel@tonic-gate 		 */
5360Sstevel@tonic-gate 		if (state != HARDOPEN) {
5370Sstevel@tonic-gate 			DEPTH(vcline) = 0;
5380Sstevel@tonic-gate 			savedoomed = doomed;
5390Sstevel@tonic-gate 			if (doomed > 0) {
540802Scf46844 				int cind = cindent();
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 				physdc(cind, cind + doomed);
5430Sstevel@tonic-gate 				doomed = 0;
5440Sstevel@tonic-gate 			}
5450Sstevel@tonic-gate 			if(MB_CUR_MAX > 1)
5460Sstevel@tonic-gate 				rewrite = _ON;
5470Sstevel@tonic-gate 			i = vreopen(LINE(vcline), lineDOT(), vcline);
5480Sstevel@tonic-gate 			if(MB_CUR_MAX > 1)
5490Sstevel@tonic-gate 				rewrite = _OFF;
5500Sstevel@tonic-gate #ifdef TRACE
5510Sstevel@tonic-gate 			if (trace)
5520Sstevel@tonic-gate 				fprintf(trace, "restoring doomed from %d to %d\n", doomed, savedoomed);
5530Sstevel@tonic-gate #endif
5540Sstevel@tonic-gate 			if (ch == 'R')
5550Sstevel@tonic-gate 				doomed = savedoomed;
5560Sstevel@tonic-gate 		}
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 		/*
5593806Scf46844 		 * Unless we are continuing on to another line
5603806Scf46844 		 * (got a NL), break out of the for loop (got
5613806Scf46844 		 * an ESCAPE).
5620Sstevel@tonic-gate 		 */
5630Sstevel@tonic-gate 		if (escape != '\n') {
5640Sstevel@tonic-gate 			vshowmode("");
5650Sstevel@tonic-gate 			break;
5660Sstevel@tonic-gate 		}
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 		/*
5690Sstevel@tonic-gate 		 * Set up for the new line.
5700Sstevel@tonic-gate 		 * First save the current line, then construct a new
5710Sstevel@tonic-gate 		 * first image for the continuation line consisting
5720Sstevel@tonic-gate 		 * of any new autoindent plus the pushed ahead text.
5730Sstevel@tonic-gate 		 */
5740Sstevel@tonic-gate 		killU();
5750Sstevel@tonic-gate 		addtext(gobblebl ? " " : "\n");
5763806Scf46844 		/* save vutmp (for undo state) into temp file */
5770Sstevel@tonic-gate 		vsave();
5780Sstevel@tonic-gate 		cnt = 1;
5790Sstevel@tonic-gate 		if (value(vi_AUTOINDENT)) {
5800Sstevel@tonic-gate 			if (value(vi_LISP))
5810Sstevel@tonic-gate 				indent = lindent(dot + 1);
5820Sstevel@tonic-gate 			else
5830Sstevel@tonic-gate 			     if (!HADUP && vaifirst)
5840Sstevel@tonic-gate 				indent = whitecnt(linebuf);
5850Sstevel@tonic-gate 			vaifirst = 0;
5860Sstevel@tonic-gate 			strcLIN(vpastwh(gcursor + 1));
5870Sstevel@tonic-gate 			gcursor = genindent(indent);
5880Sstevel@tonic-gate 			*gcursor = 0;
5890Sstevel@tonic-gate 			if (gcursor + strlen(linebuf) > &genbuf[LBSIZE - 2])
5900Sstevel@tonic-gate 				gcursor = genbuf;
5910Sstevel@tonic-gate 			CP(gcursor, linebuf);
5920Sstevel@tonic-gate 		} else {
5933806Scf46844 			/*
5943806Scf46844 			 * Put gcursor at start of genbuf to wipe
5953806Scf46844 			 * out previous line in preparation for
5963806Scf46844 			 * the next vgetline() loop.
5973806Scf46844 			 */
5980Sstevel@tonic-gate 			CP(genbuf, gcursor + 1);
5990Sstevel@tonic-gate 			gcursor = genbuf;
6000Sstevel@tonic-gate 		}
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 		/*
6030Sstevel@tonic-gate 		 * If we started out as a single line operation and are now
6040Sstevel@tonic-gate 		 * turning into a multi-line change, then we had better yank
6050Sstevel@tonic-gate 		 * out dot before it changes so that undo will work
6060Sstevel@tonic-gate 		 * correctly later.
6070Sstevel@tonic-gate 		 */
6080Sstevel@tonic-gate 		if (FIXUNDO && vundkind == VCHNG) {
6090Sstevel@tonic-gate 			vremote(1, yank, 0);
6100Sstevel@tonic-gate 			undap1--;
6110Sstevel@tonic-gate 		}
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 		/*
6140Sstevel@tonic-gate 		 * Now do the append of the new line in the buffer,
6153806Scf46844 		 * and update the display, ie: append genbuf to
6163806Scf46844 		 * the file after dot.  If slowopen
6170Sstevel@tonic-gate 		 * we don't do very much.
6180Sstevel@tonic-gate 		 */
6190Sstevel@tonic-gate 		vdoappend(genbuf);
6200Sstevel@tonic-gate 		vundkind = VMANYINS;
6210Sstevel@tonic-gate 		vcline++;
6220Sstevel@tonic-gate 		if (state != VISUAL)
6230Sstevel@tonic-gate 			vshow(dot, NOLINE);
6240Sstevel@tonic-gate 		else {
6250Sstevel@tonic-gate 			i += LINE(vcline - 1);
6260Sstevel@tonic-gate 			vopen(dot, i);
6270Sstevel@tonic-gate 			if (value(vi_SLOWOPEN))
6280Sstevel@tonic-gate 				vscrap();
6290Sstevel@tonic-gate 			else
6300Sstevel@tonic-gate 				vsync1(LINE(vcline));
6310Sstevel@tonic-gate 		}
6320Sstevel@tonic-gate 		switch (ch) {
6330Sstevel@tonic-gate 		case 'r':
6340Sstevel@tonic-gate 			break;
6350Sstevel@tonic-gate 		case 'a':
6360Sstevel@tonic-gate 			if (value(vi_TERSE)) {
6370Sstevel@tonic-gate 				vshowmode(gettext("A"));
6380Sstevel@tonic-gate 			} else {
6390Sstevel@tonic-gate 				vshowmode(gettext("APPEND MODE"));
6400Sstevel@tonic-gate 			}
6410Sstevel@tonic-gate 			break;
6420Sstevel@tonic-gate 		case 's':
6430Sstevel@tonic-gate 			if (value(vi_TERSE)) {
6440Sstevel@tonic-gate 				vshowmode(gettext("S"));
6450Sstevel@tonic-gate 			} else {
6460Sstevel@tonic-gate 				vshowmode(gettext("SUBSTITUTE MODE"));
6470Sstevel@tonic-gate 			}
6480Sstevel@tonic-gate 			break;
6490Sstevel@tonic-gate 		case 'c':
6500Sstevel@tonic-gate 			if (value(vi_TERSE)) {
6510Sstevel@tonic-gate 				vshowmode(gettext("C"));
6520Sstevel@tonic-gate 			} else {
6530Sstevel@tonic-gate 				vshowmode(gettext("CHANGE MODE"));
6540Sstevel@tonic-gate 			}
6550Sstevel@tonic-gate 			break;
6560Sstevel@tonic-gate 		case 'R':
6570Sstevel@tonic-gate 			if (value(vi_TERSE)) {
6580Sstevel@tonic-gate 				vshowmode(gettext("R"));
6590Sstevel@tonic-gate 			} else {
6600Sstevel@tonic-gate 				vshowmode(gettext("REPLACE MODE"));
6610Sstevel@tonic-gate 			}
6620Sstevel@tonic-gate 			break;
6630Sstevel@tonic-gate 		case 'i':
6640Sstevel@tonic-gate 			if (value(vi_TERSE)) {
6650Sstevel@tonic-gate 				vshowmode(gettext("I"));
6660Sstevel@tonic-gate 			} else {
6670Sstevel@tonic-gate 				vshowmode(gettext("INSERT MODE"));
6680Sstevel@tonic-gate 			}
6690Sstevel@tonic-gate 			break;
6700Sstevel@tonic-gate 		case 'o':
6710Sstevel@tonic-gate 			if (value(vi_TERSE)) {
6720Sstevel@tonic-gate 				vshowmode(gettext("O"));
6730Sstevel@tonic-gate 			} else {
6740Sstevel@tonic-gate 				vshowmode(gettext("OPEN MODE"));
6750Sstevel@tonic-gate 			}
6760Sstevel@tonic-gate 			break;
6770Sstevel@tonic-gate 		default:
6780Sstevel@tonic-gate 			if (value(vi_TERSE)) {
6790Sstevel@tonic-gate 				vshowmode(gettext("I"));
6800Sstevel@tonic-gate 			} else {
6810Sstevel@tonic-gate 				vshowmode(gettext("INPUT MODE"));
6820Sstevel@tonic-gate 			}
6830Sstevel@tonic-gate 		}
6840Sstevel@tonic-gate 		strcLIN(gcursor);
6853806Scf46844 		/* zero genbuf */
6860Sstevel@tonic-gate 		*gcursor = 0;
6870Sstevel@tonic-gate 		cursor = linebuf;
6880Sstevel@tonic-gate 		vgotoCL(nqcolumn(cursor - 1, genbuf));
6891406Scf46844 	} /* end for (;;) loop in vappend() */
6901406Scf46844 
6911406Scf46844 	if (imultlinecnt && gotNL) {
6921406Scf46844 		imultlinerep(savecnt, startsrcline, startsrccol, endsrccol);
6931406Scf46844 	} else if (omultlinecnt) {
6941406Scf46844 		omultlinerep(savecnt, startsrcline, endsrccol);
6953806Scf46844 #ifdef XPG6
6963806Scf46844 	} else if (savecnt > 1 && ch == 'r' && gotNL) {
6973806Scf46844 		/*
6983806Scf46844 		 * XPG6 assertion 313 & 254 : Position cursor for [count]r\n
6993806Scf46844 		 * then insert [count -1] newlines.
7003806Scf46844 		 */
7013806Scf46844 		endsrccol = gcursor - genbuf - 1;
7023806Scf46844 		rmultlinerep(savecnt, endsrccol);
7033806Scf46844 #endif /* XPG6 */
7040Sstevel@tonic-gate 	}
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	/*
7070Sstevel@tonic-gate 	 * All done with insertion, position the cursor
7080Sstevel@tonic-gate 	 * and sync the screen.
7090Sstevel@tonic-gate 	 */
7100Sstevel@tonic-gate 	hold = oldhold;
7111406Scf46844 	if ((imultlinecnt && gotNL) || omultlinecnt) {
7121406Scf46844 		fixdisplay();
7133806Scf46844 #ifdef XPG6
7143806Scf46844 	} else if (savecnt > 1 && ch == 'r' && gotNL) {
7153806Scf46844 		fixdisplay();
7163806Scf46844 		/*
7173806Scf46844 		 * XPG6 assertion 313 & 254 [count]r\n : Set flag to call
7183806Scf46844 		 * fixdisplay() after operate() has finished.  To be sure that
7193806Scf46844 		 * the text (after the last \n followed by an indent) is always
7203806Scf46844 		 * displayed, fixdisplay() is called right before getting
7213806Scf46844 		 * the next command.
7223806Scf46844 		 */
7233806Scf46844 		redisplay = 1;
7243806Scf46844 #endif /* XPG6 */
7251406Scf46844 	} else if (cursor > linebuf) {
7260Sstevel@tonic-gate 		cursor = lastchr(linebuf, cursor);
7273806Scf46844 #ifdef XPG6
7283806Scf46844 		/*
7293806Scf46844 		 * XPG6 assertion 313 & 254 [count]r\n :
7303806Scf46844 		 * For 'r' command, when the replacement char causes new
7313806Scf46844 		 * lines to be created, point cursor to first non-blank.
7323806Scf46844 		 * The old code, ie: cursor = lastchr(linebuf, cursor);
7333806Scf46844 		 * set cursor to the blank before the first non-blank
7343806Scf46844 		 * for r\n
7353806Scf46844 		 */
7363806Scf46844 		if (ch == 'r' && gotNL && isblank((int)*cursor))
7373806Scf46844 			++cursor;
7383806Scf46844 #endif /* XPG6 */
7391406Scf46844 	}
7400Sstevel@tonic-gate 	if (state != HARDOPEN)
7410Sstevel@tonic-gate 		vsyncCL();
7420Sstevel@tonic-gate 	else if (cursor > linebuf)
7430Sstevel@tonic-gate 		back1();
7440Sstevel@tonic-gate 	doomed = 0;
7450Sstevel@tonic-gate 	wcursor = cursor;
746802Scf46844 	(void) vmove();
7470Sstevel@tonic-gate }
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate /*
7501406Scf46844  * XPG6
7511406Scf46844  * To repeat multi-line input for [count]a, [count]A, [count]i, [count]I,
7521406Scf46844  * or a subsequent [count]. :
7531406Scf46844  * insert input count-1 more times.
7541406Scf46844  */
7551406Scf46844 
7561406Scf46844 static void
imultlinerep(int savecnt,line * startsrcline,int startsrccol,int endsrccol)7571406Scf46844 imultlinerep(int savecnt, line *startsrcline, int startsrccol, int endsrccol)
7581406Scf46844 {
7591406Scf46844 	int tmpcnt = 2;	/* 1st insert counts as 1 repeat */
7601406Scf46844 	line *srcline, *endsrcline;
7611406Scf46844 	size_t destsize = LBSIZE - endsrccol - 1;
7621406Scf46844 
7631406Scf46844 	endsrcline = dot;
7641406Scf46844 
7651406Scf46844 	/* Save linebuf into temp file before moving off the line. */
7661406Scf46844 	vsave();
7671406Scf46844 
7681406Scf46844 	/*
7691406Scf46844 	 * At this point the temp file contains the first iteration of
7701406Scf46844 	 * a multi-line insert, and we need to repeat it savecnt - 1
7711406Scf46844 	 * more times in the temp file.  dot is the last line in the
7721406Scf46844 	 * first iteration of the insert.  Decrement dot so that
7731406Scf46844 	 * vdoappend() will append each new line before the last line.
7741406Scf46844 	 */
7751406Scf46844 	--dot;
7761406Scf46844 	--vcline;
7771406Scf46844 	/*
7781406Scf46844 	 * Use genbuf to rebuild the last line in the 1st iteration
7791406Scf46844 	 * of the repeated insert, then copy this line to the temp file.
7801406Scf46844 	 */
7811406Scf46844 	(void) strlcpy((char *)genbuf, (char *)linebuf, sizeof (genbuf));
782*13093SRoger.Faulkner@Oracle.COM 	getaline(*startsrcline);
7831406Scf46844 	if (strlcpy((char *)(genbuf + endsrccol + 1),
7841406Scf46844 	    (char *)(linebuf + startsrccol), destsize) >= destsize) {
7851406Scf46844 		error(gettext("Line too long"));
7861406Scf46844 	}
7871406Scf46844 	vdoappend(genbuf);
7881406Scf46844 	vcline++;
7891406Scf46844 	/*
7901406Scf46844 	 * Loop from the second line of the first iteration
7911406Scf46844 	 * through endsrcline, appending after dot.
7921406Scf46844 	 */
7931406Scf46844 	++startsrcline;
7941406Scf46844 
7951406Scf46844 	while (tmpcnt <= savecnt) {
7961406Scf46844 		for (srcline = startsrcline; srcline <= endsrcline;
7971406Scf46844 		    ++srcline) {
7981406Scf46844 			if ((tmpcnt == savecnt) &&
7991406Scf46844 			    (srcline == endsrcline)) {
8001406Scf46844 				/*
8011406Scf46844 				 * The last line is already in place,
8021406Scf46844 				 * just make it the current line.
8031406Scf46844 				 */
8041406Scf46844 				vcline++;
8051406Scf46844 				dot++;
8061406Scf46844 				getDOT();
8071406Scf46844 				cursor = linebuf + endsrccol;
8081406Scf46844 			} else {
809*13093SRoger.Faulkner@Oracle.COM 				getaline(*srcline);
8101406Scf46844 				/* copy linebuf to temp file */
8111406Scf46844 				vdoappend(linebuf);
8121406Scf46844 				vcline++;
8131406Scf46844 			}
8141406Scf46844 		}
8151406Scf46844 		++tmpcnt;
8161406Scf46844 	}
8171406Scf46844 }
8181406Scf46844 
8191406Scf46844 /*
8201406Scf46844  * To repeat input for [count]o, [count]O, or a subsequent [count]. :
8211406Scf46844  * append input count-1 more times to the end of the already added
8221406Scf46844  * text, each time starting on a new line.
8231406Scf46844  */
8241406Scf46844 
8251406Scf46844 static void
omultlinerep(int savecnt,line * startsrcline,int endsrccol)8261406Scf46844 omultlinerep(int savecnt, line *startsrcline, int endsrccol)
8271406Scf46844 {
8281406Scf46844 	int tmpcnt = 2;	/* 1st insert counts as 1 repeat */
8291406Scf46844 	line *srcline, *endsrcline;
8301406Scf46844 
8311406Scf46844 	endsrcline = dot;
8321406Scf46844 	/* Save linebuf into temp file before moving off the line. */
8331406Scf46844 	vsave();
8341406Scf46844 
8351406Scf46844 	/*
8361406Scf46844 	 * Loop from the first line of the first iteration
8371406Scf46844 	 * through endsrcline, appending after dot.
8381406Scf46844 	 */
8391406Scf46844 	while (tmpcnt <= savecnt) {
8401406Scf46844 		for (srcline = startsrcline; srcline <= endsrcline; ++srcline) {
841*13093SRoger.Faulkner@Oracle.COM 			getaline(*srcline);
8421406Scf46844 			/* copy linebuf to temp file */
8431406Scf46844 			vdoappend(linebuf);
8441406Scf46844 			vcline++;
8451406Scf46844 		}
8461406Scf46844 		++tmpcnt;
8471406Scf46844 	}
8481406Scf46844 	cursor = linebuf + endsrccol;
8491406Scf46844 }
8501406Scf46844 
8513806Scf46844 #ifdef XPG6
8523806Scf46844 /*
8533806Scf46844  * XPG6 assertion 313 & 254 : To repeat '\n' for [count]r\n
8543806Scf46844  * insert '\n' savecnt-1 more times before the already added '\n'.
8553806Scf46844  */
8563806Scf46844 
8573806Scf46844 static void
rmultlinerep(int savecnt,int endsrccol)8583806Scf46844 rmultlinerep(int savecnt, int endsrccol)
8593806Scf46844 {
8603806Scf46844 	int tmpcnt = 2;	/* 1st replacement counts as 1 repeat */
8613806Scf46844 
8623806Scf46844 	/* Save linebuf into temp file before moving off the line. */
8633806Scf46844 	vsave();
8643806Scf46844 	/*
8653806Scf46844 	 * At this point the temp file contains the line followed by '\n',
8663806Scf46844 	 * which is preceded by indentation if autoindent is set.
8673806Scf46844 	 * '\n' must be repeated [savecnt - 1] more times in the temp file.
8683806Scf46844 	 * dot is the current line containing the '\n'.  Decrement dot so that
8693806Scf46844 	 * vdoappend() will append each '\n' before the current '\n'.
8703806Scf46844 	 * This will allow only the last line to contain any autoindent
8713806Scf46844 	 * characters.
8723806Scf46844 	 */
8733806Scf46844 	--dot;
8743806Scf46844 	--vcline;
8753806Scf46844 
8763806Scf46844 	/*
8773806Scf46844 	 * Append after dot.
8783806Scf46844 	 */
8793806Scf46844 	while (tmpcnt <= savecnt) {
8803806Scf46844 		linebuf[0] = '\0';
8813806Scf46844 		/* append linebuf below current line in temp file */
8823806Scf46844 		vdoappend(linebuf);
8833806Scf46844 		vcline++;
8843806Scf46844 		++tmpcnt;
8853806Scf46844 	}
8863806Scf46844 	/* set the current line to the line after the last '\n' */
8873806Scf46844 	++dot;
8883806Scf46844 	++vcline;
8893806Scf46844 	/* point cursor after (linebuf + endsrccol) */
8903806Scf46844 	vcursaft(linebuf + endsrccol);
8913806Scf46844 }
8923806Scf46844 #endif /* XPG6 */
8933806Scf46844 
8941406Scf46844 /*
8951406Scf46844  * Similiar to a ctrl-l, however always vrepaint() in case the last line
8961406Scf46844  * of the repeat would exceed the bottom of the screen.
8971406Scf46844  */
8981406Scf46844 
8993806Scf46844 void
fixdisplay(void)9001406Scf46844 fixdisplay(void)
9011406Scf46844 {
9021406Scf46844 	vclear();
9031406Scf46844 	vdirty(0, vcnt);
9041406Scf46844 	if (state != VISUAL) {
9051406Scf46844 		vclean();
9061406Scf46844 		vcnt = 0;
9071406Scf46844 		vmoveto(dot, cursor, 0);
9081406Scf46844 	} else {
9091406Scf46844 		vredraw(WTOP);
9101406Scf46844 		vrepaint(cursor);
9111406Scf46844 		vfixcurs();
9121406Scf46844 	}
9131406Scf46844 }
9141406Scf46844 
9151406Scf46844 /*
9160Sstevel@tonic-gate  * Subroutine for vgetline to back up a single character position,
9170Sstevel@tonic-gate  * backwards around end of lines (vgoto can't hack columns which are
9180Sstevel@tonic-gate  * less than 0 in general).
9190Sstevel@tonic-gate  */
920802Scf46844 void
back1(void)921802Scf46844 back1(void)
9220Sstevel@tonic-gate {
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 	vgoto(destline - 1, WCOLS + destcol - 1);
9250Sstevel@tonic-gate }
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate /*
9280Sstevel@tonic-gate  * Get a line into genbuf after gcursor.
9290Sstevel@tonic-gate  * Cnt limits the number of input characters
9300Sstevel@tonic-gate  * accepted and is used for handling the replace
9310Sstevel@tonic-gate  * single character command.  Aescaped is the location
9320Sstevel@tonic-gate  * where we stick a termination indicator (whether we
9330Sstevel@tonic-gate  * ended with an ESCAPE or a newline/return.
9340Sstevel@tonic-gate  *
9350Sstevel@tonic-gate  * We do erase-kill type processing here and also
9360Sstevel@tonic-gate  * are careful about the way we do this so that it is
9370Sstevel@tonic-gate  * repeatable.  (I.e. so that your kill doesn't happen,
9380Sstevel@tonic-gate  * when you repeat an insert if it was escaped with \ the
9390Sstevel@tonic-gate  * first time you did it.  commch is the command character
9400Sstevel@tonic-gate  * involved, including the prompt for readline.
9410Sstevel@tonic-gate  */
9420Sstevel@tonic-gate unsigned char *
vgetline(cnt,gcursor,aescaped,commch)9430Sstevel@tonic-gate vgetline(cnt, gcursor, aescaped, commch)
9440Sstevel@tonic-gate 	int cnt;
945802Scf46844 	unsigned char *gcursor;
9460Sstevel@tonic-gate 	bool *aescaped;
9470Sstevel@tonic-gate 	unsigned char commch;
9480Sstevel@tonic-gate {
949802Scf46844 	int c, ch;
950802Scf46844 	unsigned char *cp, *pcp;
9510Sstevel@tonic-gate 	int x, y, iwhite, backsl=0;
9520Sstevel@tonic-gate 	unsigned char *iglobp;
9530Sstevel@tonic-gate 	int (*OO)() = Outchar;
9540Sstevel@tonic-gate 	int length, width;
9550Sstevel@tonic-gate 	unsigned char multic[MULTI_BYTE_MAX+1];
9560Sstevel@tonic-gate 	wchar_t wchar = 0;
9570Sstevel@tonic-gate 	unsigned char	*p;
9580Sstevel@tonic-gate 	int	len;
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate 	/*
9620Sstevel@tonic-gate 	 * Clear the output state and counters
9630Sstevel@tonic-gate 	 * for autoindent backwards motion (counts of ^D, etc.)
9640Sstevel@tonic-gate 	 * Remember how much white space at beginning of line so
9650Sstevel@tonic-gate 	 * as not to allow backspace over autoindent.
9660Sstevel@tonic-gate 	 */
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 	*aescaped = 0;
9690Sstevel@tonic-gate 	ogcursor = gcursor;
9700Sstevel@tonic-gate 	flusho();
9710Sstevel@tonic-gate 	CDCNT = 0;
9720Sstevel@tonic-gate 	HADUP = 0;
9730Sstevel@tonic-gate 	HADZERO = 0;
9740Sstevel@tonic-gate 	gobbled = 0;
9750Sstevel@tonic-gate 	iwhite = whitecnt(genbuf);
9760Sstevel@tonic-gate 	iglobp = vglobp;
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	/*
9790Sstevel@tonic-gate 	 * Clear abbreviation recursive-use count
9800Sstevel@tonic-gate 	 */
9810Sstevel@tonic-gate 	abbrepcnt = 0;
9820Sstevel@tonic-gate 	/*
9830Sstevel@tonic-gate 	 * Carefully avoid using vinschar in the echo area.
9840Sstevel@tonic-gate 	 */
9850Sstevel@tonic-gate 	if (splitw)
9860Sstevel@tonic-gate 		Outchar = vputchar;
9870Sstevel@tonic-gate 	else {
9880Sstevel@tonic-gate 		Outchar = vinschar;
9890Sstevel@tonic-gate 		vprepins();
9900Sstevel@tonic-gate 	}
9910Sstevel@tonic-gate 	for (;;) {
9920Sstevel@tonic-gate 		length = 0;
9930Sstevel@tonic-gate 		backsl = 0;
9940Sstevel@tonic-gate 		if (gobblebl)
9950Sstevel@tonic-gate 			gobblebl--;
9960Sstevel@tonic-gate 		if (cnt != 0) {
9970Sstevel@tonic-gate 			cnt--;
9980Sstevel@tonic-gate 			if (cnt == 0)
9990Sstevel@tonic-gate 				goto vadone;
10000Sstevel@tonic-gate 		}
10010Sstevel@tonic-gate 		c = getkey();
10020Sstevel@tonic-gate 		if (c != ATTN)
10030Sstevel@tonic-gate 			c &= 0377;
10040Sstevel@tonic-gate 		ch = c;
10050Sstevel@tonic-gate 		maphopcnt = 0;
10060Sstevel@tonic-gate 		if (vglobp == 0 && Peekkey == 0 && commch != 'r')
10070Sstevel@tonic-gate 			while ((ch = map(c, immacs, commch)) != c) {
10080Sstevel@tonic-gate 				c = ch;
10090Sstevel@tonic-gate 				if (!value(vi_REMAP))
10100Sstevel@tonic-gate 					break;
10110Sstevel@tonic-gate 				if (++maphopcnt > 256)
10120Sstevel@tonic-gate 					error(gettext("Infinite macro loop"));
10130Sstevel@tonic-gate 			}
10140Sstevel@tonic-gate 		if (!iglobp) {
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate 			/*
10170Sstevel@tonic-gate 			 * Erase-kill type processing.
10180Sstevel@tonic-gate 			 * Only happens if we were not reading
10190Sstevel@tonic-gate 			 * from untyped input when we started.
10200Sstevel@tonic-gate 			 * Map users erase to ^H, kill to -1 for switch.
10210Sstevel@tonic-gate 			 */
10220Sstevel@tonic-gate 			if (c == tty.c_cc[VERASE])
10230Sstevel@tonic-gate 				c = CTRL('h');
10240Sstevel@tonic-gate 			else if (c == tty.c_cc[VKILL])
10250Sstevel@tonic-gate 				c = -1;
10260Sstevel@tonic-gate 			switch (c) {
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 			/*
10290Sstevel@tonic-gate 			 * ^?		Interrupt drops you back to visual
10300Sstevel@tonic-gate 			 *		command mode with an unread interrupt
10310Sstevel@tonic-gate 			 *		still in the input buffer.
10320Sstevel@tonic-gate 			 *
10330Sstevel@tonic-gate 			 * ^\		Quit does the same as interrupt.
10340Sstevel@tonic-gate 			 *		If you are a ex command rather than
10350Sstevel@tonic-gate 			 *		a vi command this will drop you
10360Sstevel@tonic-gate 			 *		back to command mode for sure.
10370Sstevel@tonic-gate 			 */
10380Sstevel@tonic-gate 			case ATTN:
10390Sstevel@tonic-gate 			case QUIT:
10400Sstevel@tonic-gate 				ungetkey(c);
10410Sstevel@tonic-gate 				goto vadone;
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 			/*
10440Sstevel@tonic-gate 			 * ^H		Backs up a character in the input.
10450Sstevel@tonic-gate 			 *
10460Sstevel@tonic-gate 			 * BUG:		Can't back around line boundaries.
10470Sstevel@tonic-gate 			 *		This is hard because stuff has
10480Sstevel@tonic-gate 			 *		already been saved for repeat.
10490Sstevel@tonic-gate 			 */
10500Sstevel@tonic-gate 			case CTRL('h'):
10510Sstevel@tonic-gate bakchar:
10520Sstevel@tonic-gate 				cp = lastchr(ogcursor, gcursor);
10530Sstevel@tonic-gate 				if (cp < ogcursor) {
10540Sstevel@tonic-gate 					if (splitw) {
10550Sstevel@tonic-gate 						/*
10560Sstevel@tonic-gate 						 * Backspacing over readecho
10570Sstevel@tonic-gate 						 * prompt. Pretend delete but
10580Sstevel@tonic-gate 						 * don't beep.
10590Sstevel@tonic-gate 						 */
10600Sstevel@tonic-gate 						ungetkey(c);
10610Sstevel@tonic-gate 						goto vadone;
10620Sstevel@tonic-gate 					}
1063802Scf46844 					(void) beep();
10640Sstevel@tonic-gate 					continue;
10650Sstevel@tonic-gate 				}
10660Sstevel@tonic-gate 				goto vbackup;
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 			/*
10690Sstevel@tonic-gate 			 * ^W		Back up a white/non-white word.
10700Sstevel@tonic-gate 			 */
10710Sstevel@tonic-gate 			case CTRL('w'):
10720Sstevel@tonic-gate 				wdkind = 1;
10730Sstevel@tonic-gate 				for (cp = gcursor; cp > ogcursor && isspace(cp[-1]); cp--)
10740Sstevel@tonic-gate 					continue;
10750Sstevel@tonic-gate 				pcp = lastchr(ogcursor, cp);
10760Sstevel@tonic-gate 				for (c = wordch(pcp);
10770Sstevel@tonic-gate 				    cp > ogcursor && wordof(c, pcp); cp = pcp, pcp = lastchr(ogcursor, cp))
10780Sstevel@tonic-gate 					continue;
10790Sstevel@tonic-gate 				goto vbackup;
10800Sstevel@tonic-gate 
10810Sstevel@tonic-gate 			/*
10820Sstevel@tonic-gate 			 * users kill	Kill input on this line, back to
10830Sstevel@tonic-gate 			 *		the autoindent.
10840Sstevel@tonic-gate 			 */
10850Sstevel@tonic-gate 			case -1:
10860Sstevel@tonic-gate 				cp = ogcursor;
10870Sstevel@tonic-gate vbackup:
10880Sstevel@tonic-gate 				if (cp == gcursor) {
1089802Scf46844 					(void) beep();
10900Sstevel@tonic-gate 					continue;
10910Sstevel@tonic-gate 				}
10920Sstevel@tonic-gate 				endim();
10930Sstevel@tonic-gate 				*cp = 0;
10940Sstevel@tonic-gate 				c = cindent();
10950Sstevel@tonic-gate 				vgotoCL(nqcolumn(lastchr(linebuf, cursor), genbuf));
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 				if (doomed >= 0)
10980Sstevel@tonic-gate 					doomed += c - cindent();
10990Sstevel@tonic-gate 				gcursor = cp;
11000Sstevel@tonic-gate 				continue;
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate 			/*
11030Sstevel@tonic-gate 			 * \		Followed by erase or kill
11040Sstevel@tonic-gate 			 *		maps to just the erase or kill.
11050Sstevel@tonic-gate 			 */
11060Sstevel@tonic-gate 			case '\\':
11070Sstevel@tonic-gate 				x = destcol, y = destline;
11080Sstevel@tonic-gate 				putchar('\\');
11090Sstevel@tonic-gate 				vcsync();
11100Sstevel@tonic-gate 				c = getkey();
11110Sstevel@tonic-gate 				if (c == tty.c_cc[VERASE]
11120Sstevel@tonic-gate 				    || c == tty.c_cc[VKILL])
11130Sstevel@tonic-gate 				{
11140Sstevel@tonic-gate 					vgoto(y, x);
11150Sstevel@tonic-gate 					if (doomed >= 0)
11160Sstevel@tonic-gate 						doomed++;
11170Sstevel@tonic-gate 					multic[0] = wchar = c;
11180Sstevel@tonic-gate 					length = 1;
11190Sstevel@tonic-gate 					goto def;
11200Sstevel@tonic-gate 				}
11210Sstevel@tonic-gate 				ungetkey(c), c = '\\';
11220Sstevel@tonic-gate 				backsl = 1;
11230Sstevel@tonic-gate 				break;
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 			/*
11260Sstevel@tonic-gate 			 * ^Q		Super quote following character
11270Sstevel@tonic-gate 			 *		Only ^@ is verboten (trapped at
11280Sstevel@tonic-gate 			 *		a lower level) and \n forces a line
11290Sstevel@tonic-gate 			 *		split so doesn't really go in.
11300Sstevel@tonic-gate 			 *
11310Sstevel@tonic-gate 			 * ^V		Synonym for ^Q
11320Sstevel@tonic-gate 			 */
11330Sstevel@tonic-gate 			case CTRL('q'):
11340Sstevel@tonic-gate 			case CTRL('v'):
11350Sstevel@tonic-gate 				x = destcol, y = destline;
11360Sstevel@tonic-gate 				putchar('^');
11370Sstevel@tonic-gate 				vgoto(y, x);
11380Sstevel@tonic-gate 				c = getkey();
11390Sstevel@tonic-gate #ifdef USG
11400Sstevel@tonic-gate 				if (c == ATTN)
11410Sstevel@tonic-gate 					c = tty.c_cc[VINTR];
11420Sstevel@tonic-gate #endif
11430Sstevel@tonic-gate 				if (c != NL) {
11440Sstevel@tonic-gate 					if (doomed >= 0)
11450Sstevel@tonic-gate 						doomed++;
11460Sstevel@tonic-gate 					multic[0] = wchar = c;
11470Sstevel@tonic-gate 					length = 1;
11480Sstevel@tonic-gate 					goto def;
11490Sstevel@tonic-gate 				}
11500Sstevel@tonic-gate 				break;
11510Sstevel@tonic-gate 			}
11520Sstevel@tonic-gate 		}
11530Sstevel@tonic-gate 
11540Sstevel@tonic-gate 		/*
11550Sstevel@tonic-gate 		 * If we get a blank not in the echo area
11560Sstevel@tonic-gate 		 * consider splitting the window in the wrapmargin.
11570Sstevel@tonic-gate 		 */
11580Sstevel@tonic-gate 		if(!backsl) {
11590Sstevel@tonic-gate 			ungetkey(c);
11600Sstevel@tonic-gate 			if((length = _mbftowc((char *)multic, &wchar, getkey, &Peekkey)) <= 0) {
1161802Scf46844 				(void) beep();
11620Sstevel@tonic-gate 				continue;
11630Sstevel@tonic-gate 			}
11640Sstevel@tonic-gate 		} else {
11650Sstevel@tonic-gate 			length = 1;
11660Sstevel@tonic-gate 			multic[0] = '\\';
11670Sstevel@tonic-gate 		}
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 		if (c != NL && !splitw) {
11700Sstevel@tonic-gate 			if (c == ' ' && gobblebl) {
11710Sstevel@tonic-gate 				gobbled = 1;
11720Sstevel@tonic-gate 				continue;
11730Sstevel@tonic-gate 			}
11740Sstevel@tonic-gate 			if ((width = wcwidth(wchar)) <= 0)
11750Sstevel@tonic-gate 				width = (wchar <= 0177 ? 1 : 4);
11760Sstevel@tonic-gate 			if (value(vi_WRAPMARGIN) &&
11770Sstevel@tonic-gate 				(outcol + width - 1 >= OCOLUMNS - value(vi_WRAPMARGIN) ||
11780Sstevel@tonic-gate 				 backsl && outcol==0) &&
11790Sstevel@tonic-gate 				commch != 'r') {
11800Sstevel@tonic-gate 				/*
11810Sstevel@tonic-gate 				 * At end of word and hit wrapmargin.
11820Sstevel@tonic-gate 				 * Move the word to next line and keep going.
11830Sstevel@tonic-gate 				 */
11840Sstevel@tonic-gate 				unsigned char *wp;
11850Sstevel@tonic-gate 				int bytelength;
11860Sstevel@tonic-gate #ifndef PRESUNEUC
11870Sstevel@tonic-gate 				unsigned char *tgcursor;
11880Sstevel@tonic-gate 				wchar_t wc1, wc2;
11890Sstevel@tonic-gate 				tgcursor = gcursor;
11900Sstevel@tonic-gate #endif /* PRESUNEUC */
11910Sstevel@tonic-gate 				wdkind = 1;
11920Sstevel@tonic-gate 				strncpy(gcursor, multic, length);
11930Sstevel@tonic-gate 				gcursor += length;
11940Sstevel@tonic-gate 				if (backsl) {
11950Sstevel@tonic-gate #ifdef PRESUNEUC
11960Sstevel@tonic-gate 					if((length = mbftowc((char *)multic, &wchar, getkey, &Peekkey)) <= 0) {
11970Sstevel@tonic-gate #else
11980Sstevel@tonic-gate 					if((length = _mbftowc((char *)multic, &wchar, getkey, &Peekkey)) <= 0) {
11990Sstevel@tonic-gate #endif /* PRESUNEUC */
1200802Scf46844 						(void) beep();
12010Sstevel@tonic-gate 						continue;
12020Sstevel@tonic-gate 					}
12030Sstevel@tonic-gate 					strncpy(gcursor, multic, length);
12040Sstevel@tonic-gate 					gcursor += length;
12050Sstevel@tonic-gate 				}
12060Sstevel@tonic-gate 				*gcursor = 0;
12070Sstevel@tonic-gate 				/*
12080Sstevel@tonic-gate 				 * Find end of previous word if we are past it.
12090Sstevel@tonic-gate 				 */
12100Sstevel@tonic-gate 				for (cp=gcursor; cp>ogcursor && isspace(cp[-1]); cp--)
12110Sstevel@tonic-gate 					;
12120Sstevel@tonic-gate #ifdef PRESUNEUC
12130Sstevel@tonic-gate 				/* find screen width of previous word */
12140Sstevel@tonic-gate 				width = 0;
12150Sstevel@tonic-gate 				for(wp = cp; *wp; )
12160Sstevel@tonic-gate #else
12170Sstevel@tonic-gate 				/* count screen width of pending characters */
12180Sstevel@tonic-gate 				width = 0;
12190Sstevel@tonic-gate 				for(wp = tgcursor; wp < cp;)
12200Sstevel@tonic-gate #endif /* PRESUNEUC */
12210Sstevel@tonic-gate 					if((bytelength = mbtowc(&wchar, (char *)wp, MULTI_BYTE_MAX)) < 0) {
12220Sstevel@tonic-gate 						width+=4;
12230Sstevel@tonic-gate 						wp++;
12240Sstevel@tonic-gate 					} else {
12250Sstevel@tonic-gate 						int curwidth = wcwidth(wchar);
12260Sstevel@tonic-gate 						if(curwidth <= 0)
12270Sstevel@tonic-gate 							width += (*wp < 0200 ? 2 : 4);
12280Sstevel@tonic-gate 						else
12290Sstevel@tonic-gate 							width += curwidth;
12300Sstevel@tonic-gate 						wp += bytelength;
12310Sstevel@tonic-gate 					}
12320Sstevel@tonic-gate 
12330Sstevel@tonic-gate #ifdef PRESUNEUC
12340Sstevel@tonic-gate 				if (outcol+(backsl?OCOLUMNS:0) - width >= OCOLUMNS - value(vi_WRAPMARGIN)) {
12350Sstevel@tonic-gate #else
12360Sstevel@tonic-gate 				if (outcol+(backsl?OCOLUMNS:0) + width -1 >= OCOLUMNS - value(vi_WRAPMARGIN)) {
12370Sstevel@tonic-gate #endif /* PRESUNEUC */
12380Sstevel@tonic-gate 					/*
12390Sstevel@tonic-gate 					 * Find beginning of previous word.
12400Sstevel@tonic-gate 					 */
12410Sstevel@tonic-gate #ifdef PRESUNEUC
12420Sstevel@tonic-gate 					for (; cp>ogcursor && !isspace(cp[-1]); cp--)
12430Sstevel@tonic-gate 						;
12440Sstevel@tonic-gate #else
12450Sstevel@tonic-gate 					wc1 = wc2 = 0;
12460Sstevel@tonic-gate 					while (cp>ogcursor) {
12470Sstevel@tonic-gate 						if (isspace(cp[-1])) {
12480Sstevel@tonic-gate 							break;
12490Sstevel@tonic-gate 						}
12500Sstevel@tonic-gate 						if (!multibyte) {
12510Sstevel@tonic-gate 							cp--;
12520Sstevel@tonic-gate 							continue;
12530Sstevel@tonic-gate 						}
12540Sstevel@tonic-gate 						wp = (unsigned char *)(cp -
12550Sstevel@tonic-gate 							MB_CUR_MAX);
12560Sstevel@tonic-gate 						if (wp < ogcursor)
12570Sstevel@tonic-gate 							wp = ogcursor;
12580Sstevel@tonic-gate 						while (cp > wp) {
12590Sstevel@tonic-gate /* 7tabs */if (wc2) {
12600Sstevel@tonic-gate /* 7tabs */	if ((bytelength = mbtowc(&wc1, (char *)wp, cp-wp)) != cp-wp) {
12610Sstevel@tonic-gate /* 7tabs */		wp++;
12620Sstevel@tonic-gate /* 7tabs */		wc1 = 0;
12630Sstevel@tonic-gate /* 7tabs */		continue;
12640Sstevel@tonic-gate /* 7tabs */	}
12650Sstevel@tonic-gate /* 7tabs */} else {
12660Sstevel@tonic-gate /* 7tabs */	if ((bytelength = mbtowc(&wc2, (char *)wp, cp-wp)) != cp-wp) {
12670Sstevel@tonic-gate /* 7tabs */		wp++;
12680Sstevel@tonic-gate /* 7tabs */		wc2 = 0;
12690Sstevel@tonic-gate /* 7tabs */		continue;
12700Sstevel@tonic-gate /* 7tabs */	}
12710Sstevel@tonic-gate /* 7tabs */}
12720Sstevel@tonic-gate /* 7tabs */if (wc1) {
12730Sstevel@tonic-gate /* 7tabs */	if (wdbdg && (!iswascii(wc1) || !iswascii(wc2))) {
12740Sstevel@tonic-gate /* 7tabs */		if ((*wdbdg)(wc1, wc2, 2) < 5) {
12750Sstevel@tonic-gate /* 7tabs */			goto ws;
12760Sstevel@tonic-gate /* 7tabs */		}
12770Sstevel@tonic-gate /* 7tabs */	}
12780Sstevel@tonic-gate /* 7tabs */	wc2 = wc1;
12790Sstevel@tonic-gate /* 7tabs */	wc1 = 0;
12800Sstevel@tonic-gate /* 7tabs */	cp -= bytelength - 1;
12810Sstevel@tonic-gate /* 7tabs */	break;
12820Sstevel@tonic-gate /* 7tabs */} else {
12830Sstevel@tonic-gate /* 7tabs */	cp -= bytelength - 1;
12840Sstevel@tonic-gate /* 7tabs */	break;
12850Sstevel@tonic-gate /* 7tabs */}
12860Sstevel@tonic-gate 						}
12870Sstevel@tonic-gate 						cp--;
12880Sstevel@tonic-gate 					}
12890Sstevel@tonic-gate ws:
12900Sstevel@tonic-gate #endif /* PRESUNEUC */
12910Sstevel@tonic-gate 					if (cp <= ogcursor) {
12920Sstevel@tonic-gate 						/*
12930Sstevel@tonic-gate 						 * There is a single word that
12940Sstevel@tonic-gate 						 * is too long to fit.  Just
12950Sstevel@tonic-gate 						 * let it pass, but beep for
12960Sstevel@tonic-gate 						 * each new letter to warn
12970Sstevel@tonic-gate 						 * the luser.
12980Sstevel@tonic-gate 						 */
12990Sstevel@tonic-gate 						gcursor -= length;
13000Sstevel@tonic-gate 						c = *gcursor;
13010Sstevel@tonic-gate 						*gcursor = 0;
1302802Scf46844 						(void) beep();
13030Sstevel@tonic-gate 						goto dontbreak;
13040Sstevel@tonic-gate 					}
13050Sstevel@tonic-gate 					/*
13060Sstevel@tonic-gate 					 * Save it for next line.
13070Sstevel@tonic-gate 					 */
13080Sstevel@tonic-gate 					macpush(cp, 0);
13090Sstevel@tonic-gate #ifdef PRESUNEUC
13100Sstevel@tonic-gate 					cp--;
13110Sstevel@tonic-gate #endif /* PRESUNEUC */
13120Sstevel@tonic-gate 				}
13130Sstevel@tonic-gate 				macpush("\n", 0);
13140Sstevel@tonic-gate 				/*
13150Sstevel@tonic-gate 				 * Erase white space before the word.
13160Sstevel@tonic-gate 				 */
13170Sstevel@tonic-gate 				while (cp > ogcursor && isspace(cp[-1]))
13180Sstevel@tonic-gate 					cp--;	/* skip blank */
13190Sstevel@tonic-gate 				gobblebl = 3;
13200Sstevel@tonic-gate 				goto vbackup;
13210Sstevel@tonic-gate 			}
13220Sstevel@tonic-gate 		dontbreak:;
13230Sstevel@tonic-gate 		}
13240Sstevel@tonic-gate 
13250Sstevel@tonic-gate 		/*
13260Sstevel@tonic-gate 		 * Word abbreviation mode.
13270Sstevel@tonic-gate 		 */
13280Sstevel@tonic-gate 		if (anyabbrs && gcursor > ogcursor && !wordch(multic) && wordch(lastchr(ogcursor, gcursor))) {
13290Sstevel@tonic-gate 				int wdtype, abno;
13300Sstevel@tonic-gate 
13310Sstevel@tonic-gate 				multic[length] = 0;
13320Sstevel@tonic-gate 				wdkind = 1;
13330Sstevel@tonic-gate 				cp = lastchr(ogcursor, gcursor);
13340Sstevel@tonic-gate 				pcp = lastchr(ogcursor, cp);
13350Sstevel@tonic-gate 				for (wdtype = wordch(pcp);
13360Sstevel@tonic-gate 				    cp > ogcursor && wordof(wdtype, pcp); cp = pcp, pcp = lastchr(ogcursor, pcp))
13370Sstevel@tonic-gate 					;
13380Sstevel@tonic-gate 				*gcursor = 0;
13390Sstevel@tonic-gate 				for (abno=0; abbrevs[abno].mapto; abno++) {
13400Sstevel@tonic-gate 					if (eq(cp, abbrevs[abno].cap)) {
13410Sstevel@tonic-gate 						if(abbrepcnt == 0) {
13420Sstevel@tonic-gate 							if(reccnt(abbrevs[abno].cap, abbrevs[abno].mapto))
13430Sstevel@tonic-gate 								abbrepcnt = 1;
13440Sstevel@tonic-gate 							macpush(multic, 0);
13450Sstevel@tonic-gate 							macpush(abbrevs[abno].mapto);
13460Sstevel@tonic-gate 							goto vbackup;
13470Sstevel@tonic-gate 						} else
13480Sstevel@tonic-gate 							abbrepcnt = 0;
13490Sstevel@tonic-gate 					}
13500Sstevel@tonic-gate 				}
13510Sstevel@tonic-gate 		}
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate 		switch (c) {
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate 		/*
13560Sstevel@tonic-gate 		 * ^M		Except in repeat maps to \n.
13570Sstevel@tonic-gate 		 */
13580Sstevel@tonic-gate 		case CR:
13590Sstevel@tonic-gate 			if (vglobp) {
13600Sstevel@tonic-gate 				multic[0] = wchar = c;
13610Sstevel@tonic-gate 				length = 1;
13620Sstevel@tonic-gate 				goto def;
13630Sstevel@tonic-gate 			}
13640Sstevel@tonic-gate 			c = '\n';
13650Sstevel@tonic-gate 			/* presto chango ... */
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate 		/*
13680Sstevel@tonic-gate 		 * \n		Start new line.
13690Sstevel@tonic-gate 		 */
13700Sstevel@tonic-gate 		case NL:
13710Sstevel@tonic-gate 			*aescaped = c;
13720Sstevel@tonic-gate 			goto vadone;
13730Sstevel@tonic-gate 
13740Sstevel@tonic-gate 		/*
13750Sstevel@tonic-gate 		 * escape	End insert unless repeat and more to repeat.
13760Sstevel@tonic-gate 		 */
13770Sstevel@tonic-gate 		case ESCAPE:
13780Sstevel@tonic-gate 			if (lastvgk) {
13790Sstevel@tonic-gate 				multic[0] = wchar = c;
13800Sstevel@tonic-gate 				length = 1;
13810Sstevel@tonic-gate 				goto def;
13820Sstevel@tonic-gate 			}
13830Sstevel@tonic-gate 			goto vadone;
13840Sstevel@tonic-gate 
13850Sstevel@tonic-gate 		/*
13860Sstevel@tonic-gate 		 * ^D		Backtab.
13870Sstevel@tonic-gate 		 * ^T		Software forward tab.
13880Sstevel@tonic-gate 		 *
13890Sstevel@tonic-gate 		 *		Unless in repeat where this means these
13900Sstevel@tonic-gate 		 *		were superquoted in.
13910Sstevel@tonic-gate 		 */
13920Sstevel@tonic-gate 		case CTRL('t'):
13930Sstevel@tonic-gate 			if (vglobp) {
13940Sstevel@tonic-gate 				multic[0] = wchar = c;
13950Sstevel@tonic-gate 				length = 1;
13960Sstevel@tonic-gate 				goto def;
13970Sstevel@tonic-gate 			}
13980Sstevel@tonic-gate 			/* fall into ... */
13990Sstevel@tonic-gate 
14000Sstevel@tonic-gate 			*gcursor = 0;
14010Sstevel@tonic-gate 			cp = vpastwh(genbuf);
14020Sstevel@tonic-gate 			c = whitecnt(genbuf);
14030Sstevel@tonic-gate 			if (ch == CTRL('t')) {
14040Sstevel@tonic-gate 				/*
14050Sstevel@tonic-gate 				 * ^t just generates new indent replacing
14060Sstevel@tonic-gate 				 * current white space rounded up to soft
14070Sstevel@tonic-gate 				 * tab stop increment.
14080Sstevel@tonic-gate 				 */
14090Sstevel@tonic-gate 				if (cp != gcursor)
14100Sstevel@tonic-gate 					/*
14110Sstevel@tonic-gate 					 * BUG:		Don't hack ^T except
14120Sstevel@tonic-gate 					 *		right after initial
14130Sstevel@tonic-gate 					 *		white space.
14140Sstevel@tonic-gate 					 */
14150Sstevel@tonic-gate 					continue;
14160Sstevel@tonic-gate 				cp = genindent(iwhite = backtab(c + value(vi_SHIFTWIDTH) + 1));
14170Sstevel@tonic-gate 				ogcursor = cp;
14180Sstevel@tonic-gate 				goto vbackup;
14190Sstevel@tonic-gate 			}
14200Sstevel@tonic-gate 			/*
14210Sstevel@tonic-gate 			 * ^D works only if we are at the (end of) the
14220Sstevel@tonic-gate 			 * generated autoindent.  We count the ^D for repeat
14230Sstevel@tonic-gate 			 * purposes.
14240Sstevel@tonic-gate 			 */
14250Sstevel@tonic-gate 		case CTRL('d'):
14260Sstevel@tonic-gate 			/* check if ^d was superquoted in */
14270Sstevel@tonic-gate 			if(vglobp && inscdcnt <= 0) {
14280Sstevel@tonic-gate 				multic[0] = wchar = c;
14290Sstevel@tonic-gate 				length = 1;
14300Sstevel@tonic-gate 				goto def;
14310Sstevel@tonic-gate 			}
14320Sstevel@tonic-gate 			if(vglobp)
14330Sstevel@tonic-gate 				inscdcnt--;
14340Sstevel@tonic-gate 			*gcursor = 0;
14350Sstevel@tonic-gate 			cp = vpastwh(genbuf);
14360Sstevel@tonic-gate 			c = whitecnt(genbuf);
14370Sstevel@tonic-gate 			if (c == iwhite && c != 0)
14380Sstevel@tonic-gate 				if (cp == gcursor) {
14390Sstevel@tonic-gate 					iwhite = backtab(c);
14400Sstevel@tonic-gate 					CDCNT++;
14410Sstevel@tonic-gate 					ogcursor = cp = genindent(iwhite);
14420Sstevel@tonic-gate 					goto vbackup;
14430Sstevel@tonic-gate 				} else if (&cp[1] == gcursor &&
14440Sstevel@tonic-gate 				    (*cp == '^' || *cp == '0')) {
14450Sstevel@tonic-gate 					/*
14460Sstevel@tonic-gate 					 * ^^D moves to margin, then back
14470Sstevel@tonic-gate 					 * to current indent on next line.
14480Sstevel@tonic-gate 					 *
14490Sstevel@tonic-gate 					 * 0^D moves to margin and then
14500Sstevel@tonic-gate 					 * stays there.
14510Sstevel@tonic-gate 					 */
14520Sstevel@tonic-gate 					HADZERO = *cp == '0';
14530Sstevel@tonic-gate 					ogcursor = cp = genbuf;
14540Sstevel@tonic-gate 					HADUP = 1 - HADZERO;
14550Sstevel@tonic-gate 					CDCNT = 1;
14560Sstevel@tonic-gate 					endim();
14570Sstevel@tonic-gate 					back1();
1458802Scf46844 					(void) vputchar(' ');
14590Sstevel@tonic-gate 					goto vbackup;
14600Sstevel@tonic-gate 				}
14610Sstevel@tonic-gate 
14620Sstevel@tonic-gate 			if (vglobp && vglobp - iglobp >= 2) {
14630Sstevel@tonic-gate 				if ((p = vglobp - MB_CUR_MAX) < iglobp)
14640Sstevel@tonic-gate 					p = iglobp;
14650Sstevel@tonic-gate 				for ( ; p < &vglobp[-2]; p += len) {
14660Sstevel@tonic-gate 					if ((len = mblen((char *)p, MB_CUR_MAX)) <= 0)
14670Sstevel@tonic-gate 						len = 1;
14680Sstevel@tonic-gate 				}
14690Sstevel@tonic-gate 				if ((p == &vglobp[-2]) &&
14700Sstevel@tonic-gate 			            (*p == '^' || *p == '0') &&
14710Sstevel@tonic-gate 			            gcursor == ogcursor + 1)
14720Sstevel@tonic-gate 					goto bakchar;
14730Sstevel@tonic-gate 			}
14740Sstevel@tonic-gate 			continue;
14750Sstevel@tonic-gate 
14760Sstevel@tonic-gate 		default:
14770Sstevel@tonic-gate 			/*
14780Sstevel@tonic-gate 			 * Possibly discard control inputs.
14790Sstevel@tonic-gate 			 */
14800Sstevel@tonic-gate 			if (!vglobp && junk(c)) {
1481802Scf46844 				(void) beep();
14820Sstevel@tonic-gate 				continue;
14830Sstevel@tonic-gate 			}
14840Sstevel@tonic-gate def:
14850Sstevel@tonic-gate 			if (!backsl) {
14860Sstevel@tonic-gate 				putchar(wchar);
14870Sstevel@tonic-gate 				flush();
14880Sstevel@tonic-gate 			}
14890Sstevel@tonic-gate 			if (gcursor + length - 1 > &genbuf[LBSIZE - 2])
14900Sstevel@tonic-gate 				error(gettext("Line too long"));
14910Sstevel@tonic-gate 			(void)strncpy(gcursor, multic, length);
14920Sstevel@tonic-gate 			gcursor += length;
14930Sstevel@tonic-gate 			vcsync();
14940Sstevel@tonic-gate 			if (value(vi_SHOWMATCH) && !iglobp)
14950Sstevel@tonic-gate 				if (c == ')' || c == '}')
14960Sstevel@tonic-gate 					lsmatch(gcursor);
14970Sstevel@tonic-gate 			continue;
14980Sstevel@tonic-gate 		}
14990Sstevel@tonic-gate 	}
15000Sstevel@tonic-gate vadone:
15010Sstevel@tonic-gate 	*gcursor = 0;
15020Sstevel@tonic-gate 	if (Outchar != termchar)
15030Sstevel@tonic-gate 		Outchar = OO;
15040Sstevel@tonic-gate 	endim();
15050Sstevel@tonic-gate 	return (gcursor);
15060Sstevel@tonic-gate }
15070Sstevel@tonic-gate 
15080Sstevel@tonic-gate int	vgetsplit();
15090Sstevel@tonic-gate unsigned char	*vsplitpt;
15100Sstevel@tonic-gate 
15110Sstevel@tonic-gate /*
15120Sstevel@tonic-gate  * Append the line in buffer at lp
15130Sstevel@tonic-gate  * to the buffer after dot.
15140Sstevel@tonic-gate  */
1515802Scf46844 void
vdoappend(unsigned char * lp)1516802Scf46844 vdoappend(unsigned char *lp)
15170Sstevel@tonic-gate {
1518802Scf46844 	int oing = inglobal;
15190Sstevel@tonic-gate 
15200Sstevel@tonic-gate 	vsplitpt = lp;
15210Sstevel@tonic-gate 	inglobal = 1;
15220Sstevel@tonic-gate 	(void)append(vgetsplit, dot);
15230Sstevel@tonic-gate 	inglobal = oing;
15240Sstevel@tonic-gate }
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate /*
15270Sstevel@tonic-gate  * Subroutine for vdoappend to pass to append.
15280Sstevel@tonic-gate  */
1529802Scf46844 int
vgetsplit(void)1530802Scf46844 vgetsplit(void)
15310Sstevel@tonic-gate {
15320Sstevel@tonic-gate 
15330Sstevel@tonic-gate 	if (vsplitpt == 0)
15340Sstevel@tonic-gate 		return (EOF);
15350Sstevel@tonic-gate 	strcLIN(vsplitpt);
15360Sstevel@tonic-gate 	vsplitpt = 0;
15370Sstevel@tonic-gate 	return (0);
15380Sstevel@tonic-gate }
15390Sstevel@tonic-gate 
15400Sstevel@tonic-gate /*
15410Sstevel@tonic-gate  * Vmaxrep determines the maximum repetition factor
15420Sstevel@tonic-gate  * allowed that will yield total line length less than
15430Sstevel@tonic-gate  * LBSIZE characters and also does hacks for the R command.
15440Sstevel@tonic-gate  */
1545802Scf46844 int
vmaxrep(unsigned char ch,int cnt)1546802Scf46844 vmaxrep(unsigned char ch, int cnt)
15470Sstevel@tonic-gate {
1548802Scf46844 	int len;
15490Sstevel@tonic-gate 	unsigned char *cp;
15500Sstevel@tonic-gate 	int repcnt, oldcnt, replen;
15510Sstevel@tonic-gate 	if (cnt > LBSIZE - 2)
15520Sstevel@tonic-gate 		cnt = LBSIZE - 2;
15530Sstevel@tonic-gate 	if (ch == 'R') {
15540Sstevel@tonic-gate 		len = strlen(cursor);
15550Sstevel@tonic-gate 		oldcnt = 0;
15560Sstevel@tonic-gate 		for(cp = cursor; *cp; ) {
15570Sstevel@tonic-gate 			oldcnt++;
15580Sstevel@tonic-gate 			cp = nextchr(cp);
15590Sstevel@tonic-gate 		}
15600Sstevel@tonic-gate 		repcnt = 0;
15610Sstevel@tonic-gate 		for(cp = genbuf; *cp; ) {
15620Sstevel@tonic-gate 			repcnt++;
15630Sstevel@tonic-gate 			cp = nextchr(cp);
15640Sstevel@tonic-gate 		}
15650Sstevel@tonic-gate 		/*
15660Sstevel@tonic-gate 		 * if number of characters in replacement string
15670Sstevel@tonic-gate 		 * (repcnt) is less than number of characters following
15680Sstevel@tonic-gate 		 * cursor (oldcnt), find end of repcnt
15690Sstevel@tonic-gate 		 * characters after cursor
15700Sstevel@tonic-gate 		 */
15710Sstevel@tonic-gate 		if(repcnt < oldcnt) {
15720Sstevel@tonic-gate 			for(cp = cursor; repcnt > 0; repcnt--)
15730Sstevel@tonic-gate 				cp = nextchr(cp);
15740Sstevel@tonic-gate 			len = cp - cursor;
15750Sstevel@tonic-gate 		}
15760Sstevel@tonic-gate 		CP(cursor, cursor + len);
15770Sstevel@tonic-gate 		vUD2 += len;
15780Sstevel@tonic-gate 	}
15790Sstevel@tonic-gate 	len = strlen(linebuf);
15800Sstevel@tonic-gate 	replen = strlen(genbuf);
15810Sstevel@tonic-gate 	if (len + cnt * replen <= LBSIZE - 2)
15820Sstevel@tonic-gate 		return (cnt);
15830Sstevel@tonic-gate 	cnt = (LBSIZE - 2 - len) / replen;
15840Sstevel@tonic-gate 	if (cnt == 0) {
15850Sstevel@tonic-gate 		vsave();
15860Sstevel@tonic-gate 		error(gettext("Line too long"));
15870Sstevel@tonic-gate 	}
15880Sstevel@tonic-gate 	return (cnt);
15890Sstevel@tonic-gate }
15900Sstevel@tonic-gate 
15910Sstevel@tonic-gate /*
15920Sstevel@tonic-gate  * Determine how many occurrences of word 'CAP' are in 'MAPTO'.  To be
15930Sstevel@tonic-gate  * considered an occurrence there must be both a nonword-prefix, a
15940Sstevel@tonic-gate  * complete match of 'CAP' within 'MAPTO', and a nonword-suffix.
15950Sstevel@tonic-gate  * Note that the beginning and end of 'MAPTO' are considered to be
15960Sstevel@tonic-gate  * valid nonword delimiters.
15970Sstevel@tonic-gate  */
1598802Scf46844 int
reccnt(unsigned char * cap,unsigned char * mapto)1599802Scf46844 reccnt(unsigned char *cap, unsigned char *mapto)
16000Sstevel@tonic-gate {
1601802Scf46844 	int i, cnt, final;
16020Sstevel@tonic-gate 
16030Sstevel@tonic-gate 	cnt = 0;
16040Sstevel@tonic-gate 	final = strlen(mapto) - strlen(cap);
16050Sstevel@tonic-gate 
16060Sstevel@tonic-gate 	for (i=0; i <= final; i++)
16070Sstevel@tonic-gate 	  if ((strncmp(cap, mapto+i, strlen(cap)) == 0)       /* match */
16080Sstevel@tonic-gate 	  && (i == 0     || !wordch(&mapto[i-1]))	      /* prefix ok */
16090Sstevel@tonic-gate 	  && (i == final || !wordch(&mapto[i+strlen(cap)])))  /* suffix ok */
16100Sstevel@tonic-gate 		cnt++;
16110Sstevel@tonic-gate 	return (cnt);
16120Sstevel@tonic-gate }
16130Sstevel@tonic-gate 
1614