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 */ 22*802Scf46844 /* 23*802Scf46844 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*802Scf46844 * Use is subject to license terms. 25*802Scf46844 */ 26*802Scf46844 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 */ 32*802Scf46844 33*802Scf46844 #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 #ifndef PRESUNEUC 390Sstevel@tonic-gate #include <wctype.h> 400Sstevel@tonic-gate /* Undef putchar/getchar if they're defined. */ 410Sstevel@tonic-gate #ifdef putchar 420Sstevel@tonic-gate # undef putchar 430Sstevel@tonic-gate #endif 440Sstevel@tonic-gate #ifdef getchar 450Sstevel@tonic-gate # undef getchar 460Sstevel@tonic-gate #endif 470Sstevel@tonic-gate #endif /* PRESUNEUC */ 480Sstevel@tonic-gate 490Sstevel@tonic-gate /* 500Sstevel@tonic-gate * This is the main routine for visual. 510Sstevel@tonic-gate * We here decode the count and possible named buffer specification 520Sstevel@tonic-gate * preceding a command and interpret a few of the commands. 530Sstevel@tonic-gate * Commands which involve a target (i.e. an operator) are decoded 540Sstevel@tonic-gate * in the routine operate in ex_voperate.c. 550Sstevel@tonic-gate */ 560Sstevel@tonic-gate 570Sstevel@tonic-gate #define forbid(a) { if (a) goto fonfon; } 580Sstevel@tonic-gate 590Sstevel@tonic-gate extern int windowchg; 600Sstevel@tonic-gate extern int sigok; 610Sstevel@tonic-gate void redraw(), windowinit(); 620Sstevel@tonic-gate 630Sstevel@tonic-gate #ifdef XPG4 640Sstevel@tonic-gate extern int P_cursor_offset; 650Sstevel@tonic-gate #endif 660Sstevel@tonic-gate 67*802Scf46844 void 68*802Scf46844 vmain(void) 690Sstevel@tonic-gate { 70*802Scf46844 int c, cnt, i; 710Sstevel@tonic-gate wchar_t esave[TUBECOLS]; 720Sstevel@tonic-gate extern wchar_t atube[]; 730Sstevel@tonic-gate unsigned char *oglobp; 740Sstevel@tonic-gate short d; 750Sstevel@tonic-gate line *addr; 760Sstevel@tonic-gate int ind, nlput; 770Sstevel@tonic-gate int shouldpo = 0; 780Sstevel@tonic-gate int tag_reset_wrap = 0; 790Sstevel@tonic-gate int onumber, olist, (*OPline)(), (*OPutchar)(); 800Sstevel@tonic-gate 810Sstevel@tonic-gate 820Sstevel@tonic-gate vch_mac = VC_NOTINMAC; 830Sstevel@tonic-gate ixlatctl(0); 840Sstevel@tonic-gate 850Sstevel@tonic-gate /* 860Sstevel@tonic-gate * If we started as a vi command (on the command line) 870Sstevel@tonic-gate * then go process initial commands (recover, next or tag). 880Sstevel@tonic-gate */ 890Sstevel@tonic-gate if (initev) { 900Sstevel@tonic-gate oglobp = globp; 910Sstevel@tonic-gate globp = initev; 920Sstevel@tonic-gate hadcnt = cnt = 0; 930Sstevel@tonic-gate i = tchng; 940Sstevel@tonic-gate addr = dot; 950Sstevel@tonic-gate goto doinit; 960Sstevel@tonic-gate } 970Sstevel@tonic-gate 980Sstevel@tonic-gate vshowmode(""); /* As a precaution */ 990Sstevel@tonic-gate /* 1000Sstevel@tonic-gate * NB: 1010Sstevel@tonic-gate * 1020Sstevel@tonic-gate * The current line is always in the line buffer linebuf, 1030Sstevel@tonic-gate * and the cursor at the position cursor. You should do 1040Sstevel@tonic-gate * a vsave() before moving off the line to make sure the disk 1050Sstevel@tonic-gate * copy is updated if it has changed, and a getDOT() to get 1060Sstevel@tonic-gate * the line back if you mung linebuf. The motion 1070Sstevel@tonic-gate * routines in ex_vwind.c handle most of this. 1080Sstevel@tonic-gate */ 1090Sstevel@tonic-gate for (;;) { 1100Sstevel@tonic-gate /* 1110Sstevel@tonic-gate * Decode a visual command. 1120Sstevel@tonic-gate * First sync the temp file if there has been a reasonable 1130Sstevel@tonic-gate * amount of change. Clear state for decoding of next 1140Sstevel@tonic-gate * command. 1150Sstevel@tonic-gate */ 1160Sstevel@tonic-gate TSYNC(); 1170Sstevel@tonic-gate vglobp = 0; 1180Sstevel@tonic-gate vreg = 0; 1190Sstevel@tonic-gate hold = 0; 1200Sstevel@tonic-gate seenprompt = 1; 1210Sstevel@tonic-gate wcursor = 0; 1220Sstevel@tonic-gate Xhadcnt = hadcnt = 0; 1230Sstevel@tonic-gate Xcnt = cnt = 1; 1240Sstevel@tonic-gate splitw = 0; 1250Sstevel@tonic-gate if (i = holdupd && !windowchg) { 1260Sstevel@tonic-gate if (state == VISUAL) { 1270Sstevel@tonic-gate sigok = 1; 1280Sstevel@tonic-gate (void)peekkey(); 1290Sstevel@tonic-gate sigok = 0; 1300Sstevel@tonic-gate } 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate holdupd = 0; 1330Sstevel@tonic-gate /* 1340Sstevel@tonic-gate if (LINE(0) < ZERO) { 1350Sstevel@tonic-gate vclear(); 1360Sstevel@tonic-gate vcnt = 0; 1370Sstevel@tonic-gate i = 3; 1380Sstevel@tonic-gate } 1390Sstevel@tonic-gate */ 1400Sstevel@tonic-gate if (state != VISUAL) { 1410Sstevel@tonic-gate vcnt = 0; 1420Sstevel@tonic-gate vsave(); 1430Sstevel@tonic-gate vrepaint(cursor); 1440Sstevel@tonic-gate } else if (i == 3) 1450Sstevel@tonic-gate vredraw(WTOP); 1460Sstevel@tonic-gate else 1470Sstevel@tonic-gate vsync(WTOP); 1480Sstevel@tonic-gate vfixcurs(); 1490Sstevel@tonic-gate } else if(windowchg) 1500Sstevel@tonic-gate redraw(); 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate /* 1530Sstevel@tonic-gate * Gobble up counts and named buffer specifications. 1540Sstevel@tonic-gate */ 1550Sstevel@tonic-gate for (;;) { 1560Sstevel@tonic-gate looptop: 1570Sstevel@tonic-gate #ifdef MDEBUG 1580Sstevel@tonic-gate if (trace) 1590Sstevel@tonic-gate fprintf(trace, "pc=%c",peekkey()); 1600Sstevel@tonic-gate #endif 1610Sstevel@tonic-gate sigok = 1; 1620Sstevel@tonic-gate c = peekkey(); 1630Sstevel@tonic-gate sigok = 0; 1640Sstevel@tonic-gate if (isdigit(peekkey()) && peekkey() != '0') { 1650Sstevel@tonic-gate hadcnt = 1; 1660Sstevel@tonic-gate cnt = vgetcnt(); 1670Sstevel@tonic-gate forbid (cnt <= 0); 1680Sstevel@tonic-gate } 1690Sstevel@tonic-gate if (peekkey() != '"') 1700Sstevel@tonic-gate break; 1710Sstevel@tonic-gate (void)getkey(), c = getkey(); 1720Sstevel@tonic-gate /* 1730Sstevel@tonic-gate * Buffer names be letters or digits. 1740Sstevel@tonic-gate * But not '0' as that is the source of 1750Sstevel@tonic-gate * an 'empty' named buffer spec in the routine 1760Sstevel@tonic-gate * kshift (see ex_temp.c). 1770Sstevel@tonic-gate */ 1780Sstevel@tonic-gate if(!isascii(c) && MB_CUR_MAX > 1) { 1790Sstevel@tonic-gate /* get rest of character */ 1800Sstevel@tonic-gate wchar_t wchar; 1810Sstevel@tonic-gate char multic[MULTI_BYTE_MAX]; 1820Sstevel@tonic-gate ungetkey(c); 1830Sstevel@tonic-gate (void)_mbftowc(multic, &wchar, getkey, &Peekkey); 1840Sstevel@tonic-gate } 1850Sstevel@tonic-gate forbid (c == '0' || !isalpha(c) && !isascii(c) && !isdigit(c)); 1860Sstevel@tonic-gate vreg = c; 1870Sstevel@tonic-gate } 1880Sstevel@tonic-gate reread: 1890Sstevel@tonic-gate /* 1900Sstevel@tonic-gate * Come to reread from below after some macro expansions. 1910Sstevel@tonic-gate * The call to map allows use of function key pads 1920Sstevel@tonic-gate * by performing a terminal dependent mapping of inputs. 1930Sstevel@tonic-gate */ 1940Sstevel@tonic-gate #ifdef MDEBUG 1950Sstevel@tonic-gate if (trace) 1960Sstevel@tonic-gate fprintf(trace,"pcb=%c,",peekkey()); 1970Sstevel@tonic-gate #endif 1980Sstevel@tonic-gate op = getkey(); 1990Sstevel@tonic-gate maphopcnt = 0; 2000Sstevel@tonic-gate do { 2010Sstevel@tonic-gate /* 2020Sstevel@tonic-gate * Keep mapping the char as long as it changes. 2030Sstevel@tonic-gate * This allows for double mappings, e.g., q to #, 2040Sstevel@tonic-gate * #1 to something else. 2050Sstevel@tonic-gate */ 2060Sstevel@tonic-gate c = op; 207*802Scf46844 op = map(c, arrows, 0); 2080Sstevel@tonic-gate #ifdef MDEBUG 2090Sstevel@tonic-gate if (trace) 2100Sstevel@tonic-gate fprintf(trace,"pca=%c,",c); 2110Sstevel@tonic-gate #endif 2120Sstevel@tonic-gate /* 2130Sstevel@tonic-gate * Maybe the mapped to char is a count. If so, we have 2140Sstevel@tonic-gate * to go back to the "for" to interpret it. Likewise 2150Sstevel@tonic-gate * for a buffer name. 2160Sstevel@tonic-gate */ 2170Sstevel@tonic-gate if ((isdigit(c) && c!='0') || c == '"') { 2180Sstevel@tonic-gate ungetkey(c); 2190Sstevel@tonic-gate goto looptop; 2200Sstevel@tonic-gate } 2210Sstevel@tonic-gate if (!value(vi_REMAP)) { 2220Sstevel@tonic-gate c = op; 2230Sstevel@tonic-gate break; 2240Sstevel@tonic-gate } 2250Sstevel@tonic-gate if (++maphopcnt > 256) 2260Sstevel@tonic-gate error(gettext("Infinite macro loop")); 2270Sstevel@tonic-gate } while (c != op); 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate /* 2300Sstevel@tonic-gate * Begin to build an image of this command for possible 2310Sstevel@tonic-gate * later repeat in the buffer workcmd. It will be copied 2320Sstevel@tonic-gate * to lastcmd by the routine setLAST 2330Sstevel@tonic-gate * if/when completely specified. 2340Sstevel@tonic-gate */ 2350Sstevel@tonic-gate lastcp = workcmd; 2360Sstevel@tonic-gate if (!vglobp) 2370Sstevel@tonic-gate *lastcp++ = c; 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate /* 2400Sstevel@tonic-gate * First level command decode. 2410Sstevel@tonic-gate */ 2420Sstevel@tonic-gate switch (c) { 2430Sstevel@tonic-gate 2440Sstevel@tonic-gate /* 2450Sstevel@tonic-gate * ^L Clear screen e.g. after transmission error. 2460Sstevel@tonic-gate */ 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate /* 2490Sstevel@tonic-gate * ^R Retype screen, getting rid of @ lines. 2500Sstevel@tonic-gate * If in open, equivalent to ^L. 2510Sstevel@tonic-gate * On terminals where the right arrow key sends 2520Sstevel@tonic-gate * ^L we make ^R act like ^L, since there is no 2530Sstevel@tonic-gate * way to get ^L. These terminals (adm31, tvi) 2540Sstevel@tonic-gate * are intelligent so ^R is useless. Soroc 2550Sstevel@tonic-gate * will probably foul this up, but nobody has 2560Sstevel@tonic-gate * one of them. 2570Sstevel@tonic-gate */ 2580Sstevel@tonic-gate case CTRL('l'): 2590Sstevel@tonic-gate case CTRL('r'): 2600Sstevel@tonic-gate if (c == CTRL('l') || (key_right && *key_right==CTRL('l'))) { 2610Sstevel@tonic-gate vclear(); 2620Sstevel@tonic-gate vdirty(0, vcnt); 2630Sstevel@tonic-gate } 2640Sstevel@tonic-gate if (state != VISUAL) { 2650Sstevel@tonic-gate /* 2660Sstevel@tonic-gate * Get a clean line, throw away the 2670Sstevel@tonic-gate * memory of what is displayed now, 2680Sstevel@tonic-gate * and move back onto the current line. 2690Sstevel@tonic-gate */ 2700Sstevel@tonic-gate vclean(); 2710Sstevel@tonic-gate vcnt = 0; 2720Sstevel@tonic-gate vmoveto(dot, cursor, 0); 2730Sstevel@tonic-gate continue; 2740Sstevel@tonic-gate } 2750Sstevel@tonic-gate vredraw(WTOP); 2760Sstevel@tonic-gate /* 2770Sstevel@tonic-gate * Weird glitch -- when we enter visual 2780Sstevel@tonic-gate * in a very small window we may end up with 2790Sstevel@tonic-gate * no lines on the screen because the line 2800Sstevel@tonic-gate * at the top is too long. This forces the screen 2810Sstevel@tonic-gate * to be expanded to make room for it (after 2820Sstevel@tonic-gate * we have printed @'s ick showing we goofed). 2830Sstevel@tonic-gate */ 2840Sstevel@tonic-gate if (vcnt == 0) 2850Sstevel@tonic-gate vrepaint(cursor); 2860Sstevel@tonic-gate vfixcurs(); 2870Sstevel@tonic-gate continue; 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate /* 2900Sstevel@tonic-gate * $ Escape just cancels the current command 2910Sstevel@tonic-gate * with a little feedback. 2920Sstevel@tonic-gate */ 2930Sstevel@tonic-gate case ESCAPE: 294*802Scf46844 (void) beep(); 2950Sstevel@tonic-gate continue; 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate /* 2980Sstevel@tonic-gate * @ Macros. Bring in the macro and put it 2990Sstevel@tonic-gate * in vmacbuf, point vglobp there and punt. 3000Sstevel@tonic-gate */ 3010Sstevel@tonic-gate case '@': 3020Sstevel@tonic-gate c = getesc(); 3030Sstevel@tonic-gate if (c == 0) 3040Sstevel@tonic-gate continue; 3050Sstevel@tonic-gate if (c == '@') 3060Sstevel@tonic-gate c = lastmac; 3070Sstevel@tonic-gate if (isupper(c)) 3080Sstevel@tonic-gate c = tolower(c); 3090Sstevel@tonic-gate forbid(!islower(c)); 3100Sstevel@tonic-gate lastmac = c; 3110Sstevel@tonic-gate vsave(); 3120Sstevel@tonic-gate CATCH 3130Sstevel@tonic-gate unsigned char tmpbuf[BUFSIZE]; 3140Sstevel@tonic-gate 315*802Scf46844 regbuf(c, tmpbuf, sizeof (vmacbuf)); 3160Sstevel@tonic-gate macpush(tmpbuf, 1); 3170Sstevel@tonic-gate ONERR 3180Sstevel@tonic-gate lastmac = 0; 3190Sstevel@tonic-gate splitw = 0; 3200Sstevel@tonic-gate getDOT(); 3210Sstevel@tonic-gate vrepaint(cursor); 3220Sstevel@tonic-gate continue; 3230Sstevel@tonic-gate ENDCATCH 3240Sstevel@tonic-gate vmacp = vmacbuf; 3250Sstevel@tonic-gate goto reread; 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate /* 3280Sstevel@tonic-gate * . Repeat the last (modifying) open/visual command. 3290Sstevel@tonic-gate */ 3300Sstevel@tonic-gate case '.': 3310Sstevel@tonic-gate /* 3320Sstevel@tonic-gate * Check that there was a last command, and 3330Sstevel@tonic-gate * take its count and named buffer unless they 3340Sstevel@tonic-gate * were given anew. Special case if last command 3350Sstevel@tonic-gate * referenced a numeric named buffer -- increment 3360Sstevel@tonic-gate * the number and go to a named buffer again. 3370Sstevel@tonic-gate * This allows a sequence like "1pu.u.u... 3380Sstevel@tonic-gate * to successively look for stuff in the kill chain 3390Sstevel@tonic-gate * much as one does in EMACS with C-Y and M-Y. 3400Sstevel@tonic-gate */ 3410Sstevel@tonic-gate forbid (lastcmd[0] == 0); 3420Sstevel@tonic-gate if (hadcnt) 3430Sstevel@tonic-gate lastcnt = cnt; 3440Sstevel@tonic-gate if (vreg) 3450Sstevel@tonic-gate lastreg = vreg; 3460Sstevel@tonic-gate else if (isdigit(lastreg) && lastreg < '9') 3470Sstevel@tonic-gate lastreg++; 3480Sstevel@tonic-gate vreg = lastreg; 3490Sstevel@tonic-gate cnt = lastcnt; 3500Sstevel@tonic-gate hadcnt = lasthad; 3510Sstevel@tonic-gate vglobp = lastcmd; 3520Sstevel@tonic-gate goto reread; 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate /* 3550Sstevel@tonic-gate * ^U Scroll up. A count sticks around for 3560Sstevel@tonic-gate * future scrolls as the scroll amount. 3570Sstevel@tonic-gate * Attempt to hold the indentation from the 3580Sstevel@tonic-gate * top of the screen (in logical lines). 3590Sstevel@tonic-gate * 3600Sstevel@tonic-gate * BUG: A ^U near the bottom of the screen 3610Sstevel@tonic-gate * on a dumb terminal (which can't roll back) 3620Sstevel@tonic-gate * causes the screen to be cleared and then 3630Sstevel@tonic-gate * redrawn almost as it was. In this case 3640Sstevel@tonic-gate * one should simply move the cursor. 3650Sstevel@tonic-gate */ 3660Sstevel@tonic-gate case CTRL('u'): 3670Sstevel@tonic-gate if (hadcnt) 3680Sstevel@tonic-gate vSCROLL = cnt; 3690Sstevel@tonic-gate cnt = vSCROLL; 3700Sstevel@tonic-gate if (state == VISUAL) 3710Sstevel@tonic-gate ind = vcline, cnt += ind; 3720Sstevel@tonic-gate else 3730Sstevel@tonic-gate ind = 0; 3740Sstevel@tonic-gate vmoving = 0; 3750Sstevel@tonic-gate vup(cnt, ind, 1); 376*802Scf46844 vnline((unsigned char *)NOSTR); 3770Sstevel@tonic-gate continue; 3780Sstevel@tonic-gate 3790Sstevel@tonic-gate /* 3800Sstevel@tonic-gate * ^D Scroll down. Like scroll up. 3810Sstevel@tonic-gate */ 3820Sstevel@tonic-gate case CTRL('d'): 3830Sstevel@tonic-gate #ifdef TRACE 3840Sstevel@tonic-gate if (trace) 3850Sstevel@tonic-gate fprintf(trace, "before vdown in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol)); 3860Sstevel@tonic-gate #endif 3870Sstevel@tonic-gate if (hadcnt) 3880Sstevel@tonic-gate vSCROLL = cnt; 3890Sstevel@tonic-gate cnt = vSCROLL; 3900Sstevel@tonic-gate if (state == VISUAL) 3910Sstevel@tonic-gate ind = vcnt - vcline - 1, cnt += ind; 3920Sstevel@tonic-gate else 3930Sstevel@tonic-gate ind = 0; 3940Sstevel@tonic-gate vmoving = 0; 3950Sstevel@tonic-gate vdown(cnt, ind, 1); 3960Sstevel@tonic-gate #ifdef TRACE 3970Sstevel@tonic-gate if (trace) 3980Sstevel@tonic-gate fprintf(trace, "before vnline in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol)); 3990Sstevel@tonic-gate #endif 400*802Scf46844 vnline((unsigned char *)NOSTR); 4010Sstevel@tonic-gate #ifdef TRACE 4020Sstevel@tonic-gate if (trace) 4030Sstevel@tonic-gate fprintf(trace, "after vnline in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol)); 4040Sstevel@tonic-gate #endif 4050Sstevel@tonic-gate continue; 4060Sstevel@tonic-gate 4070Sstevel@tonic-gate /* 4080Sstevel@tonic-gate * ^E Glitch the screen down (one) line. 4090Sstevel@tonic-gate * Cursor left on same line in file. 4100Sstevel@tonic-gate */ 4110Sstevel@tonic-gate case CTRL('e'): 4120Sstevel@tonic-gate if (state != VISUAL) 4130Sstevel@tonic-gate continue; 4140Sstevel@tonic-gate if (!hadcnt) 4150Sstevel@tonic-gate cnt = 1; 4160Sstevel@tonic-gate /* Bottom line of file already on screen */ 4170Sstevel@tonic-gate forbid(lineDOL()-lineDOT() <= vcnt-1-vcline); 4180Sstevel@tonic-gate ind = vcnt - vcline - 1 + cnt; 4190Sstevel@tonic-gate vdown(ind, ind, 1); 4200Sstevel@tonic-gate vnline(cursor); 4210Sstevel@tonic-gate continue; 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate /* 4240Sstevel@tonic-gate * ^Y Like ^E but up 4250Sstevel@tonic-gate */ 4260Sstevel@tonic-gate case CTRL('y'): 4270Sstevel@tonic-gate if (state != VISUAL) 4280Sstevel@tonic-gate continue; 4290Sstevel@tonic-gate if (!hadcnt) 4300Sstevel@tonic-gate cnt = 1; 4310Sstevel@tonic-gate forbid(lineDOT()-1<=vcline); /* line 1 already there */ 4320Sstevel@tonic-gate ind = vcline + cnt; 4330Sstevel@tonic-gate vup(ind, ind, 1); 4340Sstevel@tonic-gate vnline(cursor); 4350Sstevel@tonic-gate continue; 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate 4380Sstevel@tonic-gate /* 4390Sstevel@tonic-gate * m Mark position in mark register given 4400Sstevel@tonic-gate * by following letter. Return is 4410Sstevel@tonic-gate * accomplished via ' or `; former 4420Sstevel@tonic-gate * to beginning of line where mark 4430Sstevel@tonic-gate * was set, latter to column where marked. 4440Sstevel@tonic-gate */ 4450Sstevel@tonic-gate case 'm': 4460Sstevel@tonic-gate /* 4470Sstevel@tonic-gate * Getesc is generally used when a character 4480Sstevel@tonic-gate * is read as a latter part of a command 4490Sstevel@tonic-gate * to allow one to hit rubout/escape to cancel 4500Sstevel@tonic-gate * what you have typed so far. These characters 4510Sstevel@tonic-gate * are mapped to 0 by the subroutine. 4520Sstevel@tonic-gate */ 4530Sstevel@tonic-gate c = getesc(); 4540Sstevel@tonic-gate if (c == 0) 4550Sstevel@tonic-gate continue; 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate /* 4580Sstevel@tonic-gate * Markreg checks that argument is a letter 4590Sstevel@tonic-gate * and also maps ' and ` to the end of the range 4600Sstevel@tonic-gate * to allow '' or `` to reference the previous 4610Sstevel@tonic-gate * context mark. 4620Sstevel@tonic-gate */ 4630Sstevel@tonic-gate c = markreg(c); 4640Sstevel@tonic-gate forbid (c == 0); 4650Sstevel@tonic-gate vsave(); 4660Sstevel@tonic-gate names[c - 'a'] = (*dot &~ 01); 4670Sstevel@tonic-gate ncols[c - 'a'] = cursor; 4680Sstevel@tonic-gate anymarks = 1; 4690Sstevel@tonic-gate continue; 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate /* 4720Sstevel@tonic-gate * ^F Window forwards, with 2 lines of continuity. 4730Sstevel@tonic-gate * Count repeats. 4740Sstevel@tonic-gate */ 4750Sstevel@tonic-gate case CTRL('f'): 4760Sstevel@tonic-gate vsave(); 4770Sstevel@tonic-gate if (vcnt > 2) { 4780Sstevel@tonic-gate addr = dot + (vcnt - vcline) - 2 + (cnt-1)*basWLINES; 4790Sstevel@tonic-gate forbid(addr > dol); 4800Sstevel@tonic-gate dot = addr; 4810Sstevel@tonic-gate vcnt = vcline = 0; 4820Sstevel@tonic-gate } 4830Sstevel@tonic-gate vzop(0, 0, '+'); 4840Sstevel@tonic-gate continue; 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate /* 4870Sstevel@tonic-gate * ^B Window backwards, with 2 lines of continuity. 4880Sstevel@tonic-gate * Inverse of ^F. 4890Sstevel@tonic-gate */ 4900Sstevel@tonic-gate case CTRL('b'): 4910Sstevel@tonic-gate vsave(); 4920Sstevel@tonic-gate if (one + vcline != dot && vcnt > 2) { 4930Sstevel@tonic-gate addr = dot - vcline + 2 - (cnt-1)*basWLINES; 4940Sstevel@tonic-gate forbid (addr <= zero); 4950Sstevel@tonic-gate dot = addr; 4960Sstevel@tonic-gate vcnt = vcline = 0; 4970Sstevel@tonic-gate } 4980Sstevel@tonic-gate vzop(0, 0, '^'); 4990Sstevel@tonic-gate continue; 5000Sstevel@tonic-gate 5010Sstevel@tonic-gate /* 5020Sstevel@tonic-gate * z Screen adjustment, taking a following character: 5030Sstevel@tonic-gate * zcarriage_return current line to top 5040Sstevel@tonic-gate * z<NL> like zcarriage_return 5050Sstevel@tonic-gate * z- current line to bottom 5060Sstevel@tonic-gate * also z+, z^ like ^F and ^B. 5070Sstevel@tonic-gate * A preceding count is line to use rather 5080Sstevel@tonic-gate * than current line. A count between z and 5090Sstevel@tonic-gate * specifier character changes the screen size 5100Sstevel@tonic-gate * for the redraw. 5110Sstevel@tonic-gate * 5120Sstevel@tonic-gate */ 5130Sstevel@tonic-gate case 'z': 5140Sstevel@tonic-gate if (state == VISUAL) { 5150Sstevel@tonic-gate i = vgetcnt(); 5160Sstevel@tonic-gate if (i > 0) 5170Sstevel@tonic-gate vsetsiz(i); 5180Sstevel@tonic-gate c = getesc(); 5190Sstevel@tonic-gate if (c == 0) 5200Sstevel@tonic-gate continue; 5210Sstevel@tonic-gate } 5220Sstevel@tonic-gate vsave(); 5230Sstevel@tonic-gate vzop(hadcnt, cnt, c); 5240Sstevel@tonic-gate continue; 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate /* 5270Sstevel@tonic-gate * Y Yank lines, abbreviation for y_ or yy. 5280Sstevel@tonic-gate * Yanked lines can be put later if no 5290Sstevel@tonic-gate * changes intervene, or can be put in named 5300Sstevel@tonic-gate * buffers and put anytime in this session. 5310Sstevel@tonic-gate */ 5320Sstevel@tonic-gate case 'Y': 5330Sstevel@tonic-gate ungetkey('_'); 5340Sstevel@tonic-gate c = 'y'; 5350Sstevel@tonic-gate break; 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate /* 5380Sstevel@tonic-gate * J Join lines, 2 by default. Count is number 5390Sstevel@tonic-gate * of lines to join (no join operator sorry.) 5400Sstevel@tonic-gate */ 5410Sstevel@tonic-gate case 'J': 5420Sstevel@tonic-gate forbid (dot == dol); 5430Sstevel@tonic-gate if (cnt == 1) 5440Sstevel@tonic-gate cnt = 2; 5450Sstevel@tonic-gate if (cnt > (i = dol - dot + 1)) 5460Sstevel@tonic-gate cnt = i; 5470Sstevel@tonic-gate vsave(); 5480Sstevel@tonic-gate vmacchng(1); 5490Sstevel@tonic-gate setLAST(); 5500Sstevel@tonic-gate cursor = strend(linebuf); 5510Sstevel@tonic-gate vremote(cnt, join, 0); 5520Sstevel@tonic-gate notenam = (unsigned char *)"join"; 5530Sstevel@tonic-gate vmoving = 0; 5540Sstevel@tonic-gate killU(); 5550Sstevel@tonic-gate vreplace(vcline, cnt, 1); 5560Sstevel@tonic-gate if (!*cursor && cursor > linebuf) 5570Sstevel@tonic-gate cursor--; 5580Sstevel@tonic-gate if (notecnt == 2) 5590Sstevel@tonic-gate notecnt = 0; 5600Sstevel@tonic-gate vrepaint(cursor); 5610Sstevel@tonic-gate continue; 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate /* 5640Sstevel@tonic-gate * S Substitute text for whole lines, abbrev for c_. 5650Sstevel@tonic-gate * Count is number of lines to change. 5660Sstevel@tonic-gate */ 5670Sstevel@tonic-gate case 'S': 5680Sstevel@tonic-gate ungetkey('_'); 5690Sstevel@tonic-gate c = 'c'; 5700Sstevel@tonic-gate break; 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate /* 5730Sstevel@tonic-gate * O Create a new line above current and accept new 5740Sstevel@tonic-gate * input text, to an escape, there. 5750Sstevel@tonic-gate * A count specifies, for dumb terminals when 5760Sstevel@tonic-gate * slowopen is not set, the number of physical 5770Sstevel@tonic-gate * line space to open on the screen. 5780Sstevel@tonic-gate * 5790Sstevel@tonic-gate * o Like O, but opens lines below. 5800Sstevel@tonic-gate */ 5810Sstevel@tonic-gate case 'O': 5820Sstevel@tonic-gate case 'o': 5830Sstevel@tonic-gate vmacchng(1); 5840Sstevel@tonic-gate voOpen(c, cnt); 5850Sstevel@tonic-gate continue; 5860Sstevel@tonic-gate 5870Sstevel@tonic-gate /* 5880Sstevel@tonic-gate * C Change text to end of line, short for c$. 5890Sstevel@tonic-gate */ 5900Sstevel@tonic-gate case 'C': 5910Sstevel@tonic-gate if (*cursor) { 5920Sstevel@tonic-gate ungetkey('$'), c = 'c'; 5930Sstevel@tonic-gate break; 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate goto appnd; 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate /* 5980Sstevel@tonic-gate * ~ Switch case of letter under cursor 5990Sstevel@tonic-gate */ 6000Sstevel@tonic-gate case '~': 6010Sstevel@tonic-gate { 6020Sstevel@tonic-gate unsigned char mbuf[2049]; 6030Sstevel@tonic-gate unsigned char *ccursor = cursor; 6040Sstevel@tonic-gate #ifdef PRESUNEUC 6050Sstevel@tonic-gate int tmp, length; 6060Sstevel@tonic-gate wchar_t wchar; 6070Sstevel@tonic-gate #else 6080Sstevel@tonic-gate int tmp, len, n; 6090Sstevel@tonic-gate wchar_t wc; 6100Sstevel@tonic-gate #endif /* PRESUNEUC */ 6110Sstevel@tonic-gate unsigned char tmp1; 6120Sstevel@tonic-gate setLAST(); 6130Sstevel@tonic-gate for (tmp = 0; tmp + 3 < 2048; ) { 6140Sstevel@tonic-gate /* 6150Sstevel@tonic-gate * Use multiple 'r' commands to replace 6160Sstevel@tonic-gate * alpha with alternate case. 6170Sstevel@tonic-gate */ 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate if(cnt-- <= 0) 6200Sstevel@tonic-gate break; 6210Sstevel@tonic-gate #ifdef PRESUNEUC 6220Sstevel@tonic-gate length = mbtowc(&wchar, (char *)ccursor, MULTI_BYTE_MAX); 6230Sstevel@tonic-gate #else 6240Sstevel@tonic-gate len = mbtowc(&wc, (char *)ccursor, MULTI_BYTE_MAX); 6250Sstevel@tonic-gate #endif /* PRESUNEUC */ 6260Sstevel@tonic-gate #ifdef PRESUNEUC 6270Sstevel@tonic-gate if(length > 1) { 6280Sstevel@tonic-gate #else 6290Sstevel@tonic-gate n = iswalpha(wc); 6300Sstevel@tonic-gate if(len > 1 && !iswalpha(wc)) { 6310Sstevel@tonic-gate #endif /* PRESUNEUC */ 6320Sstevel@tonic-gate mbuf[tmp+0] = ' '; 6330Sstevel@tonic-gate tmp++; 6340Sstevel@tonic-gate #ifdef PRESUNEUC 6350Sstevel@tonic-gate ccursor += length; 6360Sstevel@tonic-gate #else 6370Sstevel@tonic-gate ccursor += len; 6380Sstevel@tonic-gate #endif /* PRESUNEUC */ 6390Sstevel@tonic-gate continue; 6400Sstevel@tonic-gate } 6410Sstevel@tonic-gate mbuf[tmp] = 'r'; 6420Sstevel@tonic-gate #ifdef PRESUNEUC 6430Sstevel@tonic-gate mbuf[tmp+1] = *ccursor++; 6440Sstevel@tonic-gate #else 6450Sstevel@tonic-gate ccursor += ((len > 0) ? len : 1); 6460Sstevel@tonic-gate #endif /* PRESUNEUC */ 6470Sstevel@tonic-gate /* 6480Sstevel@tonic-gate * If pointing to an alpha character, 6490Sstevel@tonic-gate * change the case. 6500Sstevel@tonic-gate */ 6510Sstevel@tonic-gate 6520Sstevel@tonic-gate tmp1 = mbuf[tmp+1]; 6530Sstevel@tonic-gate #ifdef PRESUNEUC 6540Sstevel@tonic-gate if (isupper((unsigned char)tmp1)) 6550Sstevel@tonic-gate mbuf[tmp+1] = tolower((unsigned char)tmp1); 6560Sstevel@tonic-gate else 6570Sstevel@tonic-gate mbuf[tmp+1] = toupper((unsigned char)tmp1); 6580Sstevel@tonic-gate #else 6590Sstevel@tonic-gate if (iswupper(wc)) 6600Sstevel@tonic-gate len = wctomb((char *)(mbuf + tmp + 1), 6610Sstevel@tonic-gate (wc = towlower(wc))); 6620Sstevel@tonic-gate else 6630Sstevel@tonic-gate len = wctomb((char *)(mbuf + tmp + 1), 6640Sstevel@tonic-gate (wc = towupper(wc))); 6650Sstevel@tonic-gate tmp += len - 1; 6660Sstevel@tonic-gate #endif /* PRESUNEUC */ 6670Sstevel@tonic-gate if(*ccursor) 6680Sstevel@tonic-gate /* 6690Sstevel@tonic-gate * If at end of line do not advance 6700Sstevel@tonic-gate * to the next character, else use a 6710Sstevel@tonic-gate * space to advance 1 column. 6720Sstevel@tonic-gate */ 6730Sstevel@tonic-gate mbuf[tmp+2] = ' '; 6740Sstevel@tonic-gate else { 6750Sstevel@tonic-gate mbuf[tmp+2] = '\0'; 6760Sstevel@tonic-gate tmp +=3; 6770Sstevel@tonic-gate break; 6780Sstevel@tonic-gate } 6790Sstevel@tonic-gate tmp += 3; 6800Sstevel@tonic-gate } 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate mbuf[tmp] = 0; 6830Sstevel@tonic-gate macpush(mbuf, 1); 6840Sstevel@tonic-gate } 6850Sstevel@tonic-gate continue; 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate /* 6890Sstevel@tonic-gate * A Append at end of line, short for $a. 6900Sstevel@tonic-gate */ 6910Sstevel@tonic-gate case 'A': 6920Sstevel@tonic-gate operate('$', 1); 6930Sstevel@tonic-gate appnd: 6940Sstevel@tonic-gate c = 'a'; 6950Sstevel@tonic-gate /* fall into ... */ 6960Sstevel@tonic-gate 6970Sstevel@tonic-gate /* 6980Sstevel@tonic-gate * a Appends text after cursor. Text can continue 6990Sstevel@tonic-gate * through arbitrary number of lines. 7000Sstevel@tonic-gate */ 7010Sstevel@tonic-gate case 'a': 7020Sstevel@tonic-gate if (*cursor) { 7030Sstevel@tonic-gate wchar_t wchar; 7040Sstevel@tonic-gate int length = mbtowc(&wchar, (char *)cursor, MULTI_BYTE_MAX); 7050Sstevel@tonic-gate if (state == HARDOPEN) { 7060Sstevel@tonic-gate if(length < 0) { 7070Sstevel@tonic-gate putoctal = 1; 7080Sstevel@tonic-gate putchar(*cursor); 7090Sstevel@tonic-gate putoctal = 0; 7100Sstevel@tonic-gate } else 7110Sstevel@tonic-gate putchar(wchar); 7120Sstevel@tonic-gate } 7130Sstevel@tonic-gate if(length < 0) 7140Sstevel@tonic-gate cursor++; 7150Sstevel@tonic-gate else 7160Sstevel@tonic-gate cursor += length; 7170Sstevel@tonic-gate } 7180Sstevel@tonic-gate goto insrt; 7190Sstevel@tonic-gate 7200Sstevel@tonic-gate /* 7210Sstevel@tonic-gate * I Insert at beginning of whitespace of line, 7220Sstevel@tonic-gate * short for ^i. 7230Sstevel@tonic-gate */ 7240Sstevel@tonic-gate case 'I': 7250Sstevel@tonic-gate operate('^', 1); 7260Sstevel@tonic-gate c = 'i'; 7270Sstevel@tonic-gate /* fall into ... */ 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate /* 7300Sstevel@tonic-gate * R Replace characters, one for one, by input 7310Sstevel@tonic-gate * (logically), like repeated r commands. 7320Sstevel@tonic-gate * 7330Sstevel@tonic-gate * BUG: This is like the typeover mode of many other 7340Sstevel@tonic-gate * editors, and is only rarely useful. Its 7350Sstevel@tonic-gate * implementation is a hack in a low level 7360Sstevel@tonic-gate * routine and it doesn't work very well, e.g. 7370Sstevel@tonic-gate * you can't move around within a R, etc. 7380Sstevel@tonic-gate */ 7390Sstevel@tonic-gate case 'R': 7400Sstevel@tonic-gate /* fall into... */ 7410Sstevel@tonic-gate 7420Sstevel@tonic-gate /* 7430Sstevel@tonic-gate * i Insert text to an escape in the buffer. 7440Sstevel@tonic-gate * Text is arbitrary. This command reminds of 7450Sstevel@tonic-gate * the i command in bare teco. 7460Sstevel@tonic-gate */ 7470Sstevel@tonic-gate case 'i': 7480Sstevel@tonic-gate insrt: 7490Sstevel@tonic-gate /* 7500Sstevel@tonic-gate * Common code for all the insertion commands. 7510Sstevel@tonic-gate * Save for redo, position cursor, prepare for append 7520Sstevel@tonic-gate * at command and in visual undo. Note that nothing 7530Sstevel@tonic-gate * is doomed, unless R when all is, and save the 7540Sstevel@tonic-gate * current line in a the undo temporary buffer. 7550Sstevel@tonic-gate */ 7560Sstevel@tonic-gate vmacchng(1); 7570Sstevel@tonic-gate setLAST(); 7580Sstevel@tonic-gate vcursat(cursor); 7590Sstevel@tonic-gate prepapp(); 7600Sstevel@tonic-gate vnoapp(); 7610Sstevel@tonic-gate doomed = c == 'R' ? 10000 : 0; 7620Sstevel@tonic-gate if(FIXUNDO) 7630Sstevel@tonic-gate vundkind = VCHNG; 7640Sstevel@tonic-gate vmoving = 0; 7650Sstevel@tonic-gate CP(vutmp, linebuf); 7660Sstevel@tonic-gate 7670Sstevel@tonic-gate /* 7680Sstevel@tonic-gate * If this is a repeated command, then suppress 7690Sstevel@tonic-gate * fake insert mode on dumb terminals which looks 7700Sstevel@tonic-gate * ridiculous and wastes lots of time even at 9600B. 7710Sstevel@tonic-gate */ 7720Sstevel@tonic-gate if (vglobp) 7730Sstevel@tonic-gate hold = HOLDQIK; 7740Sstevel@tonic-gate vappend(c, cnt, 0); 7750Sstevel@tonic-gate continue; 7760Sstevel@tonic-gate 7770Sstevel@tonic-gate /* 7780Sstevel@tonic-gate * An attention, normally a DEL, just beeps. 7790Sstevel@tonic-gate * If you are a vi command within ex, then 7800Sstevel@tonic-gate * two ATTN's will drop you back to command mode. 7810Sstevel@tonic-gate */ 7820Sstevel@tonic-gate case ATTN: 783*802Scf46844 (void) beep(); 7840Sstevel@tonic-gate if (initev || peekkey() != ATTN) 7850Sstevel@tonic-gate continue; 7860Sstevel@tonic-gate /* fall into... */ 7870Sstevel@tonic-gate 7880Sstevel@tonic-gate /* 7890Sstevel@tonic-gate * ^\ A quit always gets command mode. 7900Sstevel@tonic-gate */ 7910Sstevel@tonic-gate case QUIT: 7920Sstevel@tonic-gate /* 7930Sstevel@tonic-gate * Have to be careful if we were called 7940Sstevel@tonic-gate * g/xxx/vi 7950Sstevel@tonic-gate * since a return will just start up again. 7960Sstevel@tonic-gate * So we simulate an interrupt. 7970Sstevel@tonic-gate */ 7980Sstevel@tonic-gate if (inglobal) 7990Sstevel@tonic-gate onintr(0); 8000Sstevel@tonic-gate /* fall into... */ 8010Sstevel@tonic-gate 8020Sstevel@tonic-gate #ifdef notdef 8030Sstevel@tonic-gate /* 8040Sstevel@tonic-gate * q Quit back to command mode, unless called as 8050Sstevel@tonic-gate * vi on command line in which case dont do it 8060Sstevel@tonic-gate */ 8070Sstevel@tonic-gate case 'q': /* quit */ 8080Sstevel@tonic-gate if (initev) { 8090Sstevel@tonic-gate vsave(); 8100Sstevel@tonic-gate CATCH 8110Sstevel@tonic-gate error(gettext("Q gets ex command mode, :q leaves vi")); 8120Sstevel@tonic-gate ENDCATCH 8130Sstevel@tonic-gate splitw = 0; 8140Sstevel@tonic-gate getDOT(); 8150Sstevel@tonic-gate vrepaint(cursor); 8160Sstevel@tonic-gate continue; 8170Sstevel@tonic-gate } 8180Sstevel@tonic-gate #endif 8190Sstevel@tonic-gate /* fall into... */ 8200Sstevel@tonic-gate 8210Sstevel@tonic-gate /* 8220Sstevel@tonic-gate * Q Is like q, but always gets to command mode 8230Sstevel@tonic-gate * even if command line invocation was as vi. 8240Sstevel@tonic-gate */ 8250Sstevel@tonic-gate case 'Q': 8260Sstevel@tonic-gate vsave(); 8270Sstevel@tonic-gate /* 8280Sstevel@tonic-gate * If we are in the middle of a macro, throw away 8290Sstevel@tonic-gate * the rest and fix up undo. 8300Sstevel@tonic-gate * This code copied from getbr(). 8310Sstevel@tonic-gate */ 8320Sstevel@tonic-gate if (vmacp) { 8330Sstevel@tonic-gate vmacp = 0; 8340Sstevel@tonic-gate if (inopen == -1) /* don't mess up undo for esc esc */ 8350Sstevel@tonic-gate vundkind = VMANY; 8360Sstevel@tonic-gate inopen = 1; /* restore old setting now that macro done */ 8370Sstevel@tonic-gate } 8380Sstevel@tonic-gate ixlatctl(1); 8390Sstevel@tonic-gate return; 8400Sstevel@tonic-gate 8410Sstevel@tonic-gate 8420Sstevel@tonic-gate /* 8430Sstevel@tonic-gate * ZZ Like :x 8440Sstevel@tonic-gate */ 8450Sstevel@tonic-gate case 'Z': 8460Sstevel@tonic-gate forbid(getkey() != 'Z'); 8470Sstevel@tonic-gate oglobp = globp; 8480Sstevel@tonic-gate globp = (unsigned char *)"x"; 8490Sstevel@tonic-gate vclrech(0); 8500Sstevel@tonic-gate goto gogo; 8510Sstevel@tonic-gate 8520Sstevel@tonic-gate /* 8530Sstevel@tonic-gate * P Put back text before cursor or before current 8540Sstevel@tonic-gate * line. If text was whole lines goes back 8550Sstevel@tonic-gate * as whole lines. If part of a single line 8560Sstevel@tonic-gate * or parts of whole lines splits up current 8570Sstevel@tonic-gate * line to form many new lines. 8580Sstevel@tonic-gate * May specify a named buffer, or the delete 8590Sstevel@tonic-gate * saving buffers 1-9. 8600Sstevel@tonic-gate * 8610Sstevel@tonic-gate * p Like P but after rather than before. 8620Sstevel@tonic-gate */ 8630Sstevel@tonic-gate case 'P': 8640Sstevel@tonic-gate case 'p': 8650Sstevel@tonic-gate vmoving = 0; 8660Sstevel@tonic-gate #ifdef XPG4 8670Sstevel@tonic-gate P_cursor_offset = 0; 8680Sstevel@tonic-gate #endif 8690Sstevel@tonic-gate #ifdef notdef 8700Sstevel@tonic-gate forbid (!vreg && value(vi_UNDOMACRO) && inopen < 0); 8710Sstevel@tonic-gate #endif 8720Sstevel@tonic-gate /* 8730Sstevel@tonic-gate * If previous delete was partial line, use an 8740Sstevel@tonic-gate * append or insert to put it back so as to 8750Sstevel@tonic-gate * use insert mode on intelligent terminals. 8760Sstevel@tonic-gate */ 8770Sstevel@tonic-gate if (!vreg && DEL[0]) { 8780Sstevel@tonic-gate setLAST(); 8790Sstevel@tonic-gate forbid ((unsigned char)DEL[128] == 0200); 8800Sstevel@tonic-gate vglobp = DEL; 8810Sstevel@tonic-gate ungetkey(c == 'p' ? 'a' : 'i'); 8820Sstevel@tonic-gate goto reread; 8830Sstevel@tonic-gate } 8840Sstevel@tonic-gate 8850Sstevel@tonic-gate /* 8860Sstevel@tonic-gate * If a register wasn't specified, then make 8870Sstevel@tonic-gate * sure there is something to put back. 8880Sstevel@tonic-gate */ 8890Sstevel@tonic-gate forbid (!vreg && unddol == dol); 8900Sstevel@tonic-gate /* 8910Sstevel@tonic-gate * If we just did a macro the whole buffer is in 8920Sstevel@tonic-gate * the undo save area. We don't want to put THAT. 8930Sstevel@tonic-gate */ 8940Sstevel@tonic-gate forbid (vundkind == VMANY && undkind==UNDALL); 8950Sstevel@tonic-gate vsave(); 8960Sstevel@tonic-gate vmacchng(1); 8970Sstevel@tonic-gate setLAST(); 8980Sstevel@tonic-gate i = 0; 8990Sstevel@tonic-gate if (vreg && partreg(vreg) || !vreg && pkill[0]) { 9000Sstevel@tonic-gate /* 9010Sstevel@tonic-gate * Restoring multiple lines which were partial 9020Sstevel@tonic-gate * lines; will leave cursor in middle 9030Sstevel@tonic-gate * of line after shoving restored text in to 9040Sstevel@tonic-gate * split the current line. 9050Sstevel@tonic-gate */ 9060Sstevel@tonic-gate i++; 9070Sstevel@tonic-gate if (c == 'p' && *cursor) 9080Sstevel@tonic-gate cursor = nextchr(cursor); 9090Sstevel@tonic-gate } else { 9100Sstevel@tonic-gate /* 9110Sstevel@tonic-gate * In whole line case, have to back up dot 9120Sstevel@tonic-gate * for P; also want to clear cursor so 9130Sstevel@tonic-gate * cursor will eventually be positioned 9140Sstevel@tonic-gate * at the beginning of the first put line. 9150Sstevel@tonic-gate */ 9160Sstevel@tonic-gate cursor = 0; 9170Sstevel@tonic-gate if (c == 'P') { 9180Sstevel@tonic-gate dot--, vcline--; 9190Sstevel@tonic-gate c = 'p'; 9200Sstevel@tonic-gate } 9210Sstevel@tonic-gate } 9220Sstevel@tonic-gate killU(); 9230Sstevel@tonic-gate 9240Sstevel@tonic-gate /* 9250Sstevel@tonic-gate * The call to putreg can potentially 9260Sstevel@tonic-gate * bomb since there may be nothing in a named buffer. 9270Sstevel@tonic-gate * We thus put a catch in here. If we didn't and 9280Sstevel@tonic-gate * there was an error we would end up in command mode. 9290Sstevel@tonic-gate */ 9300Sstevel@tonic-gate addr = dol; /* old dol */ 9310Sstevel@tonic-gate CATCH 932*802Scf46844 vremote(1, 933*802Scf46844 vreg ? (int (*)())putreg : put, vreg); 9340Sstevel@tonic-gate ONERR 9350Sstevel@tonic-gate if (vreg == -1) { 9360Sstevel@tonic-gate splitw = 0; 9370Sstevel@tonic-gate if (op == 'P') 9380Sstevel@tonic-gate dot++, vcline++; 9390Sstevel@tonic-gate goto pfixup; 9400Sstevel@tonic-gate } 9410Sstevel@tonic-gate ENDCATCH 9420Sstevel@tonic-gate splitw = 0; 9430Sstevel@tonic-gate nlput = dol - addr + 1; 9440Sstevel@tonic-gate if (!i) { 9450Sstevel@tonic-gate /* 9460Sstevel@tonic-gate * Increment undap1, undap2 to make up 9470Sstevel@tonic-gate * for their incorrect initialization in the 9480Sstevel@tonic-gate * routine vremote before calling put/putreg. 9490Sstevel@tonic-gate */ 9500Sstevel@tonic-gate if (FIXUNDO) 9510Sstevel@tonic-gate undap1++, undap2++; 9520Sstevel@tonic-gate vcline++; 9530Sstevel@tonic-gate nlput--; 9540Sstevel@tonic-gate 9550Sstevel@tonic-gate /* 9560Sstevel@tonic-gate * After a put want current line first line, 9570Sstevel@tonic-gate * and dot was made the last line put in code 9580Sstevel@tonic-gate * run so far. This is why we increment vcline 9590Sstevel@tonic-gate * above and decrease dot here. 9600Sstevel@tonic-gate */ 9610Sstevel@tonic-gate dot -= nlput - 1; 9620Sstevel@tonic-gate } 9630Sstevel@tonic-gate #ifdef TRACE 9640Sstevel@tonic-gate if (trace) 9650Sstevel@tonic-gate fprintf(trace, "vreplace(%d, %d, %d), undap1=%d, undap2=%d, dot=%d\n", vcline, i, nlput, lineno(undap1), lineno(undap2), lineno(dot)); 9660Sstevel@tonic-gate #endif 9670Sstevel@tonic-gate vreplace(vcline, i, nlput); 9680Sstevel@tonic-gate #ifdef XPG4 9690Sstevel@tonic-gate if (op == 'P' && i > 0) { 9700Sstevel@tonic-gate dot += nlput - 1; 9710Sstevel@tonic-gate vcline += nlput - 1; 9720Sstevel@tonic-gate cursor += P_cursor_offset; 9730Sstevel@tonic-gate } 9740Sstevel@tonic-gate #endif 9750Sstevel@tonic-gate if (state != VISUAL) { 9760Sstevel@tonic-gate /* 9770Sstevel@tonic-gate * Special case in open mode. 9780Sstevel@tonic-gate * Force action on the screen when a single 9790Sstevel@tonic-gate * line is put even if it is identical to 9800Sstevel@tonic-gate * the current line, e.g. on YP; otherwise 9810Sstevel@tonic-gate * you can't tell anything happened. 9820Sstevel@tonic-gate */ 9830Sstevel@tonic-gate vjumpto(dot, cursor, '.'); 9840Sstevel@tonic-gate continue; 9850Sstevel@tonic-gate } 9860Sstevel@tonic-gate pfixup: 9870Sstevel@tonic-gate vrepaint(cursor); 9880Sstevel@tonic-gate vfixcurs(); 9890Sstevel@tonic-gate continue; 9900Sstevel@tonic-gate 9910Sstevel@tonic-gate /* 9920Sstevel@tonic-gate * ^^ Return to previous file. 9930Sstevel@tonic-gate * Like a :e #, and thus can be used after a 9940Sstevel@tonic-gate * "No Write" diagnostic. 9950Sstevel@tonic-gate */ 9960Sstevel@tonic-gate case CTRL('^'): 9970Sstevel@tonic-gate forbid (hadcnt); 9980Sstevel@tonic-gate vsave(); 9990Sstevel@tonic-gate ckaw(); 10000Sstevel@tonic-gate oglobp = globp; 10010Sstevel@tonic-gate if (value(vi_AUTOWRITE) && !value(vi_READONLY)) 10020Sstevel@tonic-gate globp = (unsigned char *)"e! #"; 10030Sstevel@tonic-gate else 10040Sstevel@tonic-gate globp = (unsigned char *)"e #"; 10050Sstevel@tonic-gate goto gogo; 10060Sstevel@tonic-gate 10070Sstevel@tonic-gate #ifdef TAG_STACK 10080Sstevel@tonic-gate /* 10090Sstevel@tonic-gate * ^T Pop the tag stack if enabled or else reset it 10100Sstevel@tonic-gate * if not. 10110Sstevel@tonic-gate */ 10120Sstevel@tonic-gate case CTRL('t'): 10130Sstevel@tonic-gate forbid (hadcnt); 10140Sstevel@tonic-gate vsave(); 10150Sstevel@tonic-gate oglobp = globp; 10160Sstevel@tonic-gate globp = (unsigned char *) "pop"; 10170Sstevel@tonic-gate goto gogo; 10180Sstevel@tonic-gate #endif 10190Sstevel@tonic-gate /* 10200Sstevel@tonic-gate * ^] Takes word after cursor as tag, and then does 10210Sstevel@tonic-gate * tag command. Read ``go right to''. 10220Sstevel@tonic-gate * This is not a search, so the wrapscan setting 10230Sstevel@tonic-gate * must be ignored. If set, then it is unset 10240Sstevel@tonic-gate * here and restored later. 10250Sstevel@tonic-gate */ 10260Sstevel@tonic-gate case CTRL(']'): 10270Sstevel@tonic-gate grabtag(); 10280Sstevel@tonic-gate oglobp = globp; 10290Sstevel@tonic-gate if (value(vi_WRAPSCAN) == 0) { 10300Sstevel@tonic-gate tag_reset_wrap = 1; 10310Sstevel@tonic-gate value(vi_WRAPSCAN) = 1; 10320Sstevel@tonic-gate } 10330Sstevel@tonic-gate globp = (unsigned char *)"tag"; 10340Sstevel@tonic-gate goto gogo; 10350Sstevel@tonic-gate 10360Sstevel@tonic-gate /* 10370Sstevel@tonic-gate * & Like :& 10380Sstevel@tonic-gate */ 10390Sstevel@tonic-gate case '&': 10400Sstevel@tonic-gate oglobp = globp; 10410Sstevel@tonic-gate globp = (unsigned char *)"&"; 10420Sstevel@tonic-gate goto gogo; 10430Sstevel@tonic-gate 10440Sstevel@tonic-gate /* 10450Sstevel@tonic-gate * ^G Bring up a status line at the bottom of 10460Sstevel@tonic-gate * the screen, like a :file command. 10470Sstevel@tonic-gate * 10480Sstevel@tonic-gate * BUG: Was ^S but doesn't work in cbreak mode 10490Sstevel@tonic-gate */ 10500Sstevel@tonic-gate case CTRL('g'): 10510Sstevel@tonic-gate oglobp = globp; 10520Sstevel@tonic-gate globp = (unsigned char *)"file"; 10530Sstevel@tonic-gate gogo: 10540Sstevel@tonic-gate addr = dot; 10550Sstevel@tonic-gate vsave(); 10560Sstevel@tonic-gate goto doinit; 10570Sstevel@tonic-gate 10580Sstevel@tonic-gate #ifdef SIGTSTP 10590Sstevel@tonic-gate /* 10600Sstevel@tonic-gate * ^Z: suspend editor session and temporarily return 10610Sstevel@tonic-gate * to shell. Only works with Berkeley/IIASA process 10620Sstevel@tonic-gate * control in kernel. 10630Sstevel@tonic-gate */ 10640Sstevel@tonic-gate case CTRL('z'): 10650Sstevel@tonic-gate forbid(dosusp == 0); 10660Sstevel@tonic-gate vsave(); 10670Sstevel@tonic-gate oglobp = globp; 10680Sstevel@tonic-gate globp = (unsigned char *)"stop"; 10690Sstevel@tonic-gate goto gogo; 10700Sstevel@tonic-gate #endif 10710Sstevel@tonic-gate 10720Sstevel@tonic-gate /* 10730Sstevel@tonic-gate * : Read a command from the echo area and 10740Sstevel@tonic-gate * execute it in command mode. 10750Sstevel@tonic-gate */ 10760Sstevel@tonic-gate case ':': 10770Sstevel@tonic-gate forbid (hadcnt); 10780Sstevel@tonic-gate vsave(); 10790Sstevel@tonic-gate i = tchng; 10800Sstevel@tonic-gate addr = dot; 10810Sstevel@tonic-gate if (readecho(c)) { 10820Sstevel@tonic-gate esave[0] = 0; 10830Sstevel@tonic-gate goto fixup; 10840Sstevel@tonic-gate } 10850Sstevel@tonic-gate getDOT(); 10860Sstevel@tonic-gate /* 10870Sstevel@tonic-gate * Use the visual undo buffer to store the global 10880Sstevel@tonic-gate * string for command mode, since it is idle right now. 10890Sstevel@tonic-gate */ 10900Sstevel@tonic-gate oglobp = globp; strcpy(vutmp, genbuf+1); globp = vutmp; 10910Sstevel@tonic-gate doinit: 10920Sstevel@tonic-gate esave[0] = 0; 10930Sstevel@tonic-gate fixech(); 10940Sstevel@tonic-gate 10950Sstevel@tonic-gate /* 10960Sstevel@tonic-gate * Have to finagle around not to lose last 10970Sstevel@tonic-gate * character after this command (when run from ex 10980Sstevel@tonic-gate * command mode). This is clumsy. 10990Sstevel@tonic-gate */ 11000Sstevel@tonic-gate d = peekc; ungetchar(0); 11010Sstevel@tonic-gate if (shouldpo) { 11020Sstevel@tonic-gate /* 11030Sstevel@tonic-gate * So after a "Hit return..." ":", we do 11040Sstevel@tonic-gate * another "Hit return..." the next time 11050Sstevel@tonic-gate */ 11060Sstevel@tonic-gate pofix(); 11070Sstevel@tonic-gate shouldpo = 0; 11080Sstevel@tonic-gate } 11090Sstevel@tonic-gate CATCH 11100Sstevel@tonic-gate /* 11110Sstevel@tonic-gate * Save old values of options so we can 11120Sstevel@tonic-gate * notice when they change; switch into 11130Sstevel@tonic-gate * cooked mode so we are interruptible. 11140Sstevel@tonic-gate */ 11150Sstevel@tonic-gate onumber = value(vi_NUMBER); 11160Sstevel@tonic-gate olist = value(vi_LIST); 11170Sstevel@tonic-gate OPline = Pline; 11180Sstevel@tonic-gate OPutchar = Putchar; 11190Sstevel@tonic-gate #ifndef CBREAK 11200Sstevel@tonic-gate vcook(); 11210Sstevel@tonic-gate #endif 11220Sstevel@tonic-gate commands(1, 1); 11230Sstevel@tonic-gate if (dot == zero && dol > zero) 11240Sstevel@tonic-gate dot = one; 11250Sstevel@tonic-gate #ifndef CBREAK 11260Sstevel@tonic-gate vraw(); 11270Sstevel@tonic-gate #endif 11280Sstevel@tonic-gate ONERR 11290Sstevel@tonic-gate #ifndef CBREAK 11300Sstevel@tonic-gate vraw(); 11310Sstevel@tonic-gate #endif 11320Sstevel@tonic-gate copy(esave, vtube[WECHO], TUBECOLS * sizeof(wchar_t)); 11330Sstevel@tonic-gate ENDCATCH 11340Sstevel@tonic-gate fixol(); 11350Sstevel@tonic-gate Pline = OPline; 11360Sstevel@tonic-gate Putchar = OPutchar; 11370Sstevel@tonic-gate ungetchar(d); 11380Sstevel@tonic-gate globp = oglobp; 11390Sstevel@tonic-gate 11400Sstevel@tonic-gate /* 11410Sstevel@tonic-gate * If we ended up with no lines in the buffer, make 11420Sstevel@tonic-gate * a line. 11430Sstevel@tonic-gate */ 11440Sstevel@tonic-gate if (dot == zero) { 11450Sstevel@tonic-gate fixzero(); 11460Sstevel@tonic-gate } 11470Sstevel@tonic-gate splitw = 0; 11480Sstevel@tonic-gate 11490Sstevel@tonic-gate /* 11500Sstevel@tonic-gate * Special case: did list/number options change? 11510Sstevel@tonic-gate */ 11520Sstevel@tonic-gate if (onumber != value(vi_NUMBER)) 11530Sstevel@tonic-gate setnumb(value(vi_NUMBER)); 11540Sstevel@tonic-gate if (olist != value(vi_LIST)) 11550Sstevel@tonic-gate setlist(value(vi_LIST)); 11560Sstevel@tonic-gate 11570Sstevel@tonic-gate fixup: 11580Sstevel@tonic-gate /* 11590Sstevel@tonic-gate * If a change occurred, other than 11600Sstevel@tonic-gate * a write which clears changes, then 11610Sstevel@tonic-gate * we should allow an undo even if . 11620Sstevel@tonic-gate * didn't move. 11630Sstevel@tonic-gate * 11640Sstevel@tonic-gate * BUG: You can make this wrong by 11650Sstevel@tonic-gate * tricking around with multiple commands 11660Sstevel@tonic-gate * on one line of : escape, and including 11670Sstevel@tonic-gate * a write command there, but it's not 11680Sstevel@tonic-gate * worth worrying about. 11690Sstevel@tonic-gate */ 11700Sstevel@tonic-gate if (FIXUNDO && tchng && tchng != i) 11710Sstevel@tonic-gate vundkind = VMANY, cursor = 0; 11720Sstevel@tonic-gate 11730Sstevel@tonic-gate /* 11740Sstevel@tonic-gate * If we are about to do another :, hold off 11750Sstevel@tonic-gate * updating of screen. 11760Sstevel@tonic-gate */ 11770Sstevel@tonic-gate if (vcnt < 0 && Peekkey == ':') { 11780Sstevel@tonic-gate getDOT(); 11790Sstevel@tonic-gate shouldpo = 1; 11800Sstevel@tonic-gate continue; 11810Sstevel@tonic-gate } 11820Sstevel@tonic-gate shouldpo = 0; 11830Sstevel@tonic-gate 11840Sstevel@tonic-gate /* 11850Sstevel@tonic-gate * In the case where the file being edited is 11860Sstevel@tonic-gate * new; e.g. if the initial state hasn't been 11870Sstevel@tonic-gate * saved yet, then do so now. 11880Sstevel@tonic-gate */ 11890Sstevel@tonic-gate if (unddol == truedol) { 11900Sstevel@tonic-gate vundkind = VNONE; 11910Sstevel@tonic-gate Vlines = lineDOL(); 11920Sstevel@tonic-gate if (!inglobal) 11930Sstevel@tonic-gate savevis(); 11940Sstevel@tonic-gate addr = zero; 11950Sstevel@tonic-gate vcnt = 0; 11960Sstevel@tonic-gate if (esave[0] == 0) 11970Sstevel@tonic-gate copy(esave, vtube[WECHO], TUBECOLS * sizeof(wchar_t)); 11980Sstevel@tonic-gate } 11990Sstevel@tonic-gate 12000Sstevel@tonic-gate /* 12010Sstevel@tonic-gate * If the current line moved reset the cursor position. 12020Sstevel@tonic-gate */ 12030Sstevel@tonic-gate if (dot != addr) { 12040Sstevel@tonic-gate vmoving = 0; 12050Sstevel@tonic-gate cursor = 0; 12060Sstevel@tonic-gate } 12070Sstevel@tonic-gate 12080Sstevel@tonic-gate /* 12090Sstevel@tonic-gate * If current line is not on screen or if we are 12100Sstevel@tonic-gate * in open mode and . moved, then redraw. 12110Sstevel@tonic-gate */ 12120Sstevel@tonic-gate i = vcline + (dot - addr); 12130Sstevel@tonic-gate if(windowchg) 12140Sstevel@tonic-gate windowinit(); 12150Sstevel@tonic-gate if (i < 0 || i >= vcnt && i >= -vcnt || state != VISUAL && dot != addr) { 12160Sstevel@tonic-gate if (state == CRTOPEN) 12170Sstevel@tonic-gate vup1(); 12180Sstevel@tonic-gate if (vcnt > 0) 12190Sstevel@tonic-gate vcnt = 0; 1220*802Scf46844 vjumpto(dot, (unsigned char *) 0, '.'); 12210Sstevel@tonic-gate } else { 12220Sstevel@tonic-gate /* 12230Sstevel@tonic-gate * Current line IS on screen. 12240Sstevel@tonic-gate * If we did a [Hit return...] then 12250Sstevel@tonic-gate * restore vcnt and clear screen if in visual 12260Sstevel@tonic-gate */ 12270Sstevel@tonic-gate vcline = i; 12280Sstevel@tonic-gate if (vcnt < 0) { 12290Sstevel@tonic-gate vcnt = -vcnt; 12300Sstevel@tonic-gate if (state == VISUAL) 12310Sstevel@tonic-gate vclear(); 12320Sstevel@tonic-gate else if (state == CRTOPEN) { 12330Sstevel@tonic-gate vcnt = 0; 12340Sstevel@tonic-gate } 12350Sstevel@tonic-gate } 12360Sstevel@tonic-gate 12370Sstevel@tonic-gate /* 12380Sstevel@tonic-gate * Limit max value of vcnt based on $ 12390Sstevel@tonic-gate */ 12400Sstevel@tonic-gate i = vcline + lineDOL() - lineDOT() + 1; 12410Sstevel@tonic-gate if (i < vcnt) 12420Sstevel@tonic-gate vcnt = i; 12430Sstevel@tonic-gate 12440Sstevel@tonic-gate /* 12450Sstevel@tonic-gate * Dirty and repaint. 12460Sstevel@tonic-gate */ 12470Sstevel@tonic-gate vdirty(0, lines); 12480Sstevel@tonic-gate vrepaint(cursor); 12490Sstevel@tonic-gate } 12500Sstevel@tonic-gate 12510Sstevel@tonic-gate /* 12520Sstevel@tonic-gate * If in visual, put back the echo area 12530Sstevel@tonic-gate * if it was clobbered. 12540Sstevel@tonic-gate */ 12550Sstevel@tonic-gate if (state == VISUAL) { 12560Sstevel@tonic-gate int sdc = destcol, sdl = destline; 12570Sstevel@tonic-gate 12580Sstevel@tonic-gate splitw++; 12590Sstevel@tonic-gate vigoto(WECHO, 0); 12600Sstevel@tonic-gate for (i = 0; i < TUBECOLS - 1; i++) { 12610Sstevel@tonic-gate if (esave[i] == 0) 12620Sstevel@tonic-gate break; 12630Sstevel@tonic-gate if(esave[i] != FILLER) 1264*802Scf46844 (void) vputchar(esave[i]); 12650Sstevel@tonic-gate } 12660Sstevel@tonic-gate splitw = 0; 12670Sstevel@tonic-gate vgoto(sdl, sdc); 12680Sstevel@tonic-gate } 12690Sstevel@tonic-gate if (tag_reset_wrap == 1) { 12700Sstevel@tonic-gate tag_reset_wrap = 0; 12710Sstevel@tonic-gate value(vi_WRAPSCAN) = 0; 12720Sstevel@tonic-gate } 12730Sstevel@tonic-gate continue; 12740Sstevel@tonic-gate 12750Sstevel@tonic-gate /* 12760Sstevel@tonic-gate * u undo the last changing command. 12770Sstevel@tonic-gate */ 12780Sstevel@tonic-gate case 'u': 12790Sstevel@tonic-gate vundo(1); 12800Sstevel@tonic-gate continue; 12810Sstevel@tonic-gate 12820Sstevel@tonic-gate /* 12830Sstevel@tonic-gate * U restore current line to initial state. 12840Sstevel@tonic-gate */ 12850Sstevel@tonic-gate case 'U': 12860Sstevel@tonic-gate vUndo(); 12870Sstevel@tonic-gate continue; 12880Sstevel@tonic-gate 12890Sstevel@tonic-gate fonfon: 1290*802Scf46844 (void) beep(); 12910Sstevel@tonic-gate vmacp = 0; 12920Sstevel@tonic-gate inopen = 1; /* might have been -1 */ 12930Sstevel@tonic-gate continue; 12940Sstevel@tonic-gate } 12950Sstevel@tonic-gate 12960Sstevel@tonic-gate /* 12970Sstevel@tonic-gate * Rest of commands are decoded by the operate 12980Sstevel@tonic-gate * routine. 12990Sstevel@tonic-gate */ 13000Sstevel@tonic-gate operate(c, cnt); 13010Sstevel@tonic-gate } 13020Sstevel@tonic-gate } 13030Sstevel@tonic-gate 13040Sstevel@tonic-gate /* 13050Sstevel@tonic-gate * Grab the word after the cursor so we can look for it as a tag. 13060Sstevel@tonic-gate */ 1307*802Scf46844 void 1308*802Scf46844 grabtag(void) 13090Sstevel@tonic-gate { 1310*802Scf46844 unsigned char *cp, *dp; 13110Sstevel@tonic-gate 13120Sstevel@tonic-gate cp = vpastwh(cursor); 13130Sstevel@tonic-gate if (*cp) { 13140Sstevel@tonic-gate dp = lasttag; 13150Sstevel@tonic-gate do { 13160Sstevel@tonic-gate if (dp < &lasttag[sizeof lasttag - 2]) 13170Sstevel@tonic-gate *dp++ = *cp; 13180Sstevel@tonic-gate cp++; 13190Sstevel@tonic-gate /* only allow ascii alphabetics */ 13200Sstevel@tonic-gate } while ((isascii(*cp) && isalpha(*cp)) || isdigit(*cp) || *cp == '_'); 13210Sstevel@tonic-gate *dp++ = 0; 13220Sstevel@tonic-gate } 13230Sstevel@tonic-gate } 13240Sstevel@tonic-gate 13250Sstevel@tonic-gate /* 13260Sstevel@tonic-gate * Before appending lines, set up addr1 and 13270Sstevel@tonic-gate * the command mode undo information. 13280Sstevel@tonic-gate */ 1329*802Scf46844 void 1330*802Scf46844 prepapp(void) 13310Sstevel@tonic-gate { 13320Sstevel@tonic-gate 13330Sstevel@tonic-gate addr1 = dot; 13340Sstevel@tonic-gate deletenone(); 13350Sstevel@tonic-gate addr1++; 13360Sstevel@tonic-gate appendnone(); 13370Sstevel@tonic-gate } 13380Sstevel@tonic-gate 13390Sstevel@tonic-gate /* 13400Sstevel@tonic-gate * Execute function f with the address bounds addr1 13410Sstevel@tonic-gate * and addr2 surrounding cnt lines starting at dot. 13420Sstevel@tonic-gate */ 1343*802Scf46844 void 13440Sstevel@tonic-gate vremote(cnt, f, arg) 13450Sstevel@tonic-gate int cnt, (*f)(), arg; 13460Sstevel@tonic-gate { 1347*802Scf46844 int oing = inglobal; 13480Sstevel@tonic-gate 13490Sstevel@tonic-gate addr1 = dot; 13500Sstevel@tonic-gate addr2 = dot + cnt - 1; 13510Sstevel@tonic-gate inglobal = 0; 13520Sstevel@tonic-gate if (FIXUNDO) 13530Sstevel@tonic-gate undap1 = undap2 = dot; 13540Sstevel@tonic-gate (*f)(arg); 13550Sstevel@tonic-gate inglobal = oing; 13560Sstevel@tonic-gate if (FIXUNDO) 13570Sstevel@tonic-gate vundkind = VMANY; 13580Sstevel@tonic-gate vmcurs = 0; 13590Sstevel@tonic-gate } 13600Sstevel@tonic-gate 13610Sstevel@tonic-gate /* 13620Sstevel@tonic-gate * Save the current contents of linebuf, if it has changed. 13630Sstevel@tonic-gate */ 1364*802Scf46844 void 1365*802Scf46844 vsave(void) 13660Sstevel@tonic-gate { 13670Sstevel@tonic-gate unsigned char temp[LBSIZE]; 13680Sstevel@tonic-gate 13690Sstevel@tonic-gate strncpy(temp, linebuf, sizeof (temp)); 13700Sstevel@tonic-gate if (FIXUNDO && vundkind == VCHNG || vundkind == VCAPU) { 13710Sstevel@tonic-gate /* 13720Sstevel@tonic-gate * If the undo state is saved in the temporary buffer 13730Sstevel@tonic-gate * vutmp, then we sync this into the temp file so that 13740Sstevel@tonic-gate * we will be able to undo even after we have moved off 13750Sstevel@tonic-gate * the line. It would be possible to associate a line 13760Sstevel@tonic-gate * with vutmp but we assume that vutmp is only associated 13770Sstevel@tonic-gate * with line dot (e.g. in case ':') above, so beware. 13780Sstevel@tonic-gate */ 13790Sstevel@tonic-gate prepapp(); 13800Sstevel@tonic-gate strcLIN(vutmp); 13810Sstevel@tonic-gate putmark(dot); 13820Sstevel@tonic-gate vremote(1, yank, 0); 13830Sstevel@tonic-gate vundkind = VMCHNG; 13840Sstevel@tonic-gate notecnt = 0; 13850Sstevel@tonic-gate undkind = UNDCHANGE; 13860Sstevel@tonic-gate } 13870Sstevel@tonic-gate /* 13880Sstevel@tonic-gate * Get the line out of the temp file and do nothing if it hasn't 13890Sstevel@tonic-gate * changed. This may seem like a loss, but the line will 13900Sstevel@tonic-gate * almost always be in a read buffer so this may well avoid disk i/o. 13910Sstevel@tonic-gate */ 13920Sstevel@tonic-gate getDOT(); 13930Sstevel@tonic-gate if (strncmp(linebuf, temp, sizeof (temp)) == 0) 13940Sstevel@tonic-gate return; 13950Sstevel@tonic-gate strcLIN(temp); 13960Sstevel@tonic-gate putmark(dot); 13970Sstevel@tonic-gate } 13980Sstevel@tonic-gate 13990Sstevel@tonic-gate #undef forbid 1400*802Scf46844 #define forbid(a) if (a) { (void) beep(); return; } 14010Sstevel@tonic-gate 14020Sstevel@tonic-gate /* 14030Sstevel@tonic-gate * Do a z operation. 14040Sstevel@tonic-gate * Code here is rather long, and very uninteresting. 14050Sstevel@tonic-gate */ 1406*802Scf46844 void 1407*802Scf46844 vzop(bool hadcnt, int cnt, int c) 14080Sstevel@tonic-gate { 1409*802Scf46844 line *addr; 14100Sstevel@tonic-gate 14110Sstevel@tonic-gate if (state != VISUAL) { 14120Sstevel@tonic-gate /* 14130Sstevel@tonic-gate * Z from open; always like a z=. 14140Sstevel@tonic-gate * This code is a mess and should be cleaned up. 14150Sstevel@tonic-gate */ 14160Sstevel@tonic-gate vmoveitup(1, 1); 14170Sstevel@tonic-gate vgoto(outline, 0); 14180Sstevel@tonic-gate ostop(normf); 14190Sstevel@tonic-gate setoutt(); 14200Sstevel@tonic-gate addr2 = dot; 14210Sstevel@tonic-gate vclear(); 14220Sstevel@tonic-gate destline = WECHO; 14230Sstevel@tonic-gate zop2(Xhadcnt ? Xcnt : value(vi_WINDOW) - 1, '='); 14240Sstevel@tonic-gate if (state == CRTOPEN) 14250Sstevel@tonic-gate putnl(); 14260Sstevel@tonic-gate putNFL(); 14270Sstevel@tonic-gate termreset(); 14280Sstevel@tonic-gate Outchar = vputchar; 14290Sstevel@tonic-gate (void)ostart(); 14300Sstevel@tonic-gate vcnt = 0; 14310Sstevel@tonic-gate outline = destline = 0; 14320Sstevel@tonic-gate vjumpto(dot, cursor, 0); 14330Sstevel@tonic-gate return; 14340Sstevel@tonic-gate } 14350Sstevel@tonic-gate if (hadcnt) { 14360Sstevel@tonic-gate addr = zero + cnt; 14370Sstevel@tonic-gate if (addr < one) 14380Sstevel@tonic-gate addr = one; 14390Sstevel@tonic-gate if (addr > dol) 14400Sstevel@tonic-gate addr = dol; 14410Sstevel@tonic-gate markit(addr); 14420Sstevel@tonic-gate } else 14430Sstevel@tonic-gate switch (c) { 14440Sstevel@tonic-gate 14450Sstevel@tonic-gate case '+': 14460Sstevel@tonic-gate addr = dot + vcnt - vcline; 14470Sstevel@tonic-gate break; 14480Sstevel@tonic-gate 14490Sstevel@tonic-gate case '^': 14500Sstevel@tonic-gate addr = dot - vcline - 1; 14510Sstevel@tonic-gate forbid (addr < one); 14520Sstevel@tonic-gate c = '-'; 14530Sstevel@tonic-gate break; 14540Sstevel@tonic-gate 14550Sstevel@tonic-gate default: 14560Sstevel@tonic-gate addr = dot; 14570Sstevel@tonic-gate break; 14580Sstevel@tonic-gate } 14590Sstevel@tonic-gate switch (c) { 14600Sstevel@tonic-gate 14610Sstevel@tonic-gate case '.': 14620Sstevel@tonic-gate case '-': 14630Sstevel@tonic-gate break; 14640Sstevel@tonic-gate 14650Sstevel@tonic-gate case '^': 14660Sstevel@tonic-gate forbid (addr <= one); 14670Sstevel@tonic-gate break; 14680Sstevel@tonic-gate 14690Sstevel@tonic-gate case '+': 14700Sstevel@tonic-gate forbid (addr >= dol); 14710Sstevel@tonic-gate /* fall into ... */ 14720Sstevel@tonic-gate 14730Sstevel@tonic-gate case CR: 14740Sstevel@tonic-gate case NL: 14750Sstevel@tonic-gate c = CR; 14760Sstevel@tonic-gate break; 14770Sstevel@tonic-gate 14780Sstevel@tonic-gate default: 1479*802Scf46844 (void) beep(); 14800Sstevel@tonic-gate return; 14810Sstevel@tonic-gate } 14820Sstevel@tonic-gate vmoving = 0; 1483*802Scf46844 vjumpto(addr, (unsigned char *)NOSTR, c); 14840Sstevel@tonic-gate } 1485