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