xref: /onnv-gate/usr/src/cmd/vi/port/ex_vops.c (revision 500:6568d6b53c69)
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*500Sceastha  * 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 
390Sstevel@tonic-gate /*
400Sstevel@tonic-gate  * This file defines the operation sequences which interface the
410Sstevel@tonic-gate  * logical changes to the file buffer with the internal and external
420Sstevel@tonic-gate  * display representations.
430Sstevel@tonic-gate  */
440Sstevel@tonic-gate 
450Sstevel@tonic-gate /*
460Sstevel@tonic-gate  * Undo.
470Sstevel@tonic-gate  *
480Sstevel@tonic-gate  * Undo is accomplished in two ways.  We often for small changes in the
490Sstevel@tonic-gate  * current line know how (in terms of a change operator) how the change
500Sstevel@tonic-gate  * occurred.  Thus on an intelligent terminal we can undo the operation
510Sstevel@tonic-gate  * by another such operation, using insert and delete character
520Sstevel@tonic-gate  * stuff.  The pointers vU[AD][12] index the buffer vutmp when this
530Sstevel@tonic-gate  * is possible and provide the necessary information.
540Sstevel@tonic-gate  *
550Sstevel@tonic-gate  * The other case is that the change involved multiple lines or that
560Sstevel@tonic-gate  * we have moved away from the line or forgotten how the change was
570Sstevel@tonic-gate  * accomplished.  In this case we do a redisplay and hope that the
580Sstevel@tonic-gate  * low level optimization routines (which don't look for winning
590Sstevel@tonic-gate  * via insert/delete character) will not lose too badly.
600Sstevel@tonic-gate  */
610Sstevel@tonic-gate unsigned char	*vUA1, *vUA2;
620Sstevel@tonic-gate unsigned char	*vUD1, *vUD2;
630Sstevel@tonic-gate 
640Sstevel@tonic-gate vUndo()
650Sstevel@tonic-gate {
660Sstevel@tonic-gate 
670Sstevel@tonic-gate 	/*
680Sstevel@tonic-gate 	 * Avoid UU which clobbers ability to do u.
690Sstevel@tonic-gate 	 */
700Sstevel@tonic-gate 	if (vundkind == VNONE || vundkind == VCAPU || vUNDdot != dot) {
710Sstevel@tonic-gate 		beep();
720Sstevel@tonic-gate 		return;
730Sstevel@tonic-gate 	}
740Sstevel@tonic-gate 	CP(vutmp, linebuf);
750Sstevel@tonic-gate 	vUD1 = linebuf; vUD2 = strend(linebuf);
760Sstevel@tonic-gate 	putmk1(dot, vUNDsav);
770Sstevel@tonic-gate 	getDOT();
780Sstevel@tonic-gate 	vUA1 = linebuf; vUA2 = strend(linebuf);
790Sstevel@tonic-gate 	vundkind = VCAPU;
800Sstevel@tonic-gate 	if (state == ONEOPEN || state == HARDOPEN) {
810Sstevel@tonic-gate 		vjumpto(dot, vUNDcurs, 0);
820Sstevel@tonic-gate 		return;
830Sstevel@tonic-gate 	}
840Sstevel@tonic-gate 	vdirty(vcline, 1);
850Sstevel@tonic-gate 	if(MB_CUR_MAX > 1)
860Sstevel@tonic-gate 		rewrite = _ON;
870Sstevel@tonic-gate 	vsyncCL();
880Sstevel@tonic-gate 	if(MB_CUR_MAX > 1)
890Sstevel@tonic-gate 		rewrite = _OFF;
900Sstevel@tonic-gate 	cursor = linebuf;
910Sstevel@tonic-gate 	vfixcurs();
920Sstevel@tonic-gate }
930Sstevel@tonic-gate 
940Sstevel@tonic-gate vundo(show)
950Sstevel@tonic-gate bool show;	/* if true update the screen */
960Sstevel@tonic-gate {
970Sstevel@tonic-gate 	register int cnt;
980Sstevel@tonic-gate 	register line *addr;
990Sstevel@tonic-gate 	register unsigned char *cp;
1000Sstevel@tonic-gate 	unsigned char temp[LBSIZE];
1010Sstevel@tonic-gate 	bool savenote;
1020Sstevel@tonic-gate 	int (*OO)();
1030Sstevel@tonic-gate 	short oldhold = hold;
1040Sstevel@tonic-gate 	unsigned multic[MULTI_BYTE_MAX];
1050Sstevel@tonic-gate 	int length;
1060Sstevel@tonic-gate 	wchar_t wchar;
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 	switch (vundkind) {
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 	case VMANYINS:
1110Sstevel@tonic-gate 		wcursor = 0;
1120Sstevel@tonic-gate 		addr1 = undap1;
1130Sstevel@tonic-gate 		addr2 = undap2 - 1;
1140Sstevel@tonic-gate 		vsave();
1150Sstevel@tonic-gate 		YANKreg('1');
1160Sstevel@tonic-gate 		notecnt = 0;
1170Sstevel@tonic-gate 		/* fall into ... */
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 	case VMANY:
1200Sstevel@tonic-gate 	case VMCHNG:
1210Sstevel@tonic-gate 		vsave();
1220Sstevel@tonic-gate 		addr = dot - vcline;
1230Sstevel@tonic-gate 		notecnt = 1;
1240Sstevel@tonic-gate 		if (undkind == UNDPUT && undap1 == undap2) {
1250Sstevel@tonic-gate 			beep();
1260Sstevel@tonic-gate 			break;
1270Sstevel@tonic-gate 		}
1280Sstevel@tonic-gate 		/*
1290Sstevel@tonic-gate 		 * Undo() call below basically replaces undap1 to undap2-1
1300Sstevel@tonic-gate 		 * with dol through unddol-1.  Hack screen image to
1310Sstevel@tonic-gate 		 * reflect this replacement.
1320Sstevel@tonic-gate 		 */
1330Sstevel@tonic-gate 		if (show)
1340Sstevel@tonic-gate 			if (undkind == UNDMOVE)
1350Sstevel@tonic-gate 				vdirty(0, lines);
1360Sstevel@tonic-gate 			else
1370Sstevel@tonic-gate 				vreplace(undap1 - addr, undap2 - undap1,
1380Sstevel@tonic-gate 				    undkind == UNDPUT ? 0 : unddol - dol);
1390Sstevel@tonic-gate 		savenote = notecnt;
1400Sstevel@tonic-gate 		undo(1);
1410Sstevel@tonic-gate 		if (show && (vundkind != VMCHNG || addr != dot))
1420Sstevel@tonic-gate 			killU();
1430Sstevel@tonic-gate 		vundkind = VMANY;
1440Sstevel@tonic-gate 		cnt = dot - addr;
1450Sstevel@tonic-gate 		if (cnt < 0 || cnt > vcnt || state != VISUAL) {
1460Sstevel@tonic-gate 			if (show)
1470Sstevel@tonic-gate 				vjumpto(dot, NOSTR, '.');
1480Sstevel@tonic-gate 			break;
1490Sstevel@tonic-gate 		}
1500Sstevel@tonic-gate 		if (!savenote)
1510Sstevel@tonic-gate 			notecnt = 0;
1520Sstevel@tonic-gate 		if (show) {
1530Sstevel@tonic-gate 			vcline = cnt;
1540Sstevel@tonic-gate 			if(MB_CUR_MAX > 1)
1550Sstevel@tonic-gate 				rewrite = _ON;
1560Sstevel@tonic-gate 			vrepaint(vmcurs);
1570Sstevel@tonic-gate 			if(MB_CUR_MAX > 1)
1580Sstevel@tonic-gate 				rewrite = _OFF;
1590Sstevel@tonic-gate 		}
1600Sstevel@tonic-gate 		vmcurs = 0;
1610Sstevel@tonic-gate 		break;
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	case VCHNG:
1640Sstevel@tonic-gate 	case VCAPU:
1650Sstevel@tonic-gate 		vundkind = VCHNG;
1660Sstevel@tonic-gate 		strcpy(temp, vutmp);
1670Sstevel@tonic-gate 		strcpy(vutmp, linebuf);
1680Sstevel@tonic-gate 		doomed = lcolumn(vUA2) - lcolumn(vUA1);
1690Sstevel@tonic-gate 		strcLIN(temp);
1700Sstevel@tonic-gate 		cp = vUA1; vUA1 = vUD1; vUD1 = cp;
1710Sstevel@tonic-gate 		cp = vUA2; vUA2 = vUD2; vUD2 = cp;
1720Sstevel@tonic-gate 		if (!show)
1730Sstevel@tonic-gate 			break;
1740Sstevel@tonic-gate 		cursor = vUD1;
1750Sstevel@tonic-gate 		if (state == HARDOPEN) {
1760Sstevel@tonic-gate 			doomed = 0;
1770Sstevel@tonic-gate 			vsave();
1780Sstevel@tonic-gate 			vopen(dot, WBOT);
1790Sstevel@tonic-gate 			vnline(cursor);
1800Sstevel@tonic-gate 			break;
1810Sstevel@tonic-gate 		}
1820Sstevel@tonic-gate 		/*
1830Sstevel@tonic-gate 		 * Pseudo insert command.
1840Sstevel@tonic-gate 		 */
1850Sstevel@tonic-gate 		vcursat(cursor);
1860Sstevel@tonic-gate 		OO = Outchar; Outchar = vinschar; hold |= HOLDQIK;
1870Sstevel@tonic-gate 		vprepins();
1880Sstevel@tonic-gate 		temp[vUA2 - linebuf] = 0;
1890Sstevel@tonic-gate 		for (cp = &temp[vUA1 - linebuf]; *cp;) {
1900Sstevel@tonic-gate 			length = mbtowc(&wchar, (char *)cp, MULTI_BYTE_MAX);
1910Sstevel@tonic-gate 			if(length < 0) {
1920Sstevel@tonic-gate 				putoctal = 1;
1930Sstevel@tonic-gate 				putchar(*cp++);
1940Sstevel@tonic-gate 				putoctal = 0;
1950Sstevel@tonic-gate 			} else {
1960Sstevel@tonic-gate 				putchar(wchar);
1970Sstevel@tonic-gate 				cp += length;
1980Sstevel@tonic-gate 			}
1990Sstevel@tonic-gate 		}
2000Sstevel@tonic-gate 		Outchar = OO; hold = oldhold;
2010Sstevel@tonic-gate 		endim();
2020Sstevel@tonic-gate 		physdc(cindent(), cindent() + doomed);
2030Sstevel@tonic-gate 		doomed = 0;
2040Sstevel@tonic-gate 		vdirty(vcline, 1);
2050Sstevel@tonic-gate 		if(MB_CUR_MAX > 1)
2060Sstevel@tonic-gate 			rewrite = _ON;
2070Sstevel@tonic-gate 		vsyncCL();
2080Sstevel@tonic-gate 		if(MB_CUR_MAX > 1)
2090Sstevel@tonic-gate 			rewrite = _OFF;
2100Sstevel@tonic-gate 		if (cursor > linebuf && cursor >= strend(linebuf))
2110Sstevel@tonic-gate 			cursor = lastchr(linebuf, cursor);
2120Sstevel@tonic-gate 		vfixcurs();
2130Sstevel@tonic-gate 		break;
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	case VNONE:
2160Sstevel@tonic-gate 		beep();
2170Sstevel@tonic-gate 		break;
2180Sstevel@tonic-gate 	}
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate /*
2220Sstevel@tonic-gate  * Routine to handle a change inside a macro.
2230Sstevel@tonic-gate  * Fromvis is true if we were called from a visual command (as
2240Sstevel@tonic-gate  * opposed to an ex command).  This has nothing to do with being
2250Sstevel@tonic-gate  * in open/visual mode as :s/foo/bar is not fromvis.
2260Sstevel@tonic-gate  */
2270Sstevel@tonic-gate vmacchng(fromvis)
2280Sstevel@tonic-gate bool fromvis;
2290Sstevel@tonic-gate {
2300Sstevel@tonic-gate 	line *savedot, *savedol;
2310Sstevel@tonic-gate 	unsigned char *savecursor;
2320Sstevel@tonic-gate 	unsigned char savelb[LBSIZE];
2330Sstevel@tonic-gate 	int nlines, more;
2340Sstevel@tonic-gate 	register line *a1, *a2;
2350Sstevel@tonic-gate 	unsigned char ch;	/* DEBUG */
2360Sstevel@tonic-gate 	int copyw(), copywR();
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	if (!inopen)
2390Sstevel@tonic-gate 		return;
2400Sstevel@tonic-gate 	if (!vmacp)
2410Sstevel@tonic-gate 		vch_mac = VC_NOTINMAC;
2420Sstevel@tonic-gate #ifdef UNDOTRACE
2430Sstevel@tonic-gate 	if (trace)
2440Sstevel@tonic-gate 		fprintf(trace, "vmacchng, vch_mac=%d, linebuf='%s', *dot=%o\n", vch_mac, linebuf, *dot);
2450Sstevel@tonic-gate #endif
2460Sstevel@tonic-gate 	if (vmacp && fromvis)
2470Sstevel@tonic-gate 		vsave();
2480Sstevel@tonic-gate #ifdef UNDOTRACE
2490Sstevel@tonic-gate 	if (trace)
2500Sstevel@tonic-gate 		fprintf(trace, "after vsave, linebuf='%s', *dot=%o\n", linebuf, *dot);
2510Sstevel@tonic-gate #endif
2520Sstevel@tonic-gate 	switch(vch_mac) {
2530Sstevel@tonic-gate 	case VC_NOCHANGE:
2540Sstevel@tonic-gate 		vch_mac = VC_ONECHANGE;
2550Sstevel@tonic-gate 		break;
2560Sstevel@tonic-gate 	case VC_ONECHANGE:
2570Sstevel@tonic-gate 		/* Save current state somewhere */
2580Sstevel@tonic-gate #ifdef UNDOTRACE
2590Sstevel@tonic-gate 		vudump("before vmacchng hairy case");
2600Sstevel@tonic-gate #endif
2610Sstevel@tonic-gate 		savedot = dot; savedol = dol; savecursor = cursor;
2620Sstevel@tonic-gate 		CP(savelb, linebuf);
2630Sstevel@tonic-gate 		nlines = dol - zero;
2640Sstevel@tonic-gate 		while ((line *) endcore - truedol < nlines)
2650Sstevel@tonic-gate 			if (morelines() < 0)
2660Sstevel@tonic-gate 				return;	/* or could be fatal error */
2670Sstevel@tonic-gate 		copyw(truedol+1, zero+1, nlines);
2680Sstevel@tonic-gate 		truedol += nlines;
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate #ifdef UNDOTRACE
2710Sstevel@tonic-gate 		visdump("before vundo");
2720Sstevel@tonic-gate #endif
2730Sstevel@tonic-gate 		/* Restore state as it was at beginning of macro */
2740Sstevel@tonic-gate 		vundo(0);
2750Sstevel@tonic-gate #ifdef UNDOTRACE
2760Sstevel@tonic-gate 		visdump("after vundo");
2770Sstevel@tonic-gate 		vudump("after vundo");
2780Sstevel@tonic-gate #endif
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 		/* Do the saveall we should have done then */
2810Sstevel@tonic-gate 		saveall();
2820Sstevel@tonic-gate #ifdef UNDOTRACE
2830Sstevel@tonic-gate 		vudump("after saveall");
2840Sstevel@tonic-gate #endif
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 		/* Restore current state from where saved */
2870Sstevel@tonic-gate 		more = savedol - dol; /* amount we shift everything by */
2880Sstevel@tonic-gate 		if (more)
2890Sstevel@tonic-gate 			(*(more>0 ? copywR : copyw))(savedol+1, dol+1, truedol-dol);
2900Sstevel@tonic-gate 		unddol += more; truedol += more; undap2 += more;
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 		truedol -= nlines;
2930Sstevel@tonic-gate 		copyw(zero+1, truedol+1, nlines);
2940Sstevel@tonic-gate 		dot = savedot; dol = savedol ; cursor = savecursor;
2950Sstevel@tonic-gate 		CP(linebuf, savelb);
2960Sstevel@tonic-gate 		vch_mac = VC_MANYCHANGE;
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 		/* Arrange that no further undo saving happens within macro */
2990Sstevel@tonic-gate 		otchng = tchng;	/* Copied this line blindly - bug? */
3000Sstevel@tonic-gate 		inopen = -1;	/* no need to save since it had to be 1 or -1 before */
3010Sstevel@tonic-gate 		vundkind = VMANY;
3020Sstevel@tonic-gate #ifdef UNDOTRACE
3030Sstevel@tonic-gate 		vudump("after vmacchng");
3040Sstevel@tonic-gate #endif
3050Sstevel@tonic-gate 		break;
3060Sstevel@tonic-gate 	case VC_NOTINMAC:
3070Sstevel@tonic-gate 	case VC_MANYCHANGE:
3080Sstevel@tonic-gate 		/* Nothing to do for various reasons. */
3090Sstevel@tonic-gate 		break;
3100Sstevel@tonic-gate 	}
3110Sstevel@tonic-gate }
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate /*
3140Sstevel@tonic-gate  * Initialize undo information before an append.
3150Sstevel@tonic-gate  */
3160Sstevel@tonic-gate vnoapp()
3170Sstevel@tonic-gate {
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	vUD1 = vUD2 = cursor;
3200Sstevel@tonic-gate }
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate /*
3230Sstevel@tonic-gate  * All the rest of the motion sequences have one or more
3240Sstevel@tonic-gate  * cases to deal with.  In the case wdot == 0, operation
3250Sstevel@tonic-gate  * is totally within current line, from cursor to wcursor.
3260Sstevel@tonic-gate  * If wdot is given, but wcursor is 0, then operation affects
3270Sstevel@tonic-gate  * the inclusive line range.  The hardest case is when both wdot
3280Sstevel@tonic-gate  * and wcursor are given, then operation affects from line dot at
3290Sstevel@tonic-gate  * cursor to line wdot at wcursor.
3300Sstevel@tonic-gate  */
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate /*
3330Sstevel@tonic-gate  * Move is simple, except for moving onto new lines in hardcopy open mode.
3340Sstevel@tonic-gate  */
3350Sstevel@tonic-gate vmove()
3360Sstevel@tonic-gate {
3370Sstevel@tonic-gate 	register int cnt;
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	if (wdot) {
3400Sstevel@tonic-gate 		if (wdot < one || wdot > dol) {
3410Sstevel@tonic-gate 			beep();
3420Sstevel@tonic-gate 			return;
3430Sstevel@tonic-gate 		}
3440Sstevel@tonic-gate 		cnt = wdot - dot;
3450Sstevel@tonic-gate 		wdot = NOLINE;
3460Sstevel@tonic-gate 		if (cnt)
3470Sstevel@tonic-gate 			killU();
3480Sstevel@tonic-gate 		vupdown(cnt, wcursor);
3490Sstevel@tonic-gate 		return;
3500Sstevel@tonic-gate 	}
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	/*
3530Sstevel@tonic-gate 	 * When we move onto a new line, save information for U undo.
3540Sstevel@tonic-gate 	 */
3550Sstevel@tonic-gate 	if (vUNDdot != dot) {
3560Sstevel@tonic-gate 		vUNDsav = *dot;
3570Sstevel@tonic-gate 		vUNDcurs = wcursor;
3580Sstevel@tonic-gate 		vUNDdot = dot;
3590Sstevel@tonic-gate 	}
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 	/*
3620Sstevel@tonic-gate 	 * In hardcopy open, type characters to left of cursor
3630Sstevel@tonic-gate 	 * on new line, or back cursor up if its to left of where we are.
3640Sstevel@tonic-gate 	 * In any case if the current line is ``rubbled'' i.e. has trashy
3650Sstevel@tonic-gate 	 * looking overstrikes on it or \'s from deletes, we reprint
3660Sstevel@tonic-gate 	 * so it is more comprehensible (and also because we can't work
3670Sstevel@tonic-gate 	 * if we let it get more out of sync since column() won't work right.
3680Sstevel@tonic-gate 	 */
3690Sstevel@tonic-gate 	if (state == HARDOPEN) {
3700Sstevel@tonic-gate 		register unsigned char *cp;
3710Sstevel@tonic-gate 		if (rubble) {
3720Sstevel@tonic-gate 			register int c;
3730Sstevel@tonic-gate 			int oldhold = hold;
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 			sethard();
3760Sstevel@tonic-gate 			cp = wcursor;
3770Sstevel@tonic-gate 			c = *cp;
3780Sstevel@tonic-gate 			*cp = 0;
3790Sstevel@tonic-gate 			hold |= HOLDDOL;
3800Sstevel@tonic-gate 			vreopen(WTOP, lineDOT(), vcline);
3810Sstevel@tonic-gate 			hold = oldhold;
3820Sstevel@tonic-gate 			*cp = c;
3830Sstevel@tonic-gate 		} else if (wcursor > cursor) {
3840Sstevel@tonic-gate 			register int length;
3850Sstevel@tonic-gate 			char multic[MULTI_BYTE_MAX];
3860Sstevel@tonic-gate 			wchar_t wchar;
3870Sstevel@tonic-gate 			vfixcurs();
3880Sstevel@tonic-gate 			for (cp = cursor; *cp && cp < wcursor;) {
3890Sstevel@tonic-gate 				length = mbtowc(&wchar, (char *)cp, MULTI_BYTE_MAX);
3900Sstevel@tonic-gate 				if(length == 0)
3910Sstevel@tonic-gate 					putchar(' ');
3920Sstevel@tonic-gate 				else if(length < 0) {
3930Sstevel@tonic-gate 					putoctal = 1;
3940Sstevel@tonic-gate 					putchar(*cp++);
3950Sstevel@tonic-gate 					putoctal = 0;
3960Sstevel@tonic-gate 				} else {
3970Sstevel@tonic-gate 					cp += length;
3980Sstevel@tonic-gate 					putchar(wchar);
3990Sstevel@tonic-gate 				}
4000Sstevel@tonic-gate 			}
4010Sstevel@tonic-gate 		}
4020Sstevel@tonic-gate 	}
4030Sstevel@tonic-gate 	vsetcurs(wcursor);
4040Sstevel@tonic-gate }
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate /*
4070Sstevel@tonic-gate  * Delete operator.
4080Sstevel@tonic-gate  *
4090Sstevel@tonic-gate  * Hard case of deleting a range where both wcursor and wdot
4100Sstevel@tonic-gate  * are specified is treated as a special case of change and handled
4110Sstevel@tonic-gate  * by vchange (although vchange may pass it back if it degenerates
4120Sstevel@tonic-gate  * to a full line range delete.)
4130Sstevel@tonic-gate  */
4140Sstevel@tonic-gate vdelete(c)
4150Sstevel@tonic-gate 	unsigned char c;
4160Sstevel@tonic-gate {
4170Sstevel@tonic-gate 	register unsigned char *cp;
4180Sstevel@tonic-gate 	register int i;
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	if (wdot) {
4210Sstevel@tonic-gate 		if (wcursor) {
4220Sstevel@tonic-gate 			vchange('d');
4230Sstevel@tonic-gate 			return;
4240Sstevel@tonic-gate 		}
4250Sstevel@tonic-gate 		if ((i = xdw()) < 0)
4260Sstevel@tonic-gate 			return;
4270Sstevel@tonic-gate 		if (state != VISUAL) {
4280Sstevel@tonic-gate 			vgoto(LINE(0), 0);
4290Sstevel@tonic-gate 			vputchar('@');
4300Sstevel@tonic-gate 		}
4310Sstevel@tonic-gate 		wdot = dot;
4320Sstevel@tonic-gate 		vremote(i, delete, 0);
4330Sstevel@tonic-gate 		notenam = (unsigned char *)"delete";
4340Sstevel@tonic-gate 		DEL[0] = 0;
4350Sstevel@tonic-gate 		killU();
4360Sstevel@tonic-gate 		vreplace(vcline, i, 0);
4370Sstevel@tonic-gate 		if (wdot > dol)
4380Sstevel@tonic-gate 			vcline--;
4390Sstevel@tonic-gate 		vrepaint(NOSTR);
4400Sstevel@tonic-gate 		return;
4410Sstevel@tonic-gate 	}
4420Sstevel@tonic-gate 	if (wcursor < linebuf)
4430Sstevel@tonic-gate 		wcursor = linebuf;
4440Sstevel@tonic-gate 	if (cursor == wcursor) {
4450Sstevel@tonic-gate 		beep();
4460Sstevel@tonic-gate 		return;
4470Sstevel@tonic-gate 	}
4480Sstevel@tonic-gate 	i = vdcMID();
4490Sstevel@tonic-gate 	cp = cursor;
4500Sstevel@tonic-gate 	setDEL();
4510Sstevel@tonic-gate 	CP(cp, wcursor);
4520Sstevel@tonic-gate 	if (cp > linebuf && (cp[0] == 0 || c == '#'))
4530Sstevel@tonic-gate 		cp = lastchr(linebuf, cp);
4540Sstevel@tonic-gate 	if (state == HARDOPEN) {
4550Sstevel@tonic-gate 		bleep(i, cp);
4560Sstevel@tonic-gate 		cursor = cp;
4570Sstevel@tonic-gate 		return;
4580Sstevel@tonic-gate 	}
4590Sstevel@tonic-gate 	physdc(lcolumn(cursor), i);
4600Sstevel@tonic-gate 	DEPTH(vcline) = 0;
4610Sstevel@tonic-gate 	if(MB_CUR_MAX > 1)
4620Sstevel@tonic-gate 		rewrite = _ON;
4630Sstevel@tonic-gate 	vreopen(LINE(vcline), lineDOT(), vcline);
4640Sstevel@tonic-gate 	if(MB_CUR_MAX > 1)
4650Sstevel@tonic-gate 		rewrite = _OFF;
4660Sstevel@tonic-gate 	vsyncCL();
4670Sstevel@tonic-gate 	vsetcurs(cp);
4680Sstevel@tonic-gate }
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate /*
4710Sstevel@tonic-gate  * Change operator.
4720Sstevel@tonic-gate  *
4730Sstevel@tonic-gate  * In a single line we mark the end of the changed area with '$'.
4740Sstevel@tonic-gate  * On multiple whole lines, we clear the lines first.
4750Sstevel@tonic-gate  * Across lines with both wcursor and wdot given, we delete
4760Sstevel@tonic-gate  * and sync then append (but one operation for undo).
4770Sstevel@tonic-gate  */
4780Sstevel@tonic-gate vchange(c)
4790Sstevel@tonic-gate 	unsigned char c;
4800Sstevel@tonic-gate {
4810Sstevel@tonic-gate 	register unsigned char *cp;
4820Sstevel@tonic-gate 	register int i, ind, cnt;
4830Sstevel@tonic-gate 	line *addr;
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	if (wdot) {
4860Sstevel@tonic-gate 		/*
4870Sstevel@tonic-gate 		 * Change/delete of lines or across line boundaries.
4880Sstevel@tonic-gate 		 */
4890Sstevel@tonic-gate 		if ((cnt = xdw()) < 0)
4900Sstevel@tonic-gate 			return;
4910Sstevel@tonic-gate 		getDOT();
4920Sstevel@tonic-gate 		if (wcursor && cnt == 1) {
4930Sstevel@tonic-gate 			/*
4940Sstevel@tonic-gate 			 * Not really.
4950Sstevel@tonic-gate 			 */
4960Sstevel@tonic-gate 			wdot = 0;
4970Sstevel@tonic-gate 			if (c == 'd') {
4980Sstevel@tonic-gate 				vdelete(c);
4990Sstevel@tonic-gate 				return;
5000Sstevel@tonic-gate 			}
5010Sstevel@tonic-gate 			goto smallchange;
5020Sstevel@tonic-gate 		}
5030Sstevel@tonic-gate 		if (cursor && wcursor) {
5040Sstevel@tonic-gate 			/*
5050Sstevel@tonic-gate 			 * Across line boundaries, but not
5060Sstevel@tonic-gate 			 * necessarily whole lines.
5070Sstevel@tonic-gate 			 * Construct what will be left.
5080Sstevel@tonic-gate 			 */
5090Sstevel@tonic-gate 			*cursor = 0;
5100Sstevel@tonic-gate 			strcpy(genbuf, linebuf);
5110Sstevel@tonic-gate 			getline(*wdot);
5120Sstevel@tonic-gate 			if (strlen(genbuf) + strlen(wcursor) > LBSIZE - 2) {
5130Sstevel@tonic-gate 				getDOT();
5140Sstevel@tonic-gate 				beep();
5150Sstevel@tonic-gate 				return;
5160Sstevel@tonic-gate 			}
5170Sstevel@tonic-gate 			strcat(genbuf, wcursor);
5180Sstevel@tonic-gate 			if (c == 'd' && *vpastwh(genbuf) == 0) {
5190Sstevel@tonic-gate 				/*
5200Sstevel@tonic-gate 				 * Although this is a delete
5210Sstevel@tonic-gate 				 * spanning line boundaries, what
5220Sstevel@tonic-gate 				 * would be left is all white space,
5230Sstevel@tonic-gate 				 * so take it all away.
5240Sstevel@tonic-gate 				 */
5250Sstevel@tonic-gate 				wcursor = 0;
5260Sstevel@tonic-gate 				getDOT();
5270Sstevel@tonic-gate 				op = 0;
5280Sstevel@tonic-gate 				notpart(lastreg);
5290Sstevel@tonic-gate 				notpart('1');
5300Sstevel@tonic-gate 				vdelete(c);
5310Sstevel@tonic-gate 				return;
5320Sstevel@tonic-gate 			}
5330Sstevel@tonic-gate 			ind = -1;
5340Sstevel@tonic-gate 		} else if (c == 'd' && wcursor == 0) {
5350Sstevel@tonic-gate 			vdelete(c);
5360Sstevel@tonic-gate 			return;
5370Sstevel@tonic-gate 		} else
5380Sstevel@tonic-gate 			/*
5390Sstevel@tonic-gate 			 * We are just substituting text for whole lines,
5400Sstevel@tonic-gate 			 * so determine the first autoindent.
5410Sstevel@tonic-gate 			 */
5420Sstevel@tonic-gate 			if (value(vi_LISP) && value(vi_AUTOINDENT))
5430Sstevel@tonic-gate 				ind = lindent(dot);
5440Sstevel@tonic-gate 			else
5450Sstevel@tonic-gate 				ind = whitecnt(linebuf);
5460Sstevel@tonic-gate 		i = vcline >= 0 ? LINE(vcline) : WTOP;
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 		/*
5490Sstevel@tonic-gate 		 * Delete the lines from the buffer,
5500Sstevel@tonic-gate 		 * and remember how the partial stuff came about in
5510Sstevel@tonic-gate 		 * case we are told to put.
5520Sstevel@tonic-gate 		 */
5530Sstevel@tonic-gate 		addr = dot;
5540Sstevel@tonic-gate 		vremote(cnt, delete, 0);
5550Sstevel@tonic-gate 		setpk();
5560Sstevel@tonic-gate 		notenam = (unsigned char *)"delete";
5570Sstevel@tonic-gate 		if (c != 'd')
5580Sstevel@tonic-gate 			notenam = (unsigned char *)"change";
5590Sstevel@tonic-gate 		/*
5600Sstevel@tonic-gate 		 * If DEL[0] were nonzero, put would put it back
5610Sstevel@tonic-gate 		 * rather than the deleted lines.
5620Sstevel@tonic-gate 		 */
5630Sstevel@tonic-gate 		DEL[0] = 0;
5640Sstevel@tonic-gate 		if (cnt > 1)
5650Sstevel@tonic-gate 			killU();
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 		/*
5680Sstevel@tonic-gate 		 * Now hack the screen image coordination.
5690Sstevel@tonic-gate 		 */
5700Sstevel@tonic-gate 		vreplace(vcline, cnt, 0);
5710Sstevel@tonic-gate 		wdot = NOLINE;
5720Sstevel@tonic-gate 		noteit(0);
5730Sstevel@tonic-gate 		vcline--;
5740Sstevel@tonic-gate 		if (addr <= dol)
5750Sstevel@tonic-gate 			dot--;
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 		/*
5780Sstevel@tonic-gate 		 * If this is a across line delete/change,
5790Sstevel@tonic-gate 		 * cursor stays where it is; just splice together the pieces
5800Sstevel@tonic-gate 		 * of the new line.  Otherwise generate a autoindent
5810Sstevel@tonic-gate 		 * after a S command.
5820Sstevel@tonic-gate 		 */
5830Sstevel@tonic-gate 		if (ind >= 0) {
5840Sstevel@tonic-gate 			*genindent(ind) = 0;
5850Sstevel@tonic-gate 			vdoappend(genbuf);
5860Sstevel@tonic-gate 		} else {
5870Sstevel@tonic-gate 			vmcurs = cursor;
5880Sstevel@tonic-gate 			strcLIN(genbuf);
5890Sstevel@tonic-gate 			vdoappend(linebuf);
5900Sstevel@tonic-gate 		}
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 		/*
5930Sstevel@tonic-gate 		 * Indicate a change on hardcopies by
5940Sstevel@tonic-gate 		 * erasing the current line.
5950Sstevel@tonic-gate 		 */
5960Sstevel@tonic-gate 		if (c != 'd' && state != VISUAL && state != HARDOPEN) {
5970Sstevel@tonic-gate 			int oldhold = hold;
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 			hold |= HOLDAT, vclrlin(i, dot), hold = oldhold;
6000Sstevel@tonic-gate 		}
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 		/*
6030Sstevel@tonic-gate 		 * Open the line (logically) on the screen, and
6040Sstevel@tonic-gate 		 * update the screen tail.  Unless we are really a delete
6050Sstevel@tonic-gate 		 * go off and gather up inserted characters.
6060Sstevel@tonic-gate 		 */
6070Sstevel@tonic-gate 		vcline++;
6080Sstevel@tonic-gate 		if (vcline < 0)
6090Sstevel@tonic-gate 			vcline = 0;
6100Sstevel@tonic-gate 		vopen(dot, i);
6110Sstevel@tonic-gate 		vsyncCL();
6120Sstevel@tonic-gate 		noteit(1);
6130Sstevel@tonic-gate 		if (c != 'd') {
6140Sstevel@tonic-gate 			if (ind >= 0) {
6150Sstevel@tonic-gate 				cursor = linebuf;
6160Sstevel@tonic-gate 				linebuf[0] = 0;
6170Sstevel@tonic-gate 				vfixcurs();
6180Sstevel@tonic-gate 			} else {
6190Sstevel@tonic-gate 				ind = 0;
6200Sstevel@tonic-gate 				vcursat(cursor);
6210Sstevel@tonic-gate 			}
6220Sstevel@tonic-gate 			vappend('x', 1, ind);
6230Sstevel@tonic-gate 			return;
6240Sstevel@tonic-gate 		}
6250Sstevel@tonic-gate 		if (*cursor == 0 && cursor > linebuf)
6260Sstevel@tonic-gate 			cursor = lastchr(linebuf, cursor);
6270Sstevel@tonic-gate 		vrepaint(cursor);
6280Sstevel@tonic-gate 		return;
6290Sstevel@tonic-gate 	}
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate smallchange:
6320Sstevel@tonic-gate 	/*
6330Sstevel@tonic-gate 	 * The rest of this is just low level hacking on changes
6340Sstevel@tonic-gate 	 * of small numbers of characters.
6350Sstevel@tonic-gate 	 */
6360Sstevel@tonic-gate 	if (wcursor < linebuf)
6370Sstevel@tonic-gate 		wcursor = linebuf;
6380Sstevel@tonic-gate 	if (cursor == wcursor) {
6390Sstevel@tonic-gate 		beep();
6400Sstevel@tonic-gate 		return;
6410Sstevel@tonic-gate 	}
6420Sstevel@tonic-gate 	i = vdcMID();
6430Sstevel@tonic-gate 	cp = cursor;
6440Sstevel@tonic-gate 	if (state != HARDOPEN)
6450Sstevel@tonic-gate 		vfixcurs();
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 	/*
6480Sstevel@tonic-gate 	 * Put out the \\'s indicating changed text in hardcopy,
6490Sstevel@tonic-gate 	 * or mark the end of the change with $ if not hardcopy.
6500Sstevel@tonic-gate 	 */
6510Sstevel@tonic-gate 	if (state == HARDOPEN)
6520Sstevel@tonic-gate 		bleep(i, cp);
6530Sstevel@tonic-gate 	else {
6540Sstevel@tonic-gate 		vcursbef(wcursor);
6550Sstevel@tonic-gate 		putchar('$');
6560Sstevel@tonic-gate 		i = cindent();
6570Sstevel@tonic-gate 	}
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 	/*
6600Sstevel@tonic-gate 	 * Remember the deleted text for possible put,
6610Sstevel@tonic-gate 	 * and then prepare and execute the input portion of the change.
6620Sstevel@tonic-gate 	 */
6630Sstevel@tonic-gate 	cursor = cp;
6640Sstevel@tonic-gate 	setDEL();
6650Sstevel@tonic-gate 	CP(cursor, wcursor);
6660Sstevel@tonic-gate 	if (state != HARDOPEN) {
6670Sstevel@tonic-gate 		/* place cursor at beginning of changing text */
6680Sstevel@tonic-gate 		vgotoCL(lcolumn(cp));
6690Sstevel@tonic-gate 		doomed = i - cindent();
6700Sstevel@tonic-gate 	} else {
6710Sstevel@tonic-gate /*
6720Sstevel@tonic-gate 		sethard();
6730Sstevel@tonic-gate 		wcursor = cursor;
6740Sstevel@tonic-gate 		cursor = linebuf;
6750Sstevel@tonic-gate 		vgoto(outline, value(vi_NUMBER) << 3);
6760Sstevel@tonic-gate 		vmove();
6770Sstevel@tonic-gate */
6780Sstevel@tonic-gate 		doomed = 0;
6790Sstevel@tonic-gate 	}
6800Sstevel@tonic-gate 	prepapp();
6810Sstevel@tonic-gate 	vappend('c', 1, 0);
6820Sstevel@tonic-gate }
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate /*
6850Sstevel@tonic-gate  * Open new lines.
6860Sstevel@tonic-gate  *
6870Sstevel@tonic-gate  * Tricky thing here is slowopen.  This causes display updating
6880Sstevel@tonic-gate  * to be held off so that 300 baud dumb terminals don't lose badly.
6890Sstevel@tonic-gate  * This also suppressed counts, which otherwise say how many blank
6900Sstevel@tonic-gate  * space to open up.  Counts are also suppressed on intelligent terminals.
6910Sstevel@tonic-gate  * Actually counts are obsoleted, since if your terminal is slow
6920Sstevel@tonic-gate  * you are better off with slowopen.
6930Sstevel@tonic-gate  */
6940Sstevel@tonic-gate voOpen(c, cnt)
6950Sstevel@tonic-gate 	int c;	/* mjm: char --> int */
6960Sstevel@tonic-gate 	register int cnt;
6970Sstevel@tonic-gate {
6980Sstevel@tonic-gate 	register int ind = 0, i;
6990Sstevel@tonic-gate 	short oldhold = hold;
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 	if (value(vi_SLOWOPEN) || value(vi_REDRAW) && insert_line && delete_line)
7020Sstevel@tonic-gate 		cnt = 1;
7030Sstevel@tonic-gate 	vsave();
7040Sstevel@tonic-gate 	setLAST();
7050Sstevel@tonic-gate 	if (value(vi_AUTOINDENT))
7060Sstevel@tonic-gate 		ind = whitecnt(linebuf);
7070Sstevel@tonic-gate 	if (c == 'O') {
7080Sstevel@tonic-gate 		vcline--;
7090Sstevel@tonic-gate 		dot--;
7100Sstevel@tonic-gate 		if (dot > zero)
7110Sstevel@tonic-gate 			getDOT();
7120Sstevel@tonic-gate 	}
7130Sstevel@tonic-gate 	if (value(vi_AUTOINDENT)) {
7140Sstevel@tonic-gate 		if (value(vi_LISP))
7150Sstevel@tonic-gate 			ind = lindent(dot + 1);
7160Sstevel@tonic-gate 	}
7170Sstevel@tonic-gate 	killU();
7180Sstevel@tonic-gate 	prepapp();
7190Sstevel@tonic-gate 	if (FIXUNDO)
7200Sstevel@tonic-gate 		vundkind = VMANY;
7210Sstevel@tonic-gate 	if (state != VISUAL)
7220Sstevel@tonic-gate 		c = WBOT + 1;
7230Sstevel@tonic-gate 	else {
7240Sstevel@tonic-gate 		c = vcline < 0 ? WTOP - cnt : LINE(vcline) + DEPTH(vcline);
7250Sstevel@tonic-gate 		if (c < ZERO)
7260Sstevel@tonic-gate 			c = ZERO;
7270Sstevel@tonic-gate 		i = LINE(vcline + 1) - c;
7280Sstevel@tonic-gate 		if (i < cnt && c <= WBOT && (!insert_line || !delete_line))
7290Sstevel@tonic-gate 			vinslin(c, cnt - i, vcline);
7300Sstevel@tonic-gate 	}
7310Sstevel@tonic-gate 	*genindent(ind) = 0;
7320Sstevel@tonic-gate 	vdoappend(genbuf);
7330Sstevel@tonic-gate 	vcline++;
7340Sstevel@tonic-gate 	oldhold = hold;
7350Sstevel@tonic-gate 	hold |= HOLDROL;
7360Sstevel@tonic-gate 	vopen(dot, c);
7370Sstevel@tonic-gate 	hold = oldhold;
7380Sstevel@tonic-gate 	if (value(vi_SLOWOPEN))
7390Sstevel@tonic-gate 		/*
7400Sstevel@tonic-gate 		 * Oh, so lazy!
7410Sstevel@tonic-gate 		 */
7420Sstevel@tonic-gate 		vscrap();
7430Sstevel@tonic-gate 	else
7440Sstevel@tonic-gate 		vsync1(LINE(vcline));
7450Sstevel@tonic-gate 	cursor = linebuf;
7460Sstevel@tonic-gate 	linebuf[0] = 0;
7470Sstevel@tonic-gate 	vappend('o', 1, ind);
7480Sstevel@tonic-gate }
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate /*
7510Sstevel@tonic-gate  * > < and = shift operators.
7520Sstevel@tonic-gate  *
7530Sstevel@tonic-gate  * Note that =, which aligns lisp, is just a ragged sort of shift,
7540Sstevel@tonic-gate  * since it never distributes text between lines.
7550Sstevel@tonic-gate  */
7560Sstevel@tonic-gate unsigned char	vshnam[2] = { 'x', 0 };
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate vshftop()
7590Sstevel@tonic-gate {
7600Sstevel@tonic-gate 	register line *addr;
7610Sstevel@tonic-gate 	register int cnt;
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	if ((cnt = xdw()) < 0)
7640Sstevel@tonic-gate 		return;
7650Sstevel@tonic-gate 	addr = dot;
7660Sstevel@tonic-gate 	vremote(cnt, vshift, 0);
7670Sstevel@tonic-gate 	vshnam[0] = op;
7680Sstevel@tonic-gate 	notenam = vshnam;
7690Sstevel@tonic-gate 	dot = addr;
7700Sstevel@tonic-gate 	vreplace(vcline, cnt, cnt);
7710Sstevel@tonic-gate 	if (state == HARDOPEN)
7720Sstevel@tonic-gate 		vcnt = 0;
7730Sstevel@tonic-gate 	vrepaint(NOSTR);
7740Sstevel@tonic-gate }
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate /*
7770Sstevel@tonic-gate  * !.
7780Sstevel@tonic-gate  *
7790Sstevel@tonic-gate  * Filter portions of the buffer through unix commands.
7800Sstevel@tonic-gate  */
7810Sstevel@tonic-gate vfilter()
7820Sstevel@tonic-gate {
7830Sstevel@tonic-gate 	register line *addr;
7840Sstevel@tonic-gate 	register int cnt;
7850Sstevel@tonic-gate 	unsigned char *oglobp;
7860Sstevel@tonic-gate 	short d;
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 	if ((cnt = xdw()) < 0)
7890Sstevel@tonic-gate 		return;
7900Sstevel@tonic-gate 	if (vglobp)
7910Sstevel@tonic-gate 		vglobp = (unsigned char *)uxb;
7920Sstevel@tonic-gate 	if (readecho('!'))
7930Sstevel@tonic-gate 		return;
7940Sstevel@tonic-gate 	oglobp = globp; globp = genbuf + 1;
7950Sstevel@tonic-gate 	d = peekc; ungetchar(0);
7960Sstevel@tonic-gate 	CATCH
7970Sstevel@tonic-gate 		fixech();
798*500Sceastha 		unix0(0, 0);
7990Sstevel@tonic-gate 	ONERR
8000Sstevel@tonic-gate 		splitw = 0;
8010Sstevel@tonic-gate 		ungetchar(d);
8020Sstevel@tonic-gate 		vrepaint(cursor);
8030Sstevel@tonic-gate 		globp = oglobp;
8040Sstevel@tonic-gate 		return;
8050Sstevel@tonic-gate 	ENDCATCH
8060Sstevel@tonic-gate 	ungetchar(d); globp = oglobp;
8070Sstevel@tonic-gate 	addr = dot;
8080Sstevel@tonic-gate 	CATCH
8090Sstevel@tonic-gate 		vgoto(WECHO, 0); flusho();
8100Sstevel@tonic-gate 		vremote(cnt, vi_filter, 2);
8110Sstevel@tonic-gate 	ONERR
8120Sstevel@tonic-gate 		vdirty(0, lines);
8130Sstevel@tonic-gate 	ENDCATCH
8140Sstevel@tonic-gate 	if (dot == zero && dol > zero)
8150Sstevel@tonic-gate 		dot = one;
8160Sstevel@tonic-gate 	splitw = 0;
8170Sstevel@tonic-gate 	notenam = (unsigned char *)"";
8180Sstevel@tonic-gate 	/*
8190Sstevel@tonic-gate 	 * BUG: we shouldn't be depending on what undap2 and undap1 are,
8200Sstevel@tonic-gate 	 * since we may be inside a macro.  What's really wanted is the
8210Sstevel@tonic-gate 	 * number of lines we read from the filter.  However, the mistake
8220Sstevel@tonic-gate 	 * will be an overestimate so it only results in extra work,
8230Sstevel@tonic-gate 	 * it shouldn't cause any real mess-ups.
8240Sstevel@tonic-gate 	 */
8250Sstevel@tonic-gate 	vreplace(vcline, cnt, undap2 - undap1);
8260Sstevel@tonic-gate 	dot = addr;
8270Sstevel@tonic-gate 	if (dot > dol) {
8280Sstevel@tonic-gate 		dot--;
8290Sstevel@tonic-gate 		vcline--;
8300Sstevel@tonic-gate 	}
8310Sstevel@tonic-gate 	vrepaint(NOSTR);
8320Sstevel@tonic-gate }
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate /*
8350Sstevel@tonic-gate  * Xdw exchanges dot and wdot if appropriate and also checks
8360Sstevel@tonic-gate  * that wdot is reasonable.  Its name comes from
8370Sstevel@tonic-gate  *	xchange dotand wdot
8380Sstevel@tonic-gate  */
8390Sstevel@tonic-gate xdw()
8400Sstevel@tonic-gate {
8410Sstevel@tonic-gate 	register unsigned char *cp;
8420Sstevel@tonic-gate 	register int cnt;
8430Sstevel@tonic-gate /*
8440Sstevel@tonic-gate 	register int notp = 0;
8450Sstevel@tonic-gate  */
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 	if (wdot == NOLINE || wdot < one || wdot > dol) {
8480Sstevel@tonic-gate 		beep();
8490Sstevel@tonic-gate 		return (-1);
8500Sstevel@tonic-gate 	}
8510Sstevel@tonic-gate 	vsave();
8520Sstevel@tonic-gate 	setLAST();
8530Sstevel@tonic-gate 	if (dot > wdot || (dot == wdot && wcursor != 0 && cursor > wcursor)) {
8540Sstevel@tonic-gate 		register line *addr;
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate 		vcline -= dot - wdot;
8570Sstevel@tonic-gate 		addr = dot; dot = wdot; wdot = addr;
8580Sstevel@tonic-gate 		cp = cursor; cursor = wcursor; wcursor = cp;
8590Sstevel@tonic-gate 	}
8600Sstevel@tonic-gate 	/*
8610Sstevel@tonic-gate 	 * If a region is specified but wcursor is at the beginning
8620Sstevel@tonic-gate 	 * of the last line, then we move it to be the end of the
8630Sstevel@tonic-gate 	 * previous line (actually off the end).
8640Sstevel@tonic-gate 	 */
8650Sstevel@tonic-gate 	if (cursor && wcursor == linebuf && wdot > dot) {
8660Sstevel@tonic-gate 		wdot--;
8670Sstevel@tonic-gate 		getDOT();
8680Sstevel@tonic-gate 		if (vpastwh(linebuf) >= cursor)
8690Sstevel@tonic-gate 			wcursor = 0;
8700Sstevel@tonic-gate 		else {
8710Sstevel@tonic-gate 			getline(*wdot);
8720Sstevel@tonic-gate 			wcursor = strend(linebuf);
8730Sstevel@tonic-gate 			getDOT();
8740Sstevel@tonic-gate 		}
8750Sstevel@tonic-gate 		/*
8760Sstevel@tonic-gate 		 * Should prepare in caller for possible dot == wdot.
8770Sstevel@tonic-gate 		 */
8780Sstevel@tonic-gate 	}
8790Sstevel@tonic-gate 	cnt = wdot - dot + 1;
8800Sstevel@tonic-gate 	if (vreg) {
8810Sstevel@tonic-gate 		vremote(cnt, YANKreg, vreg);
8820Sstevel@tonic-gate /*
8830Sstevel@tonic-gate 		if (notp)
8840Sstevel@tonic-gate 			notpart(vreg);
8850Sstevel@tonic-gate  */
8860Sstevel@tonic-gate 	}
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 	/*
8890Sstevel@tonic-gate 	 * Kill buffer code.  If delete operator is c or d, then save
8900Sstevel@tonic-gate 	 * the region in numbered buffers.
8910Sstevel@tonic-gate 	 *
8920Sstevel@tonic-gate 	 * BUG:			This may be somewhat inefficient due
8930Sstevel@tonic-gate 	 *			to the way named buffer are implemented,
8940Sstevel@tonic-gate 	 *			necessitating some optimization.
8950Sstevel@tonic-gate 	 */
8960Sstevel@tonic-gate 	vreg = 0;
8970Sstevel@tonic-gate 	if (any(op, "cd")) {
8980Sstevel@tonic-gate 		vremote(cnt, YANKreg, '1');
8990Sstevel@tonic-gate /*
9000Sstevel@tonic-gate 		if (notp)
9010Sstevel@tonic-gate 			notpart('1');
9020Sstevel@tonic-gate  */
9030Sstevel@tonic-gate 	}
9040Sstevel@tonic-gate 	return (cnt);
9050Sstevel@tonic-gate }
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate /*
9080Sstevel@tonic-gate  * Routine for vremote to call to implement shifts.
9090Sstevel@tonic-gate  */
9100Sstevel@tonic-gate vshift()
9110Sstevel@tonic-gate {
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	shift(op, 1);
9140Sstevel@tonic-gate }
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate /*
9170Sstevel@tonic-gate  * Replace a single character with the next input character.
9180Sstevel@tonic-gate  * A funny kind of insert.
9190Sstevel@tonic-gate  */
9200Sstevel@tonic-gate vrep(cnt)
9210Sstevel@tonic-gate 	register int cnt;
9220Sstevel@tonic-gate {
9230Sstevel@tonic-gate 	register int i, c;
9240Sstevel@tonic-gate 	register unsigned char *endcurs;
9250Sstevel@tonic-gate 	endcurs = cursor;
9260Sstevel@tonic-gate 	for(i = 1; i <= cnt; i++) {
9270Sstevel@tonic-gate 		if(!*endcurs) {
9280Sstevel@tonic-gate 			beep();
9290Sstevel@tonic-gate 			return;
9300Sstevel@tonic-gate 		}
9310Sstevel@tonic-gate 		endcurs = nextchr(endcurs);
9320Sstevel@tonic-gate 	}
9330Sstevel@tonic-gate 	i = lcolumn(endcurs);
9340Sstevel@tonic-gate 	vcursat(cursor);
9350Sstevel@tonic-gate 	doomed = i - cindent();
9360Sstevel@tonic-gate 	/*
9370Sstevel@tonic-gate 	 * TRANSLATION_NOTE
9380Sstevel@tonic-gate 	 *	"r" is a terse mode message that corresponds to
9390Sstevel@tonic-gate 	 *	"REPLACE 1 CHAR".
9400Sstevel@tonic-gate 	 *	Translated message of "r" must be 1 character (not byte).
9410Sstevel@tonic-gate 	 *	Or, just leave it.
9420Sstevel@tonic-gate 	 */
9430Sstevel@tonic-gate 	if(value(vi_TERSE))
9440Sstevel@tonic-gate 		vshowmode(gettext("r"));
9450Sstevel@tonic-gate 	else
9460Sstevel@tonic-gate 		vshowmode(gettext("REPLACE 1 CHAR"));
9470Sstevel@tonic-gate 	if (!vglobp) {
9480Sstevel@tonic-gate 		c = getesc();
9490Sstevel@tonic-gate 		if (c == 0) {
9500Sstevel@tonic-gate 			vshowmode("");
9510Sstevel@tonic-gate 			vfixcurs();
9520Sstevel@tonic-gate 			return;
9530Sstevel@tonic-gate 		}
9540Sstevel@tonic-gate 		ungetkey(c);
9550Sstevel@tonic-gate 	}
9560Sstevel@tonic-gate 	CP(vutmp, linebuf);
9570Sstevel@tonic-gate 	if (FIXUNDO)
9580Sstevel@tonic-gate 		vundkind = VCHNG;
9590Sstevel@tonic-gate 	wcursor = endcurs;
9600Sstevel@tonic-gate 	vUD1 = cursor; vUD2 = wcursor;
9610Sstevel@tonic-gate 	CP(cursor, wcursor);
9620Sstevel@tonic-gate 	prepapp();
9630Sstevel@tonic-gate 	vappend('r', cnt, 0);
9640Sstevel@tonic-gate 	*lastcp++ = INS[0];
9650Sstevel@tonic-gate 	setLAST();
9660Sstevel@tonic-gate }
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate /*
9690Sstevel@tonic-gate  * Yank.
9700Sstevel@tonic-gate  *
9710Sstevel@tonic-gate  * Yanking to string registers occurs for free (essentially)
9720Sstevel@tonic-gate  * in the routine xdw().
9730Sstevel@tonic-gate  */
9740Sstevel@tonic-gate vyankit()
9750Sstevel@tonic-gate {
9760Sstevel@tonic-gate 	register int cnt;
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	if (wdot) {
9790Sstevel@tonic-gate 		if ((cnt = xdw()) < 0)
9800Sstevel@tonic-gate 			return;
9810Sstevel@tonic-gate 		vremote(cnt, yank, 0);
9820Sstevel@tonic-gate 		setpk();
9830Sstevel@tonic-gate 		notenam = (unsigned char *)"yank";
9840Sstevel@tonic-gate 		if (FIXUNDO)
9850Sstevel@tonic-gate 			vundkind = VNONE;
9860Sstevel@tonic-gate 		DEL[0] = 0;
9870Sstevel@tonic-gate 		wdot = NOLINE;
9880Sstevel@tonic-gate 		if (notecnt <= vcnt - vcline && notecnt < value(vi_REPORT))
9890Sstevel@tonic-gate 			notecnt = 0;
9900Sstevel@tonic-gate 		vrepaint(cursor);
9910Sstevel@tonic-gate 		return;
9920Sstevel@tonic-gate 	}
9930Sstevel@tonic-gate 	takeout(DEL);
9940Sstevel@tonic-gate }
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate /*
9970Sstevel@tonic-gate  * Set pkill variables so a put can
9980Sstevel@tonic-gate  * know how to put back partial text.
9990Sstevel@tonic-gate  * This is necessary because undo needs the complete
10000Sstevel@tonic-gate  * line images to be saved, while a put wants to trim
10010Sstevel@tonic-gate  * the first and last lines.  The compromise
10020Sstevel@tonic-gate  * is for put to be more clever.
10030Sstevel@tonic-gate  */
10040Sstevel@tonic-gate setpk()
10050Sstevel@tonic-gate {
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 	if (wcursor) {
10080Sstevel@tonic-gate 		pkill[0] = cursor;
10090Sstevel@tonic-gate 		pkill[1] = wcursor;
10100Sstevel@tonic-gate 	}
10110Sstevel@tonic-gate }
1012