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