xref: /onnv-gate/usr/src/cmd/vi/port/ex_vput.c (revision 802:73b56fb6544b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*802Scf46844  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
280Sstevel@tonic-gate /*	  All Rights Reserved  	*/
290Sstevel@tonic-gate 
300Sstevel@tonic-gate 
310Sstevel@tonic-gate /* Copyright (c) 1981 Regents of the University of California */
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include "ex.h"
360Sstevel@tonic-gate #include "ex_tty.h"
370Sstevel@tonic-gate #include "ex_vis.h"
380Sstevel@tonic-gate 
390Sstevel@tonic-gate /*
400Sstevel@tonic-gate  * Deal with the screen, clearing, cursor positioning, putting characters
410Sstevel@tonic-gate  * into the screen image, and deleting characters.
420Sstevel@tonic-gate  * Really hard stuff here is utilizing insert character operations
430Sstevel@tonic-gate  * on intelligent terminals which differs widely from terminal to terminal.
440Sstevel@tonic-gate  */
45*802Scf46844 void
vclear(void)46*802Scf46844 vclear(void)
470Sstevel@tonic-gate {
480Sstevel@tonic-gate 
490Sstevel@tonic-gate #ifdef TRACE
500Sstevel@tonic-gate 	if (trace)
510Sstevel@tonic-gate 		tfixnl(), fprintf(trace, "------\nvclear, clear_screen '%s'\n", clear_screen);
520Sstevel@tonic-gate #endif
530Sstevel@tonic-gate 	tputs(clear_screen, lines, putch);
540Sstevel@tonic-gate 	destcol = 0;
550Sstevel@tonic-gate 	outcol = 0;
560Sstevel@tonic-gate 	destline = 0;
570Sstevel@tonic-gate 	outline = 0;
580Sstevel@tonic-gate 	if (inopen)
590Sstevel@tonic-gate 	vclrbyte(vtube0, WCOLS * (WECHO - ZERO + 1));
600Sstevel@tonic-gate }
610Sstevel@tonic-gate 
620Sstevel@tonic-gate /*
630Sstevel@tonic-gate  * Clear memory.
640Sstevel@tonic-gate  */
65*802Scf46844 void
vclrbyte(wchar_t * cp,int i)66*802Scf46844 vclrbyte(wchar_t *cp, int i)
670Sstevel@tonic-gate {
680Sstevel@tonic-gate 
690Sstevel@tonic-gate 	if (i > 0)
700Sstevel@tonic-gate 		do
710Sstevel@tonic-gate 			*cp++ = 0;
720Sstevel@tonic-gate 		while (--i != 0);
730Sstevel@tonic-gate }
740Sstevel@tonic-gate 
750Sstevel@tonic-gate /*
760Sstevel@tonic-gate  * Clear a physical display line, high level.
770Sstevel@tonic-gate  */
78*802Scf46844 void
vclrlin(int l,line * tp)79*802Scf46844 vclrlin(int l, line *tp)
800Sstevel@tonic-gate {
810Sstevel@tonic-gate 
820Sstevel@tonic-gate 	vigoto(l, 0);
830Sstevel@tonic-gate 	if ((hold & HOLDAT) == 0)
840Sstevel@tonic-gate 		putchar(tp > dol ? ((UPPERCASE || tilde_glitch) ? '^' : '~') : '@');
850Sstevel@tonic-gate 	if (state == HARDOPEN)
860Sstevel@tonic-gate 		sethard();
870Sstevel@tonic-gate 	vclreol();
880Sstevel@tonic-gate }
890Sstevel@tonic-gate 
900Sstevel@tonic-gate /*
910Sstevel@tonic-gate  * Clear to the end of the current physical line
920Sstevel@tonic-gate  */
93*802Scf46844 void
vclreol(void)94*802Scf46844 vclreol(void)
950Sstevel@tonic-gate {
96*802Scf46844 	int i;
97*802Scf46844 	wchar_t *tp, j;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate #ifdef TRACE
1000Sstevel@tonic-gate 	if (trace)
1010Sstevel@tonic-gate 		fprintf(trace, "vclreol(), destcol %d, ateopr() %d\n", destcol, ateopr());
1020Sstevel@tonic-gate #endif
1030Sstevel@tonic-gate 	if (destcol == WCOLS)
1040Sstevel@tonic-gate 		return;
1050Sstevel@tonic-gate 	destline += destcol / WCOLS;
1060Sstevel@tonic-gate 	destcol %= WCOLS;
1070Sstevel@tonic-gate 	if (destline < 0 || destline > WECHO)
1080Sstevel@tonic-gate 		error(gettext("Internal error: vclreol"));
1090Sstevel@tonic-gate 	i = WCOLS - destcol;
1100Sstevel@tonic-gate 	tp = vtube[destline] + destcol;
1110Sstevel@tonic-gate 	if (clr_eol) {
1120Sstevel@tonic-gate 		if (insert_null_glitch && *tp || !ateopr()) {
1130Sstevel@tonic-gate 			vcsync();
1140Sstevel@tonic-gate 			vputp(clr_eol, 1);
1150Sstevel@tonic-gate 		}
1160Sstevel@tonic-gate 		vclrbyte(tp, i);
1170Sstevel@tonic-gate 		return;
1180Sstevel@tonic-gate 	}
1190Sstevel@tonic-gate 	if (*tp == 0)
1200Sstevel@tonic-gate 		return;
1210Sstevel@tonic-gate 	while (i > 0 && (j = *tp & (QUOTE|TRIM))) {
1220Sstevel@tonic-gate 		if (j != ' ' && (j & QUOTE) == 0) {
1230Sstevel@tonic-gate 			destcol = WCOLS - i;
124*802Scf46844 			(void) vputchar(' ');
1250Sstevel@tonic-gate 		}
1260Sstevel@tonic-gate 		--i, *tp++ = 0;
1270Sstevel@tonic-gate 	}
1280Sstevel@tonic-gate }
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate /*
1310Sstevel@tonic-gate  * Clear the echo line.
1320Sstevel@tonic-gate  * If didphys then its been cleared physically (as
1330Sstevel@tonic-gate  * a side effect of a clear to end of display, e.g.)
1340Sstevel@tonic-gate  * so just do it logically.
1350Sstevel@tonic-gate  * If work here is being held off, just remember, in
1360Sstevel@tonic-gate  * heldech, if work needs to be done, don't do anything.
1370Sstevel@tonic-gate  */
138*802Scf46844 void
vclrech(didphys)1390Sstevel@tonic-gate vclrech(didphys)
1400Sstevel@tonic-gate 	bool didphys;
1410Sstevel@tonic-gate {
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate #ifdef ADEBUG
1440Sstevel@tonic-gate 	if (trace)
1450Sstevel@tonic-gate 		fprintf(trace, "vclrech(%d), Peekkey %d, hold %o\n", didphys, Peekkey, hold);
1460Sstevel@tonic-gate #endif
1470Sstevel@tonic-gate 	if (Peekkey == ATTN)
1480Sstevel@tonic-gate 		return;
1490Sstevel@tonic-gate 	if (hold & HOLDECH) {
1500Sstevel@tonic-gate 		heldech = !didphys;
1510Sstevel@tonic-gate 		return;
1520Sstevel@tonic-gate 	}
1530Sstevel@tonic-gate 	if (!didphys && (clr_eos || clr_eol)) {
1540Sstevel@tonic-gate 		splitw++;
1550Sstevel@tonic-gate 		/*
1560Sstevel@tonic-gate 		 * If display is retained below, then MUST use clr_eos or
1570Sstevel@tonic-gate 		 * clr_eol since we don't really know whats out there.
1580Sstevel@tonic-gate 		 * Vigoto might decide (incorrectly) to do nothing.
1590Sstevel@tonic-gate 		 */
1600Sstevel@tonic-gate 		if (memory_below) {
1610Sstevel@tonic-gate 			vgoto(WECHO, 0);
1620Sstevel@tonic-gate 			/*
1630Sstevel@tonic-gate 			 * This is tricky.  If clr_eos is as cheap we
1640Sstevel@tonic-gate 			 * should use it, so we don't have extra junk
1650Sstevel@tonic-gate 			 * floating around in memory below.  But if
1660Sstevel@tonic-gate 			 * clr_eol costs less we should use it.  The real
1670Sstevel@tonic-gate 			 * reason here is that clr_eos is incredibly
1680Sstevel@tonic-gate 			 * expensive on the HP 2626 (1/2 second or more)
1690Sstevel@tonic-gate 			 * which makes ^D scroll really slow.  But the
1700Sstevel@tonic-gate 			 * 2621 has a bug that shows up if we use clr_eol
1710Sstevel@tonic-gate 			 * instead of clr_eos, so we make sure the costs
1720Sstevel@tonic-gate 			 * are equal so it will prefer clr_eol.
1730Sstevel@tonic-gate 			 */
1740Sstevel@tonic-gate 			if (costCE < costCD)
1750Sstevel@tonic-gate 				vputp(clr_eol, 1);
1760Sstevel@tonic-gate 			else
1770Sstevel@tonic-gate 				vputp(clr_eos, 1);
1780Sstevel@tonic-gate 		} else {
1790Sstevel@tonic-gate 			if (teleray_glitch) {
1800Sstevel@tonic-gate 				/* This code basically handles the t1061
1810Sstevel@tonic-gate 				 * where positioning at (0, 0) won't work
1820Sstevel@tonic-gate 				 * because the terminal won't let you put
1830Sstevel@tonic-gate 				 * the cursor on it's magic cookie.
1840Sstevel@tonic-gate 				 *
1850Sstevel@tonic-gate 				 * Should probably be ceol_standout_glitch
1860Sstevel@tonic-gate 				 * above, or even a
1870Sstevel@tonic-gate 				 * new glitch, but right now t1061 is the
1880Sstevel@tonic-gate 				 * only terminal with teleray_glitch.
1890Sstevel@tonic-gate 				 */
1900Sstevel@tonic-gate 				vgoto(WECHO, 0);
1910Sstevel@tonic-gate 				vputp(delete_line, 1);
1920Sstevel@tonic-gate 			} else {
1930Sstevel@tonic-gate 				vigoto(WECHO, 0);
1940Sstevel@tonic-gate 				vclreol();
1950Sstevel@tonic-gate 			}
1960Sstevel@tonic-gate 		}
1970Sstevel@tonic-gate 		splitw = 0;
1980Sstevel@tonic-gate 		didphys = 1;
1990Sstevel@tonic-gate 	}
2000Sstevel@tonic-gate 	if (didphys)
2010Sstevel@tonic-gate 		vclrbyte(vtube[WECHO], WCOLS);
2020Sstevel@tonic-gate 	heldech = 0;
2030Sstevel@tonic-gate }
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate /*
2060Sstevel@tonic-gate  * Fix the echo area for use, setting
2070Sstevel@tonic-gate  * the state variable splitw so we wont rollup
2080Sstevel@tonic-gate  * when we move the cursor there.
2090Sstevel@tonic-gate  */
210*802Scf46844 void
fixech(void)211*802Scf46844 fixech(void)
2120Sstevel@tonic-gate {
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 	splitw++;
2150Sstevel@tonic-gate 	if (state != VISUAL && state != CRTOPEN) {
2160Sstevel@tonic-gate 		vclean();
2170Sstevel@tonic-gate 		vcnt = 0;
2180Sstevel@tonic-gate 	}
2190Sstevel@tonic-gate 	vgoto(WECHO, 0); flusho();
2200Sstevel@tonic-gate }
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate /*
2230Sstevel@tonic-gate  * Put the cursor ``before'' cp.
2240Sstevel@tonic-gate  */
225*802Scf46844 void
vcursbef(unsigned char * cp)226*802Scf46844 vcursbef(unsigned char *cp)
2270Sstevel@tonic-gate {
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	if (cp <= linebuf)
2300Sstevel@tonic-gate 		vgotoCL(value(vi_NUMBER) << 3);
2310Sstevel@tonic-gate 	else
2320Sstevel@tonic-gate 		vgotoCL(lcolumn(cp)-1);
2330Sstevel@tonic-gate }
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate /*
2360Sstevel@tonic-gate  * Put the cursor ``at'' cp.
2370Sstevel@tonic-gate  */
238*802Scf46844 void
vcursat(unsigned char * cp)239*802Scf46844 vcursat(unsigned char *cp)
2400Sstevel@tonic-gate {
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 	if (cp <= linebuf && linebuf[0] == 0)
2430Sstevel@tonic-gate 		vgotoCL(value(vi_NUMBER) << 3);
2440Sstevel@tonic-gate 	else
2450Sstevel@tonic-gate 		vgotoCL(lcolumn(cp));
2460Sstevel@tonic-gate }
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate /*
2490Sstevel@tonic-gate  * Put the cursor ``after'' cp.
2500Sstevel@tonic-gate  */
251*802Scf46844 void
vcursaft(unsigned char * cp)252*802Scf46844 vcursaft(unsigned char *cp)
2530Sstevel@tonic-gate {
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	vgotoCL(lcolumn(nextchr(cp)));
2560Sstevel@tonic-gate }
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate /*
2590Sstevel@tonic-gate  * Fix the cursor to be positioned in the correct place
2600Sstevel@tonic-gate  * to accept a command.
2610Sstevel@tonic-gate  */
262*802Scf46844 void
vfixcurs(void)263*802Scf46844 vfixcurs(void)
2640Sstevel@tonic-gate {
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	vsetcurs(cursor);
2670Sstevel@tonic-gate }
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate /*
2700Sstevel@tonic-gate  * Compute the column position implied by the cursor at ``nc'',
2710Sstevel@tonic-gate  * and move the cursor there.
2720Sstevel@tonic-gate  */
273*802Scf46844 void
vsetcurs(unsigned char * nc)274*802Scf46844 vsetcurs(unsigned char *nc)
2750Sstevel@tonic-gate {
276*802Scf46844 	int col;
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	col = column(nc);
2790Sstevel@tonic-gate 	if (linebuf[0])
2800Sstevel@tonic-gate 		col--;
2810Sstevel@tonic-gate 	vgotoCL(col);
2820Sstevel@tonic-gate 	cursor = nc;
2830Sstevel@tonic-gate }
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate /*
2860Sstevel@tonic-gate  * Move the cursor invisibly, i.e. only remember to do it.
2870Sstevel@tonic-gate  */
288*802Scf46844 void
vigoto(int y,int x)289*802Scf46844 vigoto(int y, int x)
2900Sstevel@tonic-gate {
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	destline = y;
2930Sstevel@tonic-gate 	destcol = x;
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate /*
2970Sstevel@tonic-gate  * Move the cursor to the position implied by any previous
2980Sstevel@tonic-gate  * vigoto (or low level hacking with destcol/destline as in readecho).
2990Sstevel@tonic-gate  */
300*802Scf46844 void
vcsync(void)301*802Scf46844 vcsync(void)
3020Sstevel@tonic-gate {
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	vgoto(destline, destcol);
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate /*
3080Sstevel@tonic-gate  * Goto column x of the current line.
3090Sstevel@tonic-gate  */
310*802Scf46844 void
vgotoCL(int x)311*802Scf46844 vgotoCL(int x)
3120Sstevel@tonic-gate {
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	if (splitw)
3150Sstevel@tonic-gate 		vgoto(WECHO, x);
3160Sstevel@tonic-gate 	else
3170Sstevel@tonic-gate 		vgoto(LINE(vcline), x);
3180Sstevel@tonic-gate }
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate /*
3210Sstevel@tonic-gate  * Invisible goto column x of current line.
3220Sstevel@tonic-gate  */
323*802Scf46844 void
vigotoCL(int x)324*802Scf46844 vigotoCL(int x)
3250Sstevel@tonic-gate {
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	if (splitw)
3280Sstevel@tonic-gate 		vigoto(WECHO, x);
3290Sstevel@tonic-gate 	else
3300Sstevel@tonic-gate 		vigoto(LINE(vcline), x);
3310Sstevel@tonic-gate }
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate /*
3340Sstevel@tonic-gate  * Show the current mode in the right hand part of the echo line,
3350Sstevel@tonic-gate  * then return the cursor to where it is now.
3360Sstevel@tonic-gate  */
337*802Scf46844 void
vshowmode(unsigned char * msg)338*802Scf46844 vshowmode(unsigned char *msg)
3390Sstevel@tonic-gate {
3400Sstevel@tonic-gate 	int savecol, saveline, savesplit;
3410Sstevel@tonic-gate 	unsigned char *p;
3420Sstevel@tonic-gate 	wchar_t	wchar;
3430Sstevel@tonic-gate 	int	length;
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	if (!value(vi_SHOWMODE))
3460Sstevel@tonic-gate 		return;
3470Sstevel@tonic-gate 	/* Don't alter mode message for macros (arrow keys) or yank/put */
3480Sstevel@tonic-gate 	if (vmacp || vglobp)
3490Sstevel@tonic-gate 		return;
3500Sstevel@tonic-gate 	savecol = outcol; saveline = outline; savesplit = splitw;
3510Sstevel@tonic-gate 	splitw = 1;	/* To avoid scrolling */
3520Sstevel@tonic-gate 	vigoto(WECHO, WCOLS-20);
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 	if (*msg) {
3550Sstevel@tonic-gate 		vcsync();
3560Sstevel@tonic-gate 		for (p = msg; *p;) {
3570Sstevel@tonic-gate 			length = mbtowc(&wchar, (char *)p, MULTI_BYTE_MAX);
3580Sstevel@tonic-gate 			if (length <= 0) {
3590Sstevel@tonic-gate 				/*
3600Sstevel@tonic-gate 				 * This should never happen, but
3610Sstevel@tonic-gate 				 * if 'msg' doesn't make a valid string,
3620Sstevel@tonic-gate 				 * treat this case as the same as the
3630Sstevel@tonic-gate 				 * null string 'msg'.
3640Sstevel@tonic-gate 				 */
3650Sstevel@tonic-gate 				/*
3660Sstevel@tonic-gate 				 * Going back to command mode - clear the message.
3670Sstevel@tonic-gate 				 */
3680Sstevel@tonic-gate 				vclreol();
3690Sstevel@tonic-gate 				break;
3700Sstevel@tonic-gate 			} else {
371*802Scf46844 				(void) vputchar(wchar);
3720Sstevel@tonic-gate 				p += length;
3730Sstevel@tonic-gate 			}
3740Sstevel@tonic-gate 		}
3750Sstevel@tonic-gate 	} else {
3760Sstevel@tonic-gate 		/*
3770Sstevel@tonic-gate 		 * Going back to command mode - clear the message.
3780Sstevel@tonic-gate 		 */
3790Sstevel@tonic-gate 		vclreol();
3800Sstevel@tonic-gate 	}
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	FLAGS(WECHO) |= VDIRT;
3830Sstevel@tonic-gate 	vgoto(saveline, savecol);
3840Sstevel@tonic-gate 	splitw = savesplit;
3850Sstevel@tonic-gate }
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate /*
3880Sstevel@tonic-gate  * Move cursor to line y, column x, handling wraparound and scrolling.
3890Sstevel@tonic-gate  */
390*802Scf46844 void
vgoto(int y,int x)391*802Scf46844 vgoto(int y, int x)
3920Sstevel@tonic-gate {
393*802Scf46844 	wchar_t *tp;
394*802Scf46844 	wchar_t c;
3950Sstevel@tonic-gate 	int		 col;
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	/*
3980Sstevel@tonic-gate 	 * Fold the possibly too large value of x.
3990Sstevel@tonic-gate 	 */
4000Sstevel@tonic-gate 	if (x >= WCOLS) {
4010Sstevel@tonic-gate 		y += x / WCOLS;
4020Sstevel@tonic-gate 		x %= WCOLS;
4030Sstevel@tonic-gate 	}
4040Sstevel@tonic-gate 	if (y < 0) {
4050Sstevel@tonic-gate 		error("Internal error: vgoto");
4060Sstevel@tonic-gate 	}
4070Sstevel@tonic-gate 	if (outcol >= WCOLS) {
4080Sstevel@tonic-gate 		if (auto_right_margin) {
4090Sstevel@tonic-gate 			outline += outcol / WCOLS;
4100Sstevel@tonic-gate 			outcol %= WCOLS;
4110Sstevel@tonic-gate 		} else
4120Sstevel@tonic-gate 			outcol = WCOLS - 1;
4130Sstevel@tonic-gate 	}
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	/*
4160Sstevel@tonic-gate 	 * In a hardcopy or glass crt open, print the stuff
4170Sstevel@tonic-gate 	 * implied by a motion, or backspace.
4180Sstevel@tonic-gate 	 */
4190Sstevel@tonic-gate 	if (state == HARDOPEN || state == ONEOPEN) {
4200Sstevel@tonic-gate 		if (y != outline)
4210Sstevel@tonic-gate 			error(gettext("Line too long for open"));
4220Sstevel@tonic-gate 		if (x + 1 < outcol - x || (outcol > x && !cursor_left))
4230Sstevel@tonic-gate 			destcol = 0, fgoto();
4240Sstevel@tonic-gate 		tp = vtube[WBOT] + outcol;
4250Sstevel@tonic-gate 		while (outcol != x)
4260Sstevel@tonic-gate 			if (outcol < x) {
4270Sstevel@tonic-gate 				int length;
4280Sstevel@tonic-gate 				unsigned char multic[MULTI_BYTE_MAX];
4290Sstevel@tonic-gate 				if (*tp == 0)
4300Sstevel@tonic-gate 					*tp = ' ';
4310Sstevel@tonic-gate 				c = *tp++ & TRIM;
4320Sstevel@tonic-gate 				length = wctomb((char *)multic, c);
4330Sstevel@tonic-gate 				if(length == 0)
4340Sstevel@tonic-gate 					length = 1;
4350Sstevel@tonic-gate 				while(length--)
436*802Scf46844 					(void) vputc(c &&
437*802Scf46844 					    (!over_strike || erase_overstrike)
438*802Scf46844 					    ? c : ' ');
4390Sstevel@tonic-gate 				if (c) {
4400Sstevel@tonic-gate 					if ((col = wcwidth(c)) < 0)
4410Sstevel@tonic-gate 						col = 0;
4420Sstevel@tonic-gate 				} else
4430Sstevel@tonic-gate 					col = 1;
4440Sstevel@tonic-gate 				outcol += col;
4450Sstevel@tonic-gate 			} else {
4460Sstevel@tonic-gate 				vputp(cursor_left, 0);
4470Sstevel@tonic-gate 				outcol--;
4480Sstevel@tonic-gate 			}
4490Sstevel@tonic-gate 		destcol = outcol = x;
4500Sstevel@tonic-gate 		destline = outline;
4510Sstevel@tonic-gate 		return;
4520Sstevel@tonic-gate 	}
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	/*
4550Sstevel@tonic-gate 	 * If the destination position implies a scroll, do it.
4560Sstevel@tonic-gate 	 */
4570Sstevel@tonic-gate 	destline = y;
4580Sstevel@tonic-gate 	if (destline > WBOT && (!splitw || destline > WECHO)) {
4590Sstevel@tonic-gate 		endim();
4600Sstevel@tonic-gate 		vrollup(destline);
4610Sstevel@tonic-gate 	}
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	/*
4640Sstevel@tonic-gate 	 * If there really is a motion involved, do it.
4650Sstevel@tonic-gate 	 * The check here is an optimization based on profiling.
4660Sstevel@tonic-gate 	 */
4670Sstevel@tonic-gate 	destcol = x;
4680Sstevel@tonic-gate 	if ((destline - outline) * WCOLS != destcol - outcol) {
4690Sstevel@tonic-gate 		if (!move_insert_mode)
4700Sstevel@tonic-gate 			endim();
4710Sstevel@tonic-gate 		fgoto();
4720Sstevel@tonic-gate 	}
4730Sstevel@tonic-gate }
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate /*
4760Sstevel@tonic-gate  * This is the hardest code in the editor, and deals with insert modes
4770Sstevel@tonic-gate  * on different kinds of intelligent terminals.  The complexity is due
4780Sstevel@tonic-gate  * to the cross product of three factors:
4790Sstevel@tonic-gate  *
4800Sstevel@tonic-gate  *	1. Lines may display as more than one segment on the screen.
4810Sstevel@tonic-gate  *	2. There are 2 kinds of intelligent terminal insert modes.
4820Sstevel@tonic-gate  *	3. Tabs squash when you insert characters in front of them,
4830Sstevel@tonic-gate  *	   in a way in which current intelligent terminals don't handle.
4840Sstevel@tonic-gate  *
4850Sstevel@tonic-gate  * The two kinds of terminals are typified by the DM2500 or HP2645 for
4860Sstevel@tonic-gate  * one and the CONCEPT-100 or the FOX for the other.
4870Sstevel@tonic-gate  *
4880Sstevel@tonic-gate  * The first (HP2645) kind has an insert mode where the characters
4890Sstevel@tonic-gate  * fall off the end of the line and the screen is shifted rigidly
4900Sstevel@tonic-gate  * no matter how the display came about.
4910Sstevel@tonic-gate  *
4920Sstevel@tonic-gate  * The second (CONCEPT-100) kind comes from terminals which are designed
4930Sstevel@tonic-gate  * for forms editing and which distinguish between blanks and ``spaces''
4940Sstevel@tonic-gate  * on the screen, spaces being like blank, but never having had
4950Sstevel@tonic-gate  * and data typed into that screen position (since, e.g. a clear operation
4960Sstevel@tonic-gate  * like clear screen).  On these terminals, when you insert a character,
4970Sstevel@tonic-gate  * the characters from where you are to the end of the screen shift
4980Sstevel@tonic-gate  * over till a ``space'' is found, and the null character there gets
4990Sstevel@tonic-gate  * eaten up.
5000Sstevel@tonic-gate  *
5010Sstevel@tonic-gate  *
5020Sstevel@tonic-gate  * The code here considers the line as consisting of several parts
5030Sstevel@tonic-gate  * the first part is the ``doomed'' part, i.e. a part of the line
5040Sstevel@tonic-gate  * which is being typed over.  Next comes some text up to the first
5050Sstevel@tonic-gate  * following tab.  The tab is the next segment of the line, and finally
5060Sstevel@tonic-gate  * text after the tab.
5070Sstevel@tonic-gate  *
5080Sstevel@tonic-gate  * We have to consider each of these segments and the effect of the
5090Sstevel@tonic-gate  * insertion of a character on them.  On terminals like HP2645's we
5100Sstevel@tonic-gate  * must simulate a multi-line insert mode using the primitive one
5110Sstevel@tonic-gate  * line insert mode.  If we are inserting in front of a tab, we have
5120Sstevel@tonic-gate  * to either delete characters from the tab or insert white space
5130Sstevel@tonic-gate  * (when the tab reaches a new spot where it gets larger) before we
5140Sstevel@tonic-gate  * insert the new character.
5150Sstevel@tonic-gate  *
5160Sstevel@tonic-gate  * On a terminal like a CONCEPT our strategy is to make all
5170Sstevel@tonic-gate  * blanks be displayed, while trying to keep the screen having ``spaces''
5180Sstevel@tonic-gate  * for portions of tabs.  In this way the terminal hardware does some
5190Sstevel@tonic-gate  * of the hacking for compression of tabs, although this tends to
5200Sstevel@tonic-gate  * disappear as you work on the line and spaces change into blanks.
5210Sstevel@tonic-gate  *
5220Sstevel@tonic-gate  * There are a number of boundary conditions (like typing just before
5230Sstevel@tonic-gate  * the first following tab) where we can avoid a lot of work.  Most
5240Sstevel@tonic-gate  * of them have to be dealt with explicitly because performance is
5250Sstevel@tonic-gate  * much, much worse if we don't.
5260Sstevel@tonic-gate  *
5270Sstevel@tonic-gate  * A final thing which is hacked here is two flavors of insert mode.
5280Sstevel@tonic-gate  * Datamedia's do this by an insert mode which you enter and leave
5290Sstevel@tonic-gate  * and by having normal motion character operate differently in this
5300Sstevel@tonic-gate  * mode, notably by having a newline insert a line on the screen in
5310Sstevel@tonic-gate  * this mode.  This generally means it is unsafe to move around
5320Sstevel@tonic-gate  * the screen ignoring the fact that we are in this mode.
5330Sstevel@tonic-gate  * This is possible on some terminals, and wins big (e.g. HP), so
5340Sstevel@tonic-gate  * we encode this as a ``can move in insert capability'' mi,
5350Sstevel@tonic-gate  * and terminals which have it can do insert mode with much less
5360Sstevel@tonic-gate  * work when tabs are present following the cursor on the current line.
5370Sstevel@tonic-gate  */
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate /*
5400Sstevel@tonic-gate  * Routine to expand a tab, calling the normal Outchar routine
5410Sstevel@tonic-gate  * to put out each implied character.  Note that we call outchar
5420Sstevel@tonic-gate  * with a QUOTE.  We use QUOTE internally to represent a position
5430Sstevel@tonic-gate  * which is part of the expansion of a tab.
5440Sstevel@tonic-gate  */
545*802Scf46844 void
vgotab(void)546*802Scf46844 vgotab(void)
5470Sstevel@tonic-gate {
548*802Scf46844 	int i = tabcol(destcol, value(vi_TABSTOP)) - destcol;
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 	do
5510Sstevel@tonic-gate 		(*Outchar)(QUOTE);
5520Sstevel@tonic-gate 	while (--i);
5530Sstevel@tonic-gate }
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate /*
5560Sstevel@tonic-gate  * Variables for insert mode.
5570Sstevel@tonic-gate  */
5580Sstevel@tonic-gate int	linend;			/* The column position of end of line */
5590Sstevel@tonic-gate int	tabstart;		/* Column of start of first following tab */
5600Sstevel@tonic-gate int	tabend;			/* Column of end of following tabs */
5610Sstevel@tonic-gate int	tabsize;		/* Size of the following tabs */
5620Sstevel@tonic-gate int	tabslack;		/* Number of ``spaces'' in following tabs */
5630Sstevel@tonic-gate int	inssiz;			/* Number of characters to be inserted */
5640Sstevel@tonic-gate int	inscol;			/* Column where insertion is taking place */
5650Sstevel@tonic-gate int	shft;			/* Amount tab expansion shifted rest of line */
5660Sstevel@tonic-gate int	slakused;		/* This much of tabslack will be used up */
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate /*
5690Sstevel@tonic-gate  * This routine MUST be called before insert mode is run,
5700Sstevel@tonic-gate  * and brings all segments of the current line to the top
5710Sstevel@tonic-gate  * of the screen image buffer so it is easier for us to
5720Sstevel@tonic-gate  * manipulate them.
5730Sstevel@tonic-gate  */
574*802Scf46844 void
vprepins(void)575*802Scf46844 vprepins(void)
5760Sstevel@tonic-gate {
577*802Scf46844 	int i;
578*802Scf46844 	wchar_t *cp = vtube0;
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 	for (i = 0; i < DEPTH(vcline); i++) {
5810Sstevel@tonic-gate 		vmaktop(LINE(vcline) + i, cp);
5820Sstevel@tonic-gate 		cp += WCOLS;
5830Sstevel@tonic-gate 	}
5840Sstevel@tonic-gate }
5850Sstevel@tonic-gate 
586*802Scf46844 void
vmaktop(int p,wchar_t * cp)587*802Scf46844 vmaktop(int p, wchar_t *cp)
5880Sstevel@tonic-gate {
589*802Scf46844 	int i;
5900Sstevel@tonic-gate 	wchar_t temp[TUBECOLS];
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 	if (p < 0 || vtube[p] == cp)
5930Sstevel@tonic-gate 		return;
5940Sstevel@tonic-gate 	for (i = ZERO; i <= WECHO; i++)
5950Sstevel@tonic-gate 		if (vtube[i] == cp) {
5960Sstevel@tonic-gate 			copy(temp, vtube[i], WCOLS * sizeof(wchar_t));
5970Sstevel@tonic-gate 			copy(vtube[i], vtube[p], WCOLS * sizeof(wchar_t));
5980Sstevel@tonic-gate 			copy(vtube[p], temp, WCOLS * sizeof(wchar_t));
5990Sstevel@tonic-gate 			vtube[i] = vtube[p];
6000Sstevel@tonic-gate 			vtube[p] = cp;
6010Sstevel@tonic-gate 			return;
6020Sstevel@tonic-gate 		}
6030Sstevel@tonic-gate 	error(gettext("Line too long"));
6040Sstevel@tonic-gate }
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate /*
6070Sstevel@tonic-gate  * Insert character c at current cursor position.
6080Sstevel@tonic-gate  * Multi-character inserts occur only as a result
6090Sstevel@tonic-gate  * of expansion of tabs (i.e. inssize == 1 except
6100Sstevel@tonic-gate  * for tabs or multibyte characters)
6110Sstevel@tonic-gate  * and code assumes this in several place
6120Sstevel@tonic-gate  * to make life simpler.
6130Sstevel@tonic-gate  */
614*802Scf46844 int
vinschar(wchar_t c)615*802Scf46844 vinschar(wchar_t c)
6160Sstevel@tonic-gate {
617*802Scf46844 	int i;
618*802Scf46844 	wchar_t *tp, wchar;
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	if ((!enter_insert_mode || !exit_insert_mode) && ((hold & HOLDQIK) || !value(vi_REDRAW) || value(vi_SLOWOPEN))) {
6210Sstevel@tonic-gate 		/*
6220Sstevel@tonic-gate 		 * Don't want to try to use terminal
6230Sstevel@tonic-gate 		 * insert mode, or to try to fake it.
6240Sstevel@tonic-gate 		 * Just put the character out; the screen
6250Sstevel@tonic-gate 		 * will probably be wrong but we will fix it later.
6260Sstevel@tonic-gate 		 */
6270Sstevel@tonic-gate 		if (c == '\t') {
6280Sstevel@tonic-gate 			vgotab();
629*802Scf46844 			return (0);
6300Sstevel@tonic-gate 		}
631*802Scf46844 		(void) vputchar(c);
6320Sstevel@tonic-gate 		if (DEPTH(vcline) * WCOLS + !value(vi_REDRAW) >
6330Sstevel@tonic-gate 		    (destline - LINE(vcline)) * WCOLS + destcol)
634*802Scf46844 			return (0);
6350Sstevel@tonic-gate 		/*
6360Sstevel@tonic-gate 		 * The next line is about to be clobbered
6370Sstevel@tonic-gate 		 * make space for another segment of this line
6380Sstevel@tonic-gate 		 * (on an intelligent terminal) or just remember
6390Sstevel@tonic-gate 		 * that next line was clobbered (on a dumb one
6400Sstevel@tonic-gate 		 * if we don't care to redraw the tail.
6410Sstevel@tonic-gate 		 */
6420Sstevel@tonic-gate 		if (insert_line) {
6430Sstevel@tonic-gate 			vnpins(0);
6440Sstevel@tonic-gate 		} else {
6450Sstevel@tonic-gate 			int i2 = LINE(vcline) + DEPTH(vcline);
6460Sstevel@tonic-gate 			if (i2 < LINE(vcline + 1) || i2 > WBOT)
647*802Scf46844 				return (0);
6480Sstevel@tonic-gate 			i = destcol;
6490Sstevel@tonic-gate 			vinslin(i2, 1, vcline);
6500Sstevel@tonic-gate 			DEPTH(vcline)++;
6510Sstevel@tonic-gate 			vigoto(i2, i);
6520Sstevel@tonic-gate 			vprepins();
6530Sstevel@tonic-gate 		}
654*802Scf46844 		return (0);
6550Sstevel@tonic-gate 	}
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	/*
6580Sstevel@tonic-gate 	 * Compute the number of positions in the line image of the
6590Sstevel@tonic-gate 	 * current line.  This is done from the physical image
6600Sstevel@tonic-gate 	 * since that is faster.  Note that we have no memory
6610Sstevel@tonic-gate 	 * from insertion to insertion so that routines which use
6620Sstevel@tonic-gate 	 * us don't have to worry about moving the cursor around.
6630Sstevel@tonic-gate 	 */
6640Sstevel@tonic-gate 	if (*vtube0 == 0)
6650Sstevel@tonic-gate 		linend = 0;
6660Sstevel@tonic-gate 	else {
6670Sstevel@tonic-gate 		/*
6680Sstevel@tonic-gate 		 * Search backwards for a non-null character
6690Sstevel@tonic-gate 		 * from the end of the displayed line.
6700Sstevel@tonic-gate 		 */
6710Sstevel@tonic-gate 		i = WCOLS * DEPTH(vcline);
6720Sstevel@tonic-gate 		if (i == 0)
6730Sstevel@tonic-gate 			i = WCOLS;
6740Sstevel@tonic-gate 		tp = vtube0 + i;
6750Sstevel@tonic-gate 		while (*--tp == 0)
6760Sstevel@tonic-gate 			if (--i == 0)
6770Sstevel@tonic-gate 				break;
6780Sstevel@tonic-gate 		linend = i;
6790Sstevel@tonic-gate 	}
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 	/*
6820Sstevel@tonic-gate 	 * We insert at a position based on the physical location
6830Sstevel@tonic-gate 	 * of the output cursor.
6840Sstevel@tonic-gate 	 */
6850Sstevel@tonic-gate 	inscol = destcol + (destline - LINE(vcline)) * WCOLS;
6860Sstevel@tonic-gate 	if (c == '\t') {
6870Sstevel@tonic-gate 		/*
6880Sstevel@tonic-gate 		 * Characters inserted from a tab must be
6890Sstevel@tonic-gate 		 * remembered as being part of a tab, but we can't
6900Sstevel@tonic-gate 		 * use QUOTE here since we really need to print blanks.
6910Sstevel@tonic-gate 		 * QUOTE|' ' is the representation of this.
6920Sstevel@tonic-gate 		 */
6930Sstevel@tonic-gate 		inssiz = tabcol(inscol, value(vi_TABSTOP)) - inscol;
6940Sstevel@tonic-gate 		c = ' ' | QUOTE;
6950Sstevel@tonic-gate 	} else {
6960Sstevel@tonic-gate 		if ((inssiz = wcwidth(c)) < 0)
6970Sstevel@tonic-gate 			inssiz = 0;
6980Sstevel@tonic-gate 	}
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate 	/*
7010Sstevel@tonic-gate 	 * If the text to be inserted is less than the number
7020Sstevel@tonic-gate 	 * of doomed positions, then we don't need insert mode,
7030Sstevel@tonic-gate 	 * rather we can just typeover.
7040Sstevel@tonic-gate 	 */
7050Sstevel@tonic-gate 	if (inssiz <= doomed) {
7060Sstevel@tonic-gate 		endim();
7070Sstevel@tonic-gate 		if (inscol != linend)
7080Sstevel@tonic-gate 			doomed -= inssiz;
7090Sstevel@tonic-gate 		do {
710*802Scf46844 			(void) vputchar(c);
7110Sstevel@tonic-gate 			if(c & QUOTE)
7120Sstevel@tonic-gate 				inssiz--;
7130Sstevel@tonic-gate 			else
7140Sstevel@tonic-gate 				break;
7150Sstevel@tonic-gate 		} while (inssiz);
716*802Scf46844 		return (0);
7170Sstevel@tonic-gate 	}
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 	/*
7200Sstevel@tonic-gate 	 * Have to really do some insertion, thus
7210Sstevel@tonic-gate 	 * stake out the bounds of the first following
7220Sstevel@tonic-gate 	 * group of tabs, computing starting position,
7230Sstevel@tonic-gate 	 * ending position, and the number of ``spaces'' therein
7240Sstevel@tonic-gate 	 * so we can tell how much it will squish.
7250Sstevel@tonic-gate 	 */
7260Sstevel@tonic-gate 	tp = vtube0 + inscol;
7270Sstevel@tonic-gate 	for (i = inscol; i < linend; i++)
7280Sstevel@tonic-gate 		if (*tp++ & QUOTE) {
7290Sstevel@tonic-gate 			--tp;
7300Sstevel@tonic-gate 			break;
7310Sstevel@tonic-gate 		}
7320Sstevel@tonic-gate 	tabstart = tabend = i;
7330Sstevel@tonic-gate 	tabslack = 0;
7340Sstevel@tonic-gate 	while (tabend < linend) {
7350Sstevel@tonic-gate 		wchar = *tp++;
7360Sstevel@tonic-gate 		if ((wchar & QUOTE) == 0)
7370Sstevel@tonic-gate 			break;
7380Sstevel@tonic-gate 		if ((wchar & TRIM) == 0)
7390Sstevel@tonic-gate 			tabslack++;
7400Sstevel@tonic-gate 		tabsize++;
7410Sstevel@tonic-gate 		tabend++;
7420Sstevel@tonic-gate 	}
7430Sstevel@tonic-gate 	tabsize = tabend - tabstart;
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 	/*
7460Sstevel@tonic-gate 	 * For HP's and DM's, e.g. tabslack has no meaning.
7470Sstevel@tonic-gate 	 */
7480Sstevel@tonic-gate 	if (!insert_null_glitch)
7490Sstevel@tonic-gate 		tabslack = 0;
7500Sstevel@tonic-gate #ifdef IDEBUG
7510Sstevel@tonic-gate 	if (trace) {
7520Sstevel@tonic-gate 		fprintf(trace, "inscol %d, inssiz %d, tabstart %d, ",
7530Sstevel@tonic-gate 			inscol, inssiz, tabstart);
7540Sstevel@tonic-gate 		fprintf(trace, "tabend %d, tabslack %d, linend %d\n",
7550Sstevel@tonic-gate 			tabend, tabslack, linend);
7560Sstevel@tonic-gate 	}
7570Sstevel@tonic-gate #endif
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate 	/*
7600Sstevel@tonic-gate 	 * The real work begins.
7610Sstevel@tonic-gate 	 */
7620Sstevel@tonic-gate 	slakused = 0;
7630Sstevel@tonic-gate 	shft = 0;
7640Sstevel@tonic-gate 	if (tabsize) {
7650Sstevel@tonic-gate 		/*
7660Sstevel@tonic-gate 		 * There are tabs on this line.
7670Sstevel@tonic-gate 		 * If they need to expand, then the rest of the line
7680Sstevel@tonic-gate 		 * will have to be shifted over.  In this case,
7690Sstevel@tonic-gate 		 * we will need to make sure there are no ``spaces''
7700Sstevel@tonic-gate 		 * in the rest of the line (on e.g. CONCEPT-100)
7710Sstevel@tonic-gate 		 * and then grab another segment on the screen if this
7720Sstevel@tonic-gate 		 * line is now deeper.  We then do the shift
7730Sstevel@tonic-gate 		 * implied by the insertion.
7740Sstevel@tonic-gate 		 */
7750Sstevel@tonic-gate 		if (inssiz >= doomed + tabcol(tabstart, value(vi_TABSTOP)) - tabstart) {
7760Sstevel@tonic-gate 			if (insert_null_glitch)
7770Sstevel@tonic-gate 				vrigid();
7780Sstevel@tonic-gate 			vneedpos(value(vi_TABSTOP));
7790Sstevel@tonic-gate 			vishft();
7800Sstevel@tonic-gate 		}
7810Sstevel@tonic-gate 	} else if (inssiz > doomed)
7820Sstevel@tonic-gate 		/*
7830Sstevel@tonic-gate 		 * No tabs, but line may still get deeper.
7840Sstevel@tonic-gate 		 */
7850Sstevel@tonic-gate 		vneedpos(inssiz - doomed);
7860Sstevel@tonic-gate 	/*
7870Sstevel@tonic-gate 	 * Now put in the inserted characters.
7880Sstevel@tonic-gate 	 */
7890Sstevel@tonic-gate 	viin(c);
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 	/*
7920Sstevel@tonic-gate 	 * Now put the cursor in its final resting place.
7930Sstevel@tonic-gate 	 */
7940Sstevel@tonic-gate 	destline = LINE(vcline);
7950Sstevel@tonic-gate 	destcol = inscol + inssiz;
7960Sstevel@tonic-gate 	vcsync();
797*802Scf46844 	return (0);
7980Sstevel@tonic-gate }
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate /*
8010Sstevel@tonic-gate  * Rigidify the rest of the line after the first
8020Sstevel@tonic-gate  * group of following tabs, typing blanks over ``spaces''.
8030Sstevel@tonic-gate  */
804*802Scf46844 void
vrigid(void)805*802Scf46844 vrigid(void)
8060Sstevel@tonic-gate {
807*802Scf46844 	int col;
808*802Scf46844 	wchar_t *tp = vtube0 + tabend;
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 	for (col = tabend; col < linend; col++)
8110Sstevel@tonic-gate 		if ((*tp++ & TRIM) == 0) {
8120Sstevel@tonic-gate 			endim();
8130Sstevel@tonic-gate 			vgotoCL(col);
814*802Scf46844 			(void) vputchar(' ' | QUOTE);
8150Sstevel@tonic-gate 		}
8160Sstevel@tonic-gate }
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate /*
8190Sstevel@tonic-gate  * We need cnt more positions on this line.
8200Sstevel@tonic-gate  * Open up new space on the screen (this may in fact be a
8210Sstevel@tonic-gate  * screen rollup).
8220Sstevel@tonic-gate  *
8230Sstevel@tonic-gate  * On a dumb terminal we may infact redisplay the rest of the
8240Sstevel@tonic-gate  * screen here brute force to keep it pretty.
8250Sstevel@tonic-gate  */
826*802Scf46844 void
vneedpos(int cnt)827*802Scf46844 vneedpos(int cnt)
8280Sstevel@tonic-gate {
829*802Scf46844 	int d = DEPTH(vcline);
830*802Scf46844 	int rmdr = d * WCOLS - linend;
8310Sstevel@tonic-gate 	if (cnt <= rmdr - insert_null_glitch)
8320Sstevel@tonic-gate 		return;
8330Sstevel@tonic-gate 	endim();
8340Sstevel@tonic-gate 	vnpins(1);
8350Sstevel@tonic-gate }
8360Sstevel@tonic-gate 
837*802Scf46844 void
vnpins(int dosync)838*802Scf46844 vnpins(int dosync)
8390Sstevel@tonic-gate {
840*802Scf46844 	int d = DEPTH(vcline);
841*802Scf46844 	int e;
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 	e = LINE(vcline) + DEPTH(vcline);
8440Sstevel@tonic-gate 	if (e < LINE(vcline + 1)) {
8450Sstevel@tonic-gate 		vigoto(e, 0);
8460Sstevel@tonic-gate 		vclreol();
8470Sstevel@tonic-gate 		return;
8480Sstevel@tonic-gate 	}
8490Sstevel@tonic-gate 	DEPTH(vcline)++;
8500Sstevel@tonic-gate 	if (e < WECHO) {
8510Sstevel@tonic-gate 		e = vglitchup(vcline, d);
8520Sstevel@tonic-gate 		vigoto(e, 0); vclreol();
8530Sstevel@tonic-gate 		if (dosync) {
8540Sstevel@tonic-gate 			int (*Ooutchar)() = Outchar;
8550Sstevel@tonic-gate 			Outchar = vputchar;
8560Sstevel@tonic-gate 			vsync(e + 1);
8570Sstevel@tonic-gate 			Outchar = Ooutchar;
8580Sstevel@tonic-gate 		}
8590Sstevel@tonic-gate 	} else {
8600Sstevel@tonic-gate 		vup1();
8610Sstevel@tonic-gate 		vigoto(WBOT, 0);
8620Sstevel@tonic-gate 		vclreol();
8630Sstevel@tonic-gate 	}
8640Sstevel@tonic-gate 	vprepins();
8650Sstevel@tonic-gate }
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate /*
8680Sstevel@tonic-gate  * Do the shift of the next tabstop implied by
8690Sstevel@tonic-gate  * insertion so it expands.
8700Sstevel@tonic-gate  */
871*802Scf46844 void
vishft(void)872*802Scf46844 vishft(void)
8730Sstevel@tonic-gate {
8740Sstevel@tonic-gate 	int tshft = 0;
8750Sstevel@tonic-gate 	int j;
876*802Scf46844 	int i;
877*802Scf46844 	wchar_t *tp = vtube0;
878*802Scf46844 	wchar_t *up, wchar;
8790Sstevel@tonic-gate 	short oldhold = hold;
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate 	shft = value(vi_TABSTOP);
8820Sstevel@tonic-gate 	hold |= HOLDPUPD;
8830Sstevel@tonic-gate 	if (!enter_insert_mode && !exit_insert_mode) {
8840Sstevel@tonic-gate 		/*
8850Sstevel@tonic-gate 		 * Dumb terminals are easy, we just have
8860Sstevel@tonic-gate 		 * to retype the text.
8870Sstevel@tonic-gate 		 */
8880Sstevel@tonic-gate 		vigotoCL(tabend + shft);
8890Sstevel@tonic-gate 		up = tp + tabend;
8900Sstevel@tonic-gate 		for (i = tabend; i < linend; i++)
8910Sstevel@tonic-gate 			if((wchar = *up++) != FILLER)
892*802Scf46844 				(void) vputchar(wchar);
8930Sstevel@tonic-gate 	} else if (insert_null_glitch) {
8940Sstevel@tonic-gate 		/*
8950Sstevel@tonic-gate 		 * CONCEPT-like terminals do most of the work for us,
8960Sstevel@tonic-gate 		 * we don't have to muck with simulation of multi-line
8970Sstevel@tonic-gate 		 * insert mode.  Some of the shifting may come for free
8980Sstevel@tonic-gate 		 * also if the tabs don't have enough slack to take up
8990Sstevel@tonic-gate 		 * all the inserted characters.
9000Sstevel@tonic-gate 		 */
9010Sstevel@tonic-gate 		i = shft;
9020Sstevel@tonic-gate 		slakused = inssiz - doomed;
9030Sstevel@tonic-gate 		if (slakused > tabslack) {
9040Sstevel@tonic-gate 			i -= slakused - tabslack;
9050Sstevel@tonic-gate 			slakused -= tabslack;
9060Sstevel@tonic-gate 		}
9070Sstevel@tonic-gate 		if (i > 0 && tabend != linend) {
9080Sstevel@tonic-gate 			tshft = i;
9090Sstevel@tonic-gate 			vgotoCL(tabend);
9100Sstevel@tonic-gate 			goim();
9110Sstevel@tonic-gate 			do
912*802Scf46844 				(void) vputchar(' ' | QUOTE);
9130Sstevel@tonic-gate 			while (--i);
9140Sstevel@tonic-gate 		}
9150Sstevel@tonic-gate 	} else {
9160Sstevel@tonic-gate 		/*
9170Sstevel@tonic-gate 		 * HP and Datamedia type terminals have to have multi-line
9180Sstevel@tonic-gate 		 * insert faked.  Hack each segment after where we are
9190Sstevel@tonic-gate 		 * (going backwards to where we are.)  We then can
9200Sstevel@tonic-gate 		 * hack the segment where the end of the first following
9210Sstevel@tonic-gate 		 * tab group is.
9220Sstevel@tonic-gate 		 */
9230Sstevel@tonic-gate 		for (j = DEPTH(vcline) - 1; j > (tabend + shft) / WCOLS; j--) {
9240Sstevel@tonic-gate 			vgotoCL(j * WCOLS);
9250Sstevel@tonic-gate 			goim();
9260Sstevel@tonic-gate 			up = tp + j * WCOLS - shft;
9270Sstevel@tonic-gate 			i = shft;
9280Sstevel@tonic-gate 			do {
9290Sstevel@tonic-gate 				wchar_t wchar;
9300Sstevel@tonic-gate 				if (wchar = *up) {
9310Sstevel@tonic-gate 					if(wchar != FILLER)
932*802Scf46844 						(void) vputchar(wchar);
9330Sstevel@tonic-gate 					up++;
9340Sstevel@tonic-gate 				} else
9350Sstevel@tonic-gate 					break;
9360Sstevel@tonic-gate 			} while (--i);
9370Sstevel@tonic-gate 		}
9380Sstevel@tonic-gate 		vigotoCL(tabstart);
9390Sstevel@tonic-gate 		i = shft - (inssiz - doomed);
9400Sstevel@tonic-gate 		if (i > 0) {
9410Sstevel@tonic-gate 			tabslack = inssiz - doomed;
9420Sstevel@tonic-gate 			vcsync();
9430Sstevel@tonic-gate 			goim();
9440Sstevel@tonic-gate 			do
945*802Scf46844 				(void) vputchar(' ');
9460Sstevel@tonic-gate 			while (--i);
9470Sstevel@tonic-gate 		}
9480Sstevel@tonic-gate 	}
9490Sstevel@tonic-gate 	/*
9500Sstevel@tonic-gate 	 * Now do the data moving in the internal screen
9510Sstevel@tonic-gate 	 * image which is common to all three cases.
9520Sstevel@tonic-gate 	 */
9530Sstevel@tonic-gate 	tp += linend;
9540Sstevel@tonic-gate 	up = tp + shft;
9550Sstevel@tonic-gate 	i = linend - tabend;
9560Sstevel@tonic-gate 	if (i > 0)
9570Sstevel@tonic-gate 		do
9580Sstevel@tonic-gate 			*--up = *--tp;
9590Sstevel@tonic-gate 		while (--i);
9600Sstevel@tonic-gate 	if (insert_null_glitch && tshft) {
9610Sstevel@tonic-gate 		i = tshft;
9620Sstevel@tonic-gate 		do
9630Sstevel@tonic-gate 			*--up = ' ' | QUOTE;
9640Sstevel@tonic-gate 		while (--i);
9650Sstevel@tonic-gate 	}
9660Sstevel@tonic-gate 	hold = oldhold;
9670Sstevel@tonic-gate }
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate /*
9700Sstevel@tonic-gate  * Now do the insert of the characters (finally).
9710Sstevel@tonic-gate  */
972*802Scf46844 void
viin(wchar_t c)973*802Scf46844 viin(wchar_t c)
9740Sstevel@tonic-gate {
975*802Scf46844 	wchar_t *tp, *up;
976*802Scf46844 	int i, j;
977*802Scf46844 	bool noim = 0;
9780Sstevel@tonic-gate 	int remdoom;
9790Sstevel@tonic-gate 	short oldhold = hold;
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 	hold |= HOLDPUPD;
9820Sstevel@tonic-gate 	if (tabsize && (enter_insert_mode && exit_insert_mode) && inssiz - doomed > tabslack)
9830Sstevel@tonic-gate 		/*
9840Sstevel@tonic-gate 		 * There is a tab out there which will be affected
9850Sstevel@tonic-gate 		 * by the insertion since there aren't enough doomed
9860Sstevel@tonic-gate 		 * characters to take up all the insertion and we do
9870Sstevel@tonic-gate 		 * have insert mode capability.
9880Sstevel@tonic-gate 		 */
9890Sstevel@tonic-gate 		if (inscol + doomed == tabstart) {
9900Sstevel@tonic-gate 			/*
9910Sstevel@tonic-gate 			 * The end of the doomed characters sits right at the
9920Sstevel@tonic-gate 			 * start of the tabs, then we don't need to use insert
9930Sstevel@tonic-gate 			 * mode; unless the tab has already been expanded
9940Sstevel@tonic-gate 			 * in which case we MUST use insert mode.
9950Sstevel@tonic-gate 			 */
9960Sstevel@tonic-gate 			slakused = 0;
9970Sstevel@tonic-gate 			noim = !shft;
9980Sstevel@tonic-gate 		} else {
9990Sstevel@tonic-gate 			/*
10000Sstevel@tonic-gate 			 * The last really special case to handle is case
10010Sstevel@tonic-gate 			 * where the tab is just sitting there and doesn't
10020Sstevel@tonic-gate 			 * have enough slack to let the insertion take
10030Sstevel@tonic-gate 			 * place without shifting the rest of the line
10040Sstevel@tonic-gate 			 * over.  In this case we have to go out and
10050Sstevel@tonic-gate 			 * delete some characters of the tab before we start
10060Sstevel@tonic-gate 			 * or the answer will be wrong, as the rest of the
10070Sstevel@tonic-gate 			 * line will have been shifted.  This code means
10080Sstevel@tonic-gate 			 * that terminals with only insert character (no
10090Sstevel@tonic-gate 			 * delete character) won't work correctly.
10100Sstevel@tonic-gate 			 */
10110Sstevel@tonic-gate 			i = inssiz - doomed - tabslack - slakused;
10120Sstevel@tonic-gate 			i %= value(vi_TABSTOP);
10130Sstevel@tonic-gate 			if (i > 0) {
10140Sstevel@tonic-gate 				vgotoCL(tabstart);
10150Sstevel@tonic-gate 				godm();
10160Sstevel@tonic-gate 				for (i = inssiz - doomed - tabslack; i > 0; i--)
10170Sstevel@tonic-gate 					vputp(delete_character, DEPTH(vcline));
10180Sstevel@tonic-gate 				enddm();
10190Sstevel@tonic-gate 			}
10200Sstevel@tonic-gate 		}
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	/*
10230Sstevel@tonic-gate 	 * Now put out the characters of the actual insertion.
10240Sstevel@tonic-gate 	 */
10250Sstevel@tonic-gate 	vigotoCL(inscol);
10260Sstevel@tonic-gate 	remdoom = doomed;
10270Sstevel@tonic-gate 	for (i = inssiz; i > 0; i--) {
10280Sstevel@tonic-gate 		if (remdoom > 0) {
10290Sstevel@tonic-gate 			remdoom--;
10300Sstevel@tonic-gate 			endim();
10310Sstevel@tonic-gate 		} else if (noim)
10320Sstevel@tonic-gate 			endim();
10330Sstevel@tonic-gate 		else if (enter_insert_mode && exit_insert_mode) {
10340Sstevel@tonic-gate 			vcsync();
10350Sstevel@tonic-gate 			goim();
10360Sstevel@tonic-gate 		}
1037*802Scf46844 		(void) vputchar(c);
10380Sstevel@tonic-gate 		if((c & QUOTE) == 0)
10390Sstevel@tonic-gate 			break;
10400Sstevel@tonic-gate 	}
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 	if (!enter_insert_mode || !exit_insert_mode) {
10430Sstevel@tonic-gate 		/*
10440Sstevel@tonic-gate 		 * We are a dumb terminal; brute force update
10450Sstevel@tonic-gate 		 * the rest of the line; this is very much an n^^2 process,
10460Sstevel@tonic-gate 		 * and totally unreasonable at low speed.
10470Sstevel@tonic-gate 		 *
10480Sstevel@tonic-gate 		 * You asked for it, you get it.
10490Sstevel@tonic-gate 		 */
10500Sstevel@tonic-gate 		int width;
10510Sstevel@tonic-gate 		tp = vtube0 + inscol + doomed;
10520Sstevel@tonic-gate 		for (i = inscol + doomed; i < tabstart; i++) {
10530Sstevel@tonic-gate 			if(*tp != FILLER)
1054*802Scf46844 				(void) vputchar(*tp);
10550Sstevel@tonic-gate 			tp++;
10560Sstevel@tonic-gate 		}
10570Sstevel@tonic-gate 		hold = oldhold;
10580Sstevel@tonic-gate 		vigotoCL(tabstart + inssiz - doomed);
10590Sstevel@tonic-gate 		for (i = tabsize - (inssiz - doomed) + shft; i > 0; i--)
1060*802Scf46844 			(void) vputchar(' ' | QUOTE);
10610Sstevel@tonic-gate 	} else {
10620Sstevel@tonic-gate 		if (!insert_null_glitch) {
10630Sstevel@tonic-gate 			/*
10640Sstevel@tonic-gate 			 * On terminals without multi-line
10650Sstevel@tonic-gate 			 * insert in the hardware, we must go fix the segments
10660Sstevel@tonic-gate 			 * between the inserted text and the following
10670Sstevel@tonic-gate 			 * tabs, if they are on different lines.
10680Sstevel@tonic-gate 			 *
10690Sstevel@tonic-gate 			 * Aaargh.
10700Sstevel@tonic-gate 			 */
10710Sstevel@tonic-gate 			tp = vtube0;
10720Sstevel@tonic-gate 			for (j = (inscol + inssiz - 1) / WCOLS + 1;
10730Sstevel@tonic-gate 			    j <= (tabstart + inssiz - doomed - 1) / WCOLS; j++) {
10740Sstevel@tonic-gate 				vgotoCL(j * WCOLS);
10750Sstevel@tonic-gate 				i = inssiz - doomed;
10760Sstevel@tonic-gate 				up = tp + j * WCOLS - i;
10770Sstevel@tonic-gate 				goim();
10780Sstevel@tonic-gate 				do {
10790Sstevel@tonic-gate 					wchar_t wchar;
10800Sstevel@tonic-gate 					if((wchar = *up++) != FILLER)
1081*802Scf46844 						(void) vputchar(wchar);
10820Sstevel@tonic-gate 				} while (--i && *up);
10830Sstevel@tonic-gate 			}
10840Sstevel@tonic-gate 		} else {
10850Sstevel@tonic-gate 			/*
10860Sstevel@tonic-gate 			 * On terminals with multi line inserts,
10870Sstevel@tonic-gate 			 * life is simpler, just reflect eating of
10880Sstevel@tonic-gate 			 * the slack.
10890Sstevel@tonic-gate 			 */
10900Sstevel@tonic-gate 			tp = vtube0 + tabend;
10910Sstevel@tonic-gate 			for (i = tabsize - (inssiz - doomed); i >= 0; i--) {
10920Sstevel@tonic-gate 				if ((*--tp & (QUOTE|TRIM)) == QUOTE) {
10930Sstevel@tonic-gate 					--tabslack;
10940Sstevel@tonic-gate 					if (tabslack >= slakused)
10950Sstevel@tonic-gate 						continue;
10960Sstevel@tonic-gate 				}
10970Sstevel@tonic-gate 				*tp = ' ' | QUOTE;
10980Sstevel@tonic-gate 			}
10990Sstevel@tonic-gate 		}
11000Sstevel@tonic-gate 		/*
11010Sstevel@tonic-gate 		 * Blank out the shifted positions to be tab positions.
11020Sstevel@tonic-gate 		 */
11030Sstevel@tonic-gate 		if (shft) {
11040Sstevel@tonic-gate 			tp = vtube0 + tabend + shft;
11050Sstevel@tonic-gate 			for (i = tabsize - (inssiz - doomed) + shft; i > 0; i--)
11060Sstevel@tonic-gate 				if ((*--tp & QUOTE) == 0)
11070Sstevel@tonic-gate 					*tp = ' ' | QUOTE;
11080Sstevel@tonic-gate 		}
11090Sstevel@tonic-gate 	}
11100Sstevel@tonic-gate 
11110Sstevel@tonic-gate 	/*
11120Sstevel@tonic-gate 	 * Finally, complete the screen image update
11130Sstevel@tonic-gate 	 * to reflect the insertion.
11140Sstevel@tonic-gate 	 */
11150Sstevel@tonic-gate 	hold = oldhold;
11160Sstevel@tonic-gate 	tp = vtube0 + tabstart; up = tp + inssiz - doomed;
11170Sstevel@tonic-gate 	for (i = tabstart; i > inscol + doomed; i--)
11180Sstevel@tonic-gate 		*--up = *--tp;
11190Sstevel@tonic-gate 	for (i = inssiz; i > 0; i--)
11200Sstevel@tonic-gate 		if((c & QUOTE) == 0) {
11210Sstevel@tonic-gate 			int width = wcwidth(c);
11220Sstevel@tonic-gate 			if (width < 0)
11230Sstevel@tonic-gate 				width = 0;
11240Sstevel@tonic-gate 			up -= width;
11250Sstevel@tonic-gate 			*up++ = c;
11260Sstevel@tonic-gate 			if(width)
11270Sstevel@tonic-gate 				while(--width)
11280Sstevel@tonic-gate 					*up++ = FILLER;
11290Sstevel@tonic-gate 			break;
11300Sstevel@tonic-gate 		}
11310Sstevel@tonic-gate 		else
11320Sstevel@tonic-gate 			*--up = c;
11330Sstevel@tonic-gate 	doomed = 0;
11340Sstevel@tonic-gate }
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate /*
11370Sstevel@tonic-gate  * Go into ``delete mode''.  If the
11380Sstevel@tonic-gate  * sequence which goes into delete mode
11390Sstevel@tonic-gate  * is the same as that which goes into insert
11400Sstevel@tonic-gate  * mode, then we are in delete mode already.
11410Sstevel@tonic-gate  */
1142*802Scf46844 void
godm(void)1143*802Scf46844 godm(void)
11440Sstevel@tonic-gate {
11450Sstevel@tonic-gate 
11460Sstevel@tonic-gate 	if (insmode) {
11470Sstevel@tonic-gate 		if (eq(enter_delete_mode, enter_insert_mode))
11480Sstevel@tonic-gate 			return;
11490Sstevel@tonic-gate 		endim();
11500Sstevel@tonic-gate 	}
11510Sstevel@tonic-gate 	vputp(enter_delete_mode, 0);
11520Sstevel@tonic-gate }
11530Sstevel@tonic-gate 
11540Sstevel@tonic-gate /*
11550Sstevel@tonic-gate  * If we are coming out of delete mode, but
11560Sstevel@tonic-gate  * delete and insert mode end with the same sequence,
11570Sstevel@tonic-gate  * it wins to pretend we are now in insert mode,
11580Sstevel@tonic-gate  * since we will likely want to be there again soon
11590Sstevel@tonic-gate  * if we just moved over to delete space from part of
11600Sstevel@tonic-gate  * a tab (above).
11610Sstevel@tonic-gate  */
1162*802Scf46844 void
enddm(void)1163*802Scf46844 enddm(void)
11640Sstevel@tonic-gate {
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate 	if (eq(enter_delete_mode, enter_insert_mode)) {
11670Sstevel@tonic-gate 		insmode = 1;
11680Sstevel@tonic-gate 		return;
11690Sstevel@tonic-gate 	}
11700Sstevel@tonic-gate 	vputp(exit_delete_mode, 0);
11710Sstevel@tonic-gate }
11720Sstevel@tonic-gate 
11730Sstevel@tonic-gate /*
11740Sstevel@tonic-gate  * In and out of insert mode.
11750Sstevel@tonic-gate  * Note that the code here demands that there be
11760Sstevel@tonic-gate  * a string for insert mode (the null string) even
11770Sstevel@tonic-gate  * if the terminal does all insertions a single character
11780Sstevel@tonic-gate  * at a time, since it branches based on whether enter_insert_mode is null.
11790Sstevel@tonic-gate  */
1180*802Scf46844 void
goim(void)1181*802Scf46844 goim(void)
11820Sstevel@tonic-gate {
11830Sstevel@tonic-gate 
11840Sstevel@tonic-gate 	if (!insmode)
11850Sstevel@tonic-gate 		vputp(enter_insert_mode, 0);
11860Sstevel@tonic-gate 	insmode = 1;
11870Sstevel@tonic-gate }
11880Sstevel@tonic-gate 
1189*802Scf46844 void
endim(void)1190*802Scf46844 endim(void)
11910Sstevel@tonic-gate {
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 	if (insmode) {
11940Sstevel@tonic-gate 		vputp(exit_insert_mode, 0);
11950Sstevel@tonic-gate 		insmode = 0;
11960Sstevel@tonic-gate 	}
11970Sstevel@tonic-gate }
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate /*
12000Sstevel@tonic-gate  * Put the character c on the screen at the current cursor position.
12010Sstevel@tonic-gate  * This routine handles wraparound and scrolling and understands not
12020Sstevel@tonic-gate  * to roll when splitw is set, i.e. we are working in the echo area.
12030Sstevel@tonic-gate  * There is a bunch of hacking here dealing with the difference between
12040Sstevel@tonic-gate  * QUOTE, QUOTE|' ', and ' ' for CONCEPT-100 like terminals, and also
12050Sstevel@tonic-gate  * code to deal with terminals which overstrike, including CRT's where
12060Sstevel@tonic-gate  * you can erase overstrikes with some work.  CRT's which do underlining
12070Sstevel@tonic-gate  * implicitly which has to be erased (like CONCEPTS) are also handled.
12080Sstevel@tonic-gate  */
1209*802Scf46844 int
vputchar(wchar_t c)1210*802Scf46844 vputchar(wchar_t c)
12110Sstevel@tonic-gate {
12120Sstevel@tonic-gate 	unsigned char multic[MULTI_BYTE_MAX];
1213*802Scf46844 	wchar_t *tp;
1214*802Scf46844 	int d, length, length2, bytelength;
1215*802Scf46844 	unsigned char *p;
12160Sstevel@tonic-gate 	short oldhold = hold;
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	c &= (QUOTE|TRIM);
12190Sstevel@tonic-gate #ifdef TRACE
12200Sstevel@tonic-gate 	if (trace) {
12210Sstevel@tonic-gate 		tracec(c);
12220Sstevel@tonic-gate 	}
12230Sstevel@tonic-gate #endif
12240Sstevel@tonic-gate 	if(c & QUOTE)
12250Sstevel@tonic-gate 		length = 1;
12260Sstevel@tonic-gate 	else
12270Sstevel@tonic-gate 		if ((length = wcwidth(c)) < 0)
12280Sstevel@tonic-gate 			length = 0;
12290Sstevel@tonic-gate 	/* Fix problem of >79 chars on echo line. */
12300Sstevel@tonic-gate 	if (destcol >= WCOLS-1 && splitw && destline == WECHO)
12310Sstevel@tonic-gate 		pofix();
12320Sstevel@tonic-gate 	if (destcol >= WCOLS) {
12330Sstevel@tonic-gate 		destline += destcol / WCOLS;
12340Sstevel@tonic-gate 		destcol %= WCOLS;
12350Sstevel@tonic-gate 	}
12360Sstevel@tonic-gate 	if (destline > WBOT && (!splitw || destline > WECHO))
12370Sstevel@tonic-gate 		vrollup(destline);
12380Sstevel@tonic-gate 	if (destline < 0)
12390Sstevel@tonic-gate 		error(gettext("Line too long to fit on screen"));
12400Sstevel@tonic-gate 	if(destcol + length - 1 >= WCOLS) {
12410Sstevel@tonic-gate 		/* print out split multibyte character using '>' */
12420Sstevel@tonic-gate 		hold |= HOLDPUPD;
12430Sstevel@tonic-gate #ifdef PRESUNEUC
12440Sstevel@tonic-gate 		while(length--)
1245*802Scf46844 			(void) vputchar('>');
12460Sstevel@tonic-gate #else
12470Sstevel@tonic-gate 		if (mc_wrap == 0)
12480Sstevel@tonic-gate 			while(length--)
1249*802Scf46844 				(void) vputchar(mc_filler);
12500Sstevel@tonic-gate 		else {
12510Sstevel@tonic-gate 			for (length = WCOLS - destcol; length; length--)
1252*802Scf46844 				(void) vputchar(mc_filler);
12530Sstevel@tonic-gate 			hold = oldhold;
12540Sstevel@tonic-gate 			if ((length = wcwidth(c)) < 0)
12550Sstevel@tonic-gate 				length = 0;
1256*802Scf46844 			(void) vputchar(c);
12570Sstevel@tonic-gate 		}
12580Sstevel@tonic-gate #endif /* PRESUNEUC */
12590Sstevel@tonic-gate 		hold = oldhold;
1260*802Scf46844 		return (0);
12610Sstevel@tonic-gate 	}
12620Sstevel@tonic-gate 	tp = vtube[destline] + destcol;
12630Sstevel@tonic-gate 	switch (c) {
12640Sstevel@tonic-gate 
12650Sstevel@tonic-gate 	case '\t':
12660Sstevel@tonic-gate 		vgotab();
1267*802Scf46844 		return (0);
12680Sstevel@tonic-gate 
12690Sstevel@tonic-gate 	case ' ':
12700Sstevel@tonic-gate 		/*
12710Sstevel@tonic-gate 		 * We can get away without printing a space in a number
12720Sstevel@tonic-gate 		 * of cases, but not always.  We get away with doing nothing
12730Sstevel@tonic-gate 		 * if we are not in insert mode, and not on a CONCEPT-100
12740Sstevel@tonic-gate 		 * like terminal, and either not in hardcopy open or in hardcopy
12750Sstevel@tonic-gate 		 * open on a terminal with no overstriking, provided,
12760Sstevel@tonic-gate 		 * in all cases, that nothing has ever been displayed
12770Sstevel@tonic-gate 		 * at this position.  Ugh.
12780Sstevel@tonic-gate 		 */
12790Sstevel@tonic-gate 		if (!insmode && !insert_null_glitch && (state != HARDOPEN || over_strike) && (*tp&TRIM) == 0) {
12800Sstevel@tonic-gate 			*tp = ' ';
12810Sstevel@tonic-gate 			destcol++;
1282*802Scf46844 			return (0);
12830Sstevel@tonic-gate 		}
12840Sstevel@tonic-gate 		goto def;
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate 	case QUOTE:
12870Sstevel@tonic-gate 		if (insmode) {
12880Sstevel@tonic-gate 			/*
12890Sstevel@tonic-gate 			 * When in insert mode, tabs have to expand
12900Sstevel@tonic-gate 			 * to real, printed blanks.
12910Sstevel@tonic-gate 			 */
12920Sstevel@tonic-gate 			c = ' ' | QUOTE;
12930Sstevel@tonic-gate 			goto def;
12940Sstevel@tonic-gate 		}
12950Sstevel@tonic-gate 		if (*tp == 0) {
12960Sstevel@tonic-gate 			/*
12970Sstevel@tonic-gate 			 * A ``space''.
12980Sstevel@tonic-gate 			 */
12990Sstevel@tonic-gate 			if ((hold & HOLDPUPD) == 0)
13000Sstevel@tonic-gate 				*tp = QUOTE;
13010Sstevel@tonic-gate 			destcol++;
1302*802Scf46844 			return (0);
13030Sstevel@tonic-gate 		}
13040Sstevel@tonic-gate 		/*
13050Sstevel@tonic-gate 		 * A ``space'' ontop of a part of a tab.
13060Sstevel@tonic-gate 		 */
13070Sstevel@tonic-gate 		if (*tp & QUOTE) {
13080Sstevel@tonic-gate 			destcol++;
1309*802Scf46844 			return (0);
13100Sstevel@tonic-gate 		}
13110Sstevel@tonic-gate 		c = ' ' | QUOTE;
13120Sstevel@tonic-gate 		/* fall into ... */
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate def:
13150Sstevel@tonic-gate 	default:
13160Sstevel@tonic-gate 		d = *tp & TRIM;
13170Sstevel@tonic-gate 		/*
13180Sstevel@tonic-gate 		 * Now get away with doing nothing if the characters
13190Sstevel@tonic-gate 		 * are the same, provided we are not in insert mode
13200Sstevel@tonic-gate 		 * and if we are in hardopen, that the terminal has overstrike.
13210Sstevel@tonic-gate 		 */
13220Sstevel@tonic-gate #ifdef PRESUNEUC
13230Sstevel@tonic-gate 		if (rewrite == _OFF && d == (c & TRIM) && !insmode && (state != HARDOPEN || over_strike)) {
13240Sstevel@tonic-gate #else
13250Sstevel@tonic-gate 		if (rewrite == _OFF && d == (c & TRIM) && !insmode &&
13260Sstevel@tonic-gate 		    (state != HARDOPEN || over_strike) && !multibyte) {
13270Sstevel@tonic-gate #endif /* PRESUNEUC */
13280Sstevel@tonic-gate 			if ((hold & HOLDPUPD) == 0) {
13290Sstevel@tonic-gate 				*tp++ = c;
13300Sstevel@tonic-gate 				if(length) {
13310Sstevel@tonic-gate 					length2 = length;
13320Sstevel@tonic-gate 					while(--length2)
13330Sstevel@tonic-gate 						*tp++ = FILLER;
13340Sstevel@tonic-gate 				}
13350Sstevel@tonic-gate 			}
13360Sstevel@tonic-gate 			destcol += length;
1337*802Scf46844 			return (0);
13380Sstevel@tonic-gate 		}
13390Sstevel@tonic-gate 		/*
13400Sstevel@tonic-gate 		 * Backwards looking optimization.
13410Sstevel@tonic-gate 		 * The low level cursor motion routines will use
13420Sstevel@tonic-gate 		 * a cursor motion right sequence to step 1 character
13430Sstevel@tonic-gate 		 * right.  On, e.g., a DM3025A this is 2 characters
13440Sstevel@tonic-gate 		 * and printing is noticeably slower at 300 baud.
13450Sstevel@tonic-gate 		 * Since the low level routines are not allowed to use
13460Sstevel@tonic-gate 		 * spaces for positioning, we discover the common
13470Sstevel@tonic-gate 		 * case of a single space here and force a space
13480Sstevel@tonic-gate 		 * to be printed.
13490Sstevel@tonic-gate 		 */
13500Sstevel@tonic-gate 		if (destcol == outcol + 1 && tp[-1] == ' ' && outline == destline) {
1351*802Scf46844 			(void) vputc(' ');
13520Sstevel@tonic-gate 			outcol++;
13530Sstevel@tonic-gate 		}
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate 		/*
13560Sstevel@tonic-gate 		 * This is an inline expansion a call to vcsync() dictated
13570Sstevel@tonic-gate 		 * by high frequency in a profile.
13580Sstevel@tonic-gate 		 */
13590Sstevel@tonic-gate 		if (outcol != destcol || outline != destline)
13600Sstevel@tonic-gate 			vgoto(destline, destcol);
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 		/*
13630Sstevel@tonic-gate 		 * Deal with terminals which have overstrike.
13640Sstevel@tonic-gate 		 * We handle erasing general overstrikes, erasing
13650Sstevel@tonic-gate 		 * underlines on terminals (such as CONCEPTS) which
13660Sstevel@tonic-gate 		 * do underlining correctly automatically (e.g. on nroff
13670Sstevel@tonic-gate 		 * output), and remembering, in hardcopy mode,
13680Sstevel@tonic-gate 		 * that we have overstruct something.
13690Sstevel@tonic-gate 		 */
13700Sstevel@tonic-gate 		if (!insmode && d && d != ' ' && d != (c & TRIM)) {
13710Sstevel@tonic-gate 			if (erase_overstrike && (over_strike || transparent_underline && (c == '_' || d == '_'))) {
1372*802Scf46844 				(void) vputc(' ');
13730Sstevel@tonic-gate 				outcol++, destcol++;
13740Sstevel@tonic-gate 				back1();
13750Sstevel@tonic-gate 			} else
13760Sstevel@tonic-gate 				rubble = 1;
13770Sstevel@tonic-gate 		}
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 		/*
13800Sstevel@tonic-gate 		 * Unless we are just bashing characters around for
13810Sstevel@tonic-gate 		 * inner working of insert mode, update the display.
13820Sstevel@tonic-gate 		 */
13830Sstevel@tonic-gate 		if ((hold & HOLDPUPD) == 0) {
13840Sstevel@tonic-gate 			*tp++ = c;
13850Sstevel@tonic-gate 			length2 = length;
13860Sstevel@tonic-gate 			/* put in filler characters */
13870Sstevel@tonic-gate 			if(length)
13880Sstevel@tonic-gate 				while(--length2)
13890Sstevel@tonic-gate 					*tp++ = FILLER;
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate 		}
13920Sstevel@tonic-gate 		/*
13930Sstevel@tonic-gate 		 * In insert mode, put out the insert_character sequence, padded
13940Sstevel@tonic-gate 		 * based on the depth of the current line.
13950Sstevel@tonic-gate 		 * A terminal which had no real insert mode, rather
13960Sstevel@tonic-gate 		 * opening a character position at a time could do this.
13970Sstevel@tonic-gate 		 * Actually should use depth to end of current line
13980Sstevel@tonic-gate 		 * but this rarely matters.
13990Sstevel@tonic-gate 		 */
14000Sstevel@tonic-gate 		if (insmode)
14010Sstevel@tonic-gate 			vputp(insert_character, DEPTH(vcline));
14020Sstevel@tonic-gate 		c &= TRIM;
14030Sstevel@tonic-gate 		bytelength = wctomb((char *)multic, c);
14040Sstevel@tonic-gate 		p = multic;
14050Sstevel@tonic-gate 		while(bytelength--)
1406*802Scf46844 			(void) vputc(*p++);
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate 		/*
14090Sstevel@tonic-gate 		 * In insert mode, insert_padding is a post insert pad.
14100Sstevel@tonic-gate 		 */
14110Sstevel@tonic-gate 		if (insmode)
14120Sstevel@tonic-gate 			vputp(insert_padding, DEPTH(vcline));
14130Sstevel@tonic-gate 		destcol += length;
14140Sstevel@tonic-gate 		outcol += length;
14150Sstevel@tonic-gate 
14160Sstevel@tonic-gate 		/*
14170Sstevel@tonic-gate 		 * CONCEPT braindamage in early models:  after a wraparound
14180Sstevel@tonic-gate 		 * the next newline is eaten.  It's hungry so we just
14190Sstevel@tonic-gate 		 * feed it now rather than worrying about it.
14200Sstevel@tonic-gate 		 * Fixed to use	return linefeed to work right
14210Sstevel@tonic-gate 		 * on vt100/tab132 as well as concept.
14220Sstevel@tonic-gate 		 */
14230Sstevel@tonic-gate 		if (eat_newline_glitch && outcol % WCOLS == 0) {
1424*802Scf46844 			(void) vputc('\r');
1425*802Scf46844 			(void) vputc('\n');
14260Sstevel@tonic-gate 		}
14270Sstevel@tonic-gate 	}
1428*802Scf46844 	return (0);
14290Sstevel@tonic-gate }
14300Sstevel@tonic-gate 
14310Sstevel@tonic-gate /*
14320Sstevel@tonic-gate  * Delete display positions stcol through endcol.
14330Sstevel@tonic-gate  * Amount of use of special terminal features here is limited.
14340Sstevel@tonic-gate  */
1435*802Scf46844 void
1436*802Scf46844 physdc(int stcol, int endcol)
14370Sstevel@tonic-gate {
1438*802Scf46844 	wchar_t *tp, *up;
14390Sstevel@tonic-gate 	wchar_t *tpe;
1440*802Scf46844 	int i;
1441*802Scf46844 	int nc = endcol - stcol;
14420Sstevel@tonic-gate 
14430Sstevel@tonic-gate #ifdef IDEBUG
14440Sstevel@tonic-gate 	if (trace)
14450Sstevel@tonic-gate 		tfixnl(), fprintf(trace, "physdc(%d, %d)\n", stcol, endcol);
14460Sstevel@tonic-gate #endif
14470Sstevel@tonic-gate 	if (!delete_character || nc <= 0)
14480Sstevel@tonic-gate 		return;
14490Sstevel@tonic-gate 	if (insert_null_glitch) {
14500Sstevel@tonic-gate 		/*
14510Sstevel@tonic-gate 		 * CONCEPT-100 like terminal.
14520Sstevel@tonic-gate 		 * If there are any ``spaces'' in the material to be
14530Sstevel@tonic-gate 		 * deleted, then this is too hard, just retype.
14540Sstevel@tonic-gate 		 */
14550Sstevel@tonic-gate 		vprepins();
14560Sstevel@tonic-gate 		up = vtube0 + stcol;
14570Sstevel@tonic-gate 		i = nc;
14580Sstevel@tonic-gate 		do
14590Sstevel@tonic-gate 			if ((*up++ & (QUOTE|TRIM)) == QUOTE)
14600Sstevel@tonic-gate 				return;
14610Sstevel@tonic-gate 		while (--i);
14620Sstevel@tonic-gate 		i = 2 * nc;
14630Sstevel@tonic-gate 		do
14640Sstevel@tonic-gate 			if (*up == 0 || (*up++ & QUOTE) == QUOTE)
14650Sstevel@tonic-gate 				return;
14660Sstevel@tonic-gate 		while (--i);
14670Sstevel@tonic-gate 		vgotoCL(stcol);
14680Sstevel@tonic-gate 	} else {
14690Sstevel@tonic-gate 		/*
14700Sstevel@tonic-gate 		 * HP like delete mode.
14710Sstevel@tonic-gate 		 * Compute how much text we are moving over by deleting.
14720Sstevel@tonic-gate 		 * If it appears to be faster to just retype
14730Sstevel@tonic-gate 		 * the line, do nothing and that will be done later.
14740Sstevel@tonic-gate 		 * We are assuming 2 output characters per deleted
14750Sstevel@tonic-gate 		 * characters and that clear to end of line is available.
14760Sstevel@tonic-gate 		 */
14770Sstevel@tonic-gate 		i = stcol / WCOLS;
14780Sstevel@tonic-gate 		if (i != endcol / WCOLS)
14790Sstevel@tonic-gate 			return;
14800Sstevel@tonic-gate 		i += LINE(vcline);
14810Sstevel@tonic-gate 		stcol %= WCOLS;
14820Sstevel@tonic-gate 		endcol %= WCOLS;
14830Sstevel@tonic-gate 		up = vtube[i]; tp = up + endcol; tpe = up + WCOLS;
14840Sstevel@tonic-gate 		while (tp < tpe && *tp)
14850Sstevel@tonic-gate 			tp++;
14860Sstevel@tonic-gate 		if (tp - (up + stcol) < 2 * nc)
14870Sstevel@tonic-gate 			return;
14880Sstevel@tonic-gate 		vgoto(i, stcol);
14890Sstevel@tonic-gate 	}
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate 	/*
14920Sstevel@tonic-gate 	 * Go into delete mode and do the actual delete.
14930Sstevel@tonic-gate 	 * Padding is on delete_character itself.
14940Sstevel@tonic-gate 	 */
14950Sstevel@tonic-gate 	godm();
14960Sstevel@tonic-gate 	for (i = nc; i > 0; i--)
14970Sstevel@tonic-gate 		vputp(delete_character, DEPTH(vcline));
14980Sstevel@tonic-gate 	vputp(exit_delete_mode, 0);
14990Sstevel@tonic-gate 
15000Sstevel@tonic-gate 	/*
15010Sstevel@tonic-gate 	 * Straighten up.
15020Sstevel@tonic-gate 	 * With CONCEPT like terminals, characters are pulled left
15030Sstevel@tonic-gate 	 * from first following null.  HP like terminals shift rest of
15040Sstevel@tonic-gate 	 * this (single physical) line rigidly.
15050Sstevel@tonic-gate 	 */
15060Sstevel@tonic-gate 	if (insert_null_glitch) {
15070Sstevel@tonic-gate 		up = vtube0 + stcol;
15080Sstevel@tonic-gate 		tp = vtube0 + endcol;
15090Sstevel@tonic-gate 		while (i = *tp++) {
15100Sstevel@tonic-gate 			if ((i & (QUOTE|TRIM)) == QUOTE)
15110Sstevel@tonic-gate 				break;
15120Sstevel@tonic-gate 			*up++ = i;
15130Sstevel@tonic-gate 		}
15140Sstevel@tonic-gate 		do
15150Sstevel@tonic-gate 			*up++ = i;
15160Sstevel@tonic-gate 		while (--nc);
15170Sstevel@tonic-gate 	} else {
15180Sstevel@tonic-gate 		copy(up + stcol, up + endcol, (WCOLS - endcol) * sizeof(wchar_t));
15190Sstevel@tonic-gate 		vclrbyte(tpe - nc, nc);
15200Sstevel@tonic-gate 	}
15210Sstevel@tonic-gate }
15220Sstevel@tonic-gate 
15230Sstevel@tonic-gate #ifdef TRACE
15240Sstevel@tonic-gate tfixnl()
15250Sstevel@tonic-gate {
15260Sstevel@tonic-gate 
15270Sstevel@tonic-gate 	if (trubble || techoin)
15280Sstevel@tonic-gate 		fprintf(trace, "\n");
15290Sstevel@tonic-gate 	trubble = 0, techoin = 0;
15300Sstevel@tonic-gate }
15310Sstevel@tonic-gate 
15320Sstevel@tonic-gate tvliny()
15330Sstevel@tonic-gate {
1534*802Scf46844 	int i;
15350Sstevel@tonic-gate 
15360Sstevel@tonic-gate 	if (!trace)
15370Sstevel@tonic-gate 		return;
15380Sstevel@tonic-gate 	tfixnl();
15390Sstevel@tonic-gate 	fprintf(trace, "vcnt = %d, vcline = %d, vliny = ", vcnt, vcline);
15400Sstevel@tonic-gate 	for (i = 0; i <= vcnt; i++) {
15410Sstevel@tonic-gate 		fprintf(trace, "%d", LINE(i));
15420Sstevel@tonic-gate 		if (FLAGS(i) & VDIRT)
15430Sstevel@tonic-gate 			fprintf(trace, "*");
15440Sstevel@tonic-gate 		if (DEPTH(i) != 1)
15450Sstevel@tonic-gate 			fprintf(trace, "<%d>", DEPTH(i));
15460Sstevel@tonic-gate 		if (i < vcnt)
15470Sstevel@tonic-gate 			fprintf(trace, " ");
15480Sstevel@tonic-gate 	}
15490Sstevel@tonic-gate 	fprintf(trace, "\n");
15500Sstevel@tonic-gate }
15510Sstevel@tonic-gate 
15520Sstevel@tonic-gate tracec(c)
15530Sstevel@tonic-gate 	int c;		/* char --> int */
15540Sstevel@tonic-gate {
15550Sstevel@tonic-gate 
15560Sstevel@tonic-gate 	if (!techoin)
15570Sstevel@tonic-gate 		trubble = 1;
15580Sstevel@tonic-gate 	if (c == ESCAPE)
15590Sstevel@tonic-gate 		fprintf(trace, "$");
15600Sstevel@tonic-gate 	else if (c & QUOTE)	/* for 3B (no sign extension) */
15610Sstevel@tonic-gate 		fprintf(trace, "~%c", ctlof(c&TRIM));
15620Sstevel@tonic-gate 	else if (c < ' ' || c == DELETE)
15630Sstevel@tonic-gate 		fprintf(trace, "^%c", ctlof(c));
15640Sstevel@tonic-gate 	else
15650Sstevel@tonic-gate 		fprintf(trace, "%c", c);
15660Sstevel@tonic-gate }
15670Sstevel@tonic-gate #endif
15680Sstevel@tonic-gate 
15690Sstevel@tonic-gate /*
15700Sstevel@tonic-gate  * Put a character with possible tracing.
15710Sstevel@tonic-gate  */
15720Sstevel@tonic-gate int
15730Sstevel@tonic-gate vputch(char c)
15740Sstevel@tonic-gate {
15750Sstevel@tonic-gate 
15760Sstevel@tonic-gate #ifdef TRACE
15770Sstevel@tonic-gate 	if (trace) {
15780Sstevel@tonic-gate 		tracec(c);
15790Sstevel@tonic-gate 	}
15800Sstevel@tonic-gate #endif
1581*802Scf46844 	(void) vputc(c);
1582*802Scf46844 	return (0);
15830Sstevel@tonic-gate }
1584