1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 24*7c478bd9Sstevel@tonic-gate 25*7c478bd9Sstevel@tonic-gate 26*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1981 Regents of the University of California */ 27*7c478bd9Sstevel@tonic-gate /* 28*7c478bd9Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 29*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 30*7c478bd9Sstevel@tonic-gate */ 31*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.22 */ 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate #include "ex.h" 34*7c478bd9Sstevel@tonic-gate #include "ex_tty.h" 35*7c478bd9Sstevel@tonic-gate #include "ex_vis.h" 36*7c478bd9Sstevel@tonic-gate #ifndef PRESUNEUC 37*7c478bd9Sstevel@tonic-gate #include <wctype.h> 38*7c478bd9Sstevel@tonic-gate /* Undef putchar/getchar if they're defined. */ 39*7c478bd9Sstevel@tonic-gate #ifdef putchar 40*7c478bd9Sstevel@tonic-gate # undef putchar 41*7c478bd9Sstevel@tonic-gate #endif 42*7c478bd9Sstevel@tonic-gate #ifdef getchar 43*7c478bd9Sstevel@tonic-gate # undef getchar 44*7c478bd9Sstevel@tonic-gate #endif 45*7c478bd9Sstevel@tonic-gate #endif /* PRESUNEUC */ 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate /* 48*7c478bd9Sstevel@tonic-gate * This is the main routine for visual. 49*7c478bd9Sstevel@tonic-gate * We here decode the count and possible named buffer specification 50*7c478bd9Sstevel@tonic-gate * preceding a command and interpret a few of the commands. 51*7c478bd9Sstevel@tonic-gate * Commands which involve a target (i.e. an operator) are decoded 52*7c478bd9Sstevel@tonic-gate * in the routine operate in ex_voperate.c. 53*7c478bd9Sstevel@tonic-gate */ 54*7c478bd9Sstevel@tonic-gate 55*7c478bd9Sstevel@tonic-gate #define forbid(a) { if (a) goto fonfon; } 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate extern int windowchg; 58*7c478bd9Sstevel@tonic-gate extern int sigok; 59*7c478bd9Sstevel@tonic-gate void redraw(), windowinit(); 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate #ifdef XPG4 62*7c478bd9Sstevel@tonic-gate extern int P_cursor_offset; 63*7c478bd9Sstevel@tonic-gate #endif 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate vmain() 66*7c478bd9Sstevel@tonic-gate { 67*7c478bd9Sstevel@tonic-gate register int c, cnt, i; 68*7c478bd9Sstevel@tonic-gate wchar_t esave[TUBECOLS]; 69*7c478bd9Sstevel@tonic-gate extern wchar_t atube[]; 70*7c478bd9Sstevel@tonic-gate unsigned char *oglobp; 71*7c478bd9Sstevel@tonic-gate short d; 72*7c478bd9Sstevel@tonic-gate line *addr; 73*7c478bd9Sstevel@tonic-gate int ind, nlput; 74*7c478bd9Sstevel@tonic-gate int shouldpo = 0; 75*7c478bd9Sstevel@tonic-gate int tag_reset_wrap = 0; 76*7c478bd9Sstevel@tonic-gate int onumber, olist, (*OPline)(), (*OPutchar)(); 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate vch_mac = VC_NOTINMAC; 80*7c478bd9Sstevel@tonic-gate ixlatctl(0); 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate /* 83*7c478bd9Sstevel@tonic-gate * If we started as a vi command (on the command line) 84*7c478bd9Sstevel@tonic-gate * then go process initial commands (recover, next or tag). 85*7c478bd9Sstevel@tonic-gate */ 86*7c478bd9Sstevel@tonic-gate if (initev) { 87*7c478bd9Sstevel@tonic-gate oglobp = globp; 88*7c478bd9Sstevel@tonic-gate globp = initev; 89*7c478bd9Sstevel@tonic-gate hadcnt = cnt = 0; 90*7c478bd9Sstevel@tonic-gate i = tchng; 91*7c478bd9Sstevel@tonic-gate addr = dot; 92*7c478bd9Sstevel@tonic-gate goto doinit; 93*7c478bd9Sstevel@tonic-gate } 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate vshowmode(""); /* As a precaution */ 96*7c478bd9Sstevel@tonic-gate /* 97*7c478bd9Sstevel@tonic-gate * NB: 98*7c478bd9Sstevel@tonic-gate * 99*7c478bd9Sstevel@tonic-gate * The current line is always in the line buffer linebuf, 100*7c478bd9Sstevel@tonic-gate * and the cursor at the position cursor. You should do 101*7c478bd9Sstevel@tonic-gate * a vsave() before moving off the line to make sure the disk 102*7c478bd9Sstevel@tonic-gate * copy is updated if it has changed, and a getDOT() to get 103*7c478bd9Sstevel@tonic-gate * the line back if you mung linebuf. The motion 104*7c478bd9Sstevel@tonic-gate * routines in ex_vwind.c handle most of this. 105*7c478bd9Sstevel@tonic-gate */ 106*7c478bd9Sstevel@tonic-gate for (;;) { 107*7c478bd9Sstevel@tonic-gate /* 108*7c478bd9Sstevel@tonic-gate * Decode a visual command. 109*7c478bd9Sstevel@tonic-gate * First sync the temp file if there has been a reasonable 110*7c478bd9Sstevel@tonic-gate * amount of change. Clear state for decoding of next 111*7c478bd9Sstevel@tonic-gate * command. 112*7c478bd9Sstevel@tonic-gate */ 113*7c478bd9Sstevel@tonic-gate TSYNC(); 114*7c478bd9Sstevel@tonic-gate vglobp = 0; 115*7c478bd9Sstevel@tonic-gate vreg = 0; 116*7c478bd9Sstevel@tonic-gate hold = 0; 117*7c478bd9Sstevel@tonic-gate seenprompt = 1; 118*7c478bd9Sstevel@tonic-gate wcursor = 0; 119*7c478bd9Sstevel@tonic-gate Xhadcnt = hadcnt = 0; 120*7c478bd9Sstevel@tonic-gate Xcnt = cnt = 1; 121*7c478bd9Sstevel@tonic-gate splitw = 0; 122*7c478bd9Sstevel@tonic-gate if (i = holdupd && !windowchg) { 123*7c478bd9Sstevel@tonic-gate if (state == VISUAL) { 124*7c478bd9Sstevel@tonic-gate sigok = 1; 125*7c478bd9Sstevel@tonic-gate (void)peekkey(); 126*7c478bd9Sstevel@tonic-gate sigok = 0; 127*7c478bd9Sstevel@tonic-gate } 128*7c478bd9Sstevel@tonic-gate 129*7c478bd9Sstevel@tonic-gate holdupd = 0; 130*7c478bd9Sstevel@tonic-gate /* 131*7c478bd9Sstevel@tonic-gate if (LINE(0) < ZERO) { 132*7c478bd9Sstevel@tonic-gate vclear(); 133*7c478bd9Sstevel@tonic-gate vcnt = 0; 134*7c478bd9Sstevel@tonic-gate i = 3; 135*7c478bd9Sstevel@tonic-gate } 136*7c478bd9Sstevel@tonic-gate */ 137*7c478bd9Sstevel@tonic-gate if (state != VISUAL) { 138*7c478bd9Sstevel@tonic-gate vcnt = 0; 139*7c478bd9Sstevel@tonic-gate vsave(); 140*7c478bd9Sstevel@tonic-gate vrepaint(cursor); 141*7c478bd9Sstevel@tonic-gate } else if (i == 3) 142*7c478bd9Sstevel@tonic-gate vredraw(WTOP); 143*7c478bd9Sstevel@tonic-gate else 144*7c478bd9Sstevel@tonic-gate vsync(WTOP); 145*7c478bd9Sstevel@tonic-gate vfixcurs(); 146*7c478bd9Sstevel@tonic-gate } else if(windowchg) 147*7c478bd9Sstevel@tonic-gate redraw(); 148*7c478bd9Sstevel@tonic-gate 149*7c478bd9Sstevel@tonic-gate /* 150*7c478bd9Sstevel@tonic-gate * Gobble up counts and named buffer specifications. 151*7c478bd9Sstevel@tonic-gate */ 152*7c478bd9Sstevel@tonic-gate for (;;) { 153*7c478bd9Sstevel@tonic-gate looptop: 154*7c478bd9Sstevel@tonic-gate #ifdef MDEBUG 155*7c478bd9Sstevel@tonic-gate if (trace) 156*7c478bd9Sstevel@tonic-gate fprintf(trace, "pc=%c",peekkey()); 157*7c478bd9Sstevel@tonic-gate #endif 158*7c478bd9Sstevel@tonic-gate sigok = 1; 159*7c478bd9Sstevel@tonic-gate c = peekkey(); 160*7c478bd9Sstevel@tonic-gate sigok = 0; 161*7c478bd9Sstevel@tonic-gate if (isdigit(peekkey()) && peekkey() != '0') { 162*7c478bd9Sstevel@tonic-gate hadcnt = 1; 163*7c478bd9Sstevel@tonic-gate cnt = vgetcnt(); 164*7c478bd9Sstevel@tonic-gate forbid (cnt <= 0); 165*7c478bd9Sstevel@tonic-gate } 166*7c478bd9Sstevel@tonic-gate if (peekkey() != '"') 167*7c478bd9Sstevel@tonic-gate break; 168*7c478bd9Sstevel@tonic-gate (void)getkey(), c = getkey(); 169*7c478bd9Sstevel@tonic-gate /* 170*7c478bd9Sstevel@tonic-gate * Buffer names be letters or digits. 171*7c478bd9Sstevel@tonic-gate * But not '0' as that is the source of 172*7c478bd9Sstevel@tonic-gate * an 'empty' named buffer spec in the routine 173*7c478bd9Sstevel@tonic-gate * kshift (see ex_temp.c). 174*7c478bd9Sstevel@tonic-gate */ 175*7c478bd9Sstevel@tonic-gate if(!isascii(c) && MB_CUR_MAX > 1) { 176*7c478bd9Sstevel@tonic-gate /* get rest of character */ 177*7c478bd9Sstevel@tonic-gate wchar_t wchar; 178*7c478bd9Sstevel@tonic-gate char multic[MULTI_BYTE_MAX]; 179*7c478bd9Sstevel@tonic-gate ungetkey(c); 180*7c478bd9Sstevel@tonic-gate (void)_mbftowc(multic, &wchar, getkey, &Peekkey); 181*7c478bd9Sstevel@tonic-gate } 182*7c478bd9Sstevel@tonic-gate forbid (c == '0' || !isalpha(c) && !isascii(c) && !isdigit(c)); 183*7c478bd9Sstevel@tonic-gate vreg = c; 184*7c478bd9Sstevel@tonic-gate } 185*7c478bd9Sstevel@tonic-gate reread: 186*7c478bd9Sstevel@tonic-gate /* 187*7c478bd9Sstevel@tonic-gate * Come to reread from below after some macro expansions. 188*7c478bd9Sstevel@tonic-gate * The call to map allows use of function key pads 189*7c478bd9Sstevel@tonic-gate * by performing a terminal dependent mapping of inputs. 190*7c478bd9Sstevel@tonic-gate */ 191*7c478bd9Sstevel@tonic-gate #ifdef MDEBUG 192*7c478bd9Sstevel@tonic-gate if (trace) 193*7c478bd9Sstevel@tonic-gate fprintf(trace,"pcb=%c,",peekkey()); 194*7c478bd9Sstevel@tonic-gate #endif 195*7c478bd9Sstevel@tonic-gate op = getkey(); 196*7c478bd9Sstevel@tonic-gate maphopcnt = 0; 197*7c478bd9Sstevel@tonic-gate do { 198*7c478bd9Sstevel@tonic-gate /* 199*7c478bd9Sstevel@tonic-gate * Keep mapping the char as long as it changes. 200*7c478bd9Sstevel@tonic-gate * This allows for double mappings, e.g., q to #, 201*7c478bd9Sstevel@tonic-gate * #1 to something else. 202*7c478bd9Sstevel@tonic-gate */ 203*7c478bd9Sstevel@tonic-gate c = op; 204*7c478bd9Sstevel@tonic-gate op = map(c,arrows,0); 205*7c478bd9Sstevel@tonic-gate #ifdef MDEBUG 206*7c478bd9Sstevel@tonic-gate if (trace) 207*7c478bd9Sstevel@tonic-gate fprintf(trace,"pca=%c,",c); 208*7c478bd9Sstevel@tonic-gate #endif 209*7c478bd9Sstevel@tonic-gate /* 210*7c478bd9Sstevel@tonic-gate * Maybe the mapped to char is a count. If so, we have 211*7c478bd9Sstevel@tonic-gate * to go back to the "for" to interpret it. Likewise 212*7c478bd9Sstevel@tonic-gate * for a buffer name. 213*7c478bd9Sstevel@tonic-gate */ 214*7c478bd9Sstevel@tonic-gate if ((isdigit(c) && c!='0') || c == '"') { 215*7c478bd9Sstevel@tonic-gate ungetkey(c); 216*7c478bd9Sstevel@tonic-gate goto looptop; 217*7c478bd9Sstevel@tonic-gate } 218*7c478bd9Sstevel@tonic-gate if (!value(vi_REMAP)) { 219*7c478bd9Sstevel@tonic-gate c = op; 220*7c478bd9Sstevel@tonic-gate break; 221*7c478bd9Sstevel@tonic-gate } 222*7c478bd9Sstevel@tonic-gate if (++maphopcnt > 256) 223*7c478bd9Sstevel@tonic-gate error(gettext("Infinite macro loop")); 224*7c478bd9Sstevel@tonic-gate } while (c != op); 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate /* 227*7c478bd9Sstevel@tonic-gate * Begin to build an image of this command for possible 228*7c478bd9Sstevel@tonic-gate * later repeat in the buffer workcmd. It will be copied 229*7c478bd9Sstevel@tonic-gate * to lastcmd by the routine setLAST 230*7c478bd9Sstevel@tonic-gate * if/when completely specified. 231*7c478bd9Sstevel@tonic-gate */ 232*7c478bd9Sstevel@tonic-gate lastcp = workcmd; 233*7c478bd9Sstevel@tonic-gate if (!vglobp) 234*7c478bd9Sstevel@tonic-gate *lastcp++ = c; 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate /* 237*7c478bd9Sstevel@tonic-gate * First level command decode. 238*7c478bd9Sstevel@tonic-gate */ 239*7c478bd9Sstevel@tonic-gate switch (c) { 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate /* 242*7c478bd9Sstevel@tonic-gate * ^L Clear screen e.g. after transmission error. 243*7c478bd9Sstevel@tonic-gate */ 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate /* 246*7c478bd9Sstevel@tonic-gate * ^R Retype screen, getting rid of @ lines. 247*7c478bd9Sstevel@tonic-gate * If in open, equivalent to ^L. 248*7c478bd9Sstevel@tonic-gate * On terminals where the right arrow key sends 249*7c478bd9Sstevel@tonic-gate * ^L we make ^R act like ^L, since there is no 250*7c478bd9Sstevel@tonic-gate * way to get ^L. These terminals (adm31, tvi) 251*7c478bd9Sstevel@tonic-gate * are intelligent so ^R is useless. Soroc 252*7c478bd9Sstevel@tonic-gate * will probably foul this up, but nobody has 253*7c478bd9Sstevel@tonic-gate * one of them. 254*7c478bd9Sstevel@tonic-gate */ 255*7c478bd9Sstevel@tonic-gate case CTRL('l'): 256*7c478bd9Sstevel@tonic-gate case CTRL('r'): 257*7c478bd9Sstevel@tonic-gate if (c == CTRL('l') || (key_right && *key_right==CTRL('l'))) { 258*7c478bd9Sstevel@tonic-gate vclear(); 259*7c478bd9Sstevel@tonic-gate vdirty(0, vcnt); 260*7c478bd9Sstevel@tonic-gate } 261*7c478bd9Sstevel@tonic-gate if (state != VISUAL) { 262*7c478bd9Sstevel@tonic-gate /* 263*7c478bd9Sstevel@tonic-gate * Get a clean line, throw away the 264*7c478bd9Sstevel@tonic-gate * memory of what is displayed now, 265*7c478bd9Sstevel@tonic-gate * and move back onto the current line. 266*7c478bd9Sstevel@tonic-gate */ 267*7c478bd9Sstevel@tonic-gate vclean(); 268*7c478bd9Sstevel@tonic-gate vcnt = 0; 269*7c478bd9Sstevel@tonic-gate vmoveto(dot, cursor, 0); 270*7c478bd9Sstevel@tonic-gate continue; 271*7c478bd9Sstevel@tonic-gate } 272*7c478bd9Sstevel@tonic-gate vredraw(WTOP); 273*7c478bd9Sstevel@tonic-gate /* 274*7c478bd9Sstevel@tonic-gate * Weird glitch -- when we enter visual 275*7c478bd9Sstevel@tonic-gate * in a very small window we may end up with 276*7c478bd9Sstevel@tonic-gate * no lines on the screen because the line 277*7c478bd9Sstevel@tonic-gate * at the top is too long. This forces the screen 278*7c478bd9Sstevel@tonic-gate * to be expanded to make room for it (after 279*7c478bd9Sstevel@tonic-gate * we have printed @'s ick showing we goofed). 280*7c478bd9Sstevel@tonic-gate */ 281*7c478bd9Sstevel@tonic-gate if (vcnt == 0) 282*7c478bd9Sstevel@tonic-gate vrepaint(cursor); 283*7c478bd9Sstevel@tonic-gate vfixcurs(); 284*7c478bd9Sstevel@tonic-gate continue; 285*7c478bd9Sstevel@tonic-gate 286*7c478bd9Sstevel@tonic-gate /* 287*7c478bd9Sstevel@tonic-gate * $ Escape just cancels the current command 288*7c478bd9Sstevel@tonic-gate * with a little feedback. 289*7c478bd9Sstevel@tonic-gate */ 290*7c478bd9Sstevel@tonic-gate case ESCAPE: 291*7c478bd9Sstevel@tonic-gate beep(); 292*7c478bd9Sstevel@tonic-gate continue; 293*7c478bd9Sstevel@tonic-gate 294*7c478bd9Sstevel@tonic-gate /* 295*7c478bd9Sstevel@tonic-gate * @ Macros. Bring in the macro and put it 296*7c478bd9Sstevel@tonic-gate * in vmacbuf, point vglobp there and punt. 297*7c478bd9Sstevel@tonic-gate */ 298*7c478bd9Sstevel@tonic-gate case '@': 299*7c478bd9Sstevel@tonic-gate c = getesc(); 300*7c478bd9Sstevel@tonic-gate if (c == 0) 301*7c478bd9Sstevel@tonic-gate continue; 302*7c478bd9Sstevel@tonic-gate if (c == '@') 303*7c478bd9Sstevel@tonic-gate c = lastmac; 304*7c478bd9Sstevel@tonic-gate if (isupper(c)) 305*7c478bd9Sstevel@tonic-gate c = tolower(c); 306*7c478bd9Sstevel@tonic-gate forbid(!islower(c)); 307*7c478bd9Sstevel@tonic-gate lastmac = c; 308*7c478bd9Sstevel@tonic-gate vsave(); 309*7c478bd9Sstevel@tonic-gate CATCH 310*7c478bd9Sstevel@tonic-gate unsigned char tmpbuf[BUFSIZE]; 311*7c478bd9Sstevel@tonic-gate 312*7c478bd9Sstevel@tonic-gate regbuf(c,tmpbuf,sizeof(vmacbuf)); 313*7c478bd9Sstevel@tonic-gate macpush(tmpbuf, 1); 314*7c478bd9Sstevel@tonic-gate ONERR 315*7c478bd9Sstevel@tonic-gate lastmac = 0; 316*7c478bd9Sstevel@tonic-gate splitw = 0; 317*7c478bd9Sstevel@tonic-gate getDOT(); 318*7c478bd9Sstevel@tonic-gate vrepaint(cursor); 319*7c478bd9Sstevel@tonic-gate continue; 320*7c478bd9Sstevel@tonic-gate ENDCATCH 321*7c478bd9Sstevel@tonic-gate vmacp = vmacbuf; 322*7c478bd9Sstevel@tonic-gate goto reread; 323*7c478bd9Sstevel@tonic-gate 324*7c478bd9Sstevel@tonic-gate /* 325*7c478bd9Sstevel@tonic-gate * . Repeat the last (modifying) open/visual command. 326*7c478bd9Sstevel@tonic-gate */ 327*7c478bd9Sstevel@tonic-gate case '.': 328*7c478bd9Sstevel@tonic-gate /* 329*7c478bd9Sstevel@tonic-gate * Check that there was a last command, and 330*7c478bd9Sstevel@tonic-gate * take its count and named buffer unless they 331*7c478bd9Sstevel@tonic-gate * were given anew. Special case if last command 332*7c478bd9Sstevel@tonic-gate * referenced a numeric named buffer -- increment 333*7c478bd9Sstevel@tonic-gate * the number and go to a named buffer again. 334*7c478bd9Sstevel@tonic-gate * This allows a sequence like "1pu.u.u... 335*7c478bd9Sstevel@tonic-gate * to successively look for stuff in the kill chain 336*7c478bd9Sstevel@tonic-gate * much as one does in EMACS with C-Y and M-Y. 337*7c478bd9Sstevel@tonic-gate */ 338*7c478bd9Sstevel@tonic-gate forbid (lastcmd[0] == 0); 339*7c478bd9Sstevel@tonic-gate if (hadcnt) 340*7c478bd9Sstevel@tonic-gate lastcnt = cnt; 341*7c478bd9Sstevel@tonic-gate if (vreg) 342*7c478bd9Sstevel@tonic-gate lastreg = vreg; 343*7c478bd9Sstevel@tonic-gate else if (isdigit(lastreg) && lastreg < '9') 344*7c478bd9Sstevel@tonic-gate lastreg++; 345*7c478bd9Sstevel@tonic-gate vreg = lastreg; 346*7c478bd9Sstevel@tonic-gate cnt = lastcnt; 347*7c478bd9Sstevel@tonic-gate hadcnt = lasthad; 348*7c478bd9Sstevel@tonic-gate vglobp = lastcmd; 349*7c478bd9Sstevel@tonic-gate goto reread; 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate /* 352*7c478bd9Sstevel@tonic-gate * ^U Scroll up. A count sticks around for 353*7c478bd9Sstevel@tonic-gate * future scrolls as the scroll amount. 354*7c478bd9Sstevel@tonic-gate * Attempt to hold the indentation from the 355*7c478bd9Sstevel@tonic-gate * top of the screen (in logical lines). 356*7c478bd9Sstevel@tonic-gate * 357*7c478bd9Sstevel@tonic-gate * BUG: A ^U near the bottom of the screen 358*7c478bd9Sstevel@tonic-gate * on a dumb terminal (which can't roll back) 359*7c478bd9Sstevel@tonic-gate * causes the screen to be cleared and then 360*7c478bd9Sstevel@tonic-gate * redrawn almost as it was. In this case 361*7c478bd9Sstevel@tonic-gate * one should simply move the cursor. 362*7c478bd9Sstevel@tonic-gate */ 363*7c478bd9Sstevel@tonic-gate case CTRL('u'): 364*7c478bd9Sstevel@tonic-gate if (hadcnt) 365*7c478bd9Sstevel@tonic-gate vSCROLL = cnt; 366*7c478bd9Sstevel@tonic-gate cnt = vSCROLL; 367*7c478bd9Sstevel@tonic-gate if (state == VISUAL) 368*7c478bd9Sstevel@tonic-gate ind = vcline, cnt += ind; 369*7c478bd9Sstevel@tonic-gate else 370*7c478bd9Sstevel@tonic-gate ind = 0; 371*7c478bd9Sstevel@tonic-gate vmoving = 0; 372*7c478bd9Sstevel@tonic-gate vup(cnt, ind, 1); 373*7c478bd9Sstevel@tonic-gate vnline(NOSTR); 374*7c478bd9Sstevel@tonic-gate continue; 375*7c478bd9Sstevel@tonic-gate 376*7c478bd9Sstevel@tonic-gate /* 377*7c478bd9Sstevel@tonic-gate * ^D Scroll down. Like scroll up. 378*7c478bd9Sstevel@tonic-gate */ 379*7c478bd9Sstevel@tonic-gate case CTRL('d'): 380*7c478bd9Sstevel@tonic-gate #ifdef TRACE 381*7c478bd9Sstevel@tonic-gate if (trace) 382*7c478bd9Sstevel@tonic-gate fprintf(trace, "before vdown in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol)); 383*7c478bd9Sstevel@tonic-gate #endif 384*7c478bd9Sstevel@tonic-gate if (hadcnt) 385*7c478bd9Sstevel@tonic-gate vSCROLL = cnt; 386*7c478bd9Sstevel@tonic-gate cnt = vSCROLL; 387*7c478bd9Sstevel@tonic-gate if (state == VISUAL) 388*7c478bd9Sstevel@tonic-gate ind = vcnt - vcline - 1, cnt += ind; 389*7c478bd9Sstevel@tonic-gate else 390*7c478bd9Sstevel@tonic-gate ind = 0; 391*7c478bd9Sstevel@tonic-gate vmoving = 0; 392*7c478bd9Sstevel@tonic-gate vdown(cnt, ind, 1); 393*7c478bd9Sstevel@tonic-gate #ifdef TRACE 394*7c478bd9Sstevel@tonic-gate if (trace) 395*7c478bd9Sstevel@tonic-gate fprintf(trace, "before vnline in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol)); 396*7c478bd9Sstevel@tonic-gate #endif 397*7c478bd9Sstevel@tonic-gate vnline(NOSTR); 398*7c478bd9Sstevel@tonic-gate #ifdef TRACE 399*7c478bd9Sstevel@tonic-gate if (trace) 400*7c478bd9Sstevel@tonic-gate fprintf(trace, "after vnline in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol)); 401*7c478bd9Sstevel@tonic-gate #endif 402*7c478bd9Sstevel@tonic-gate continue; 403*7c478bd9Sstevel@tonic-gate 404*7c478bd9Sstevel@tonic-gate /* 405*7c478bd9Sstevel@tonic-gate * ^E Glitch the screen down (one) line. 406*7c478bd9Sstevel@tonic-gate * Cursor left on same line in file. 407*7c478bd9Sstevel@tonic-gate */ 408*7c478bd9Sstevel@tonic-gate case CTRL('e'): 409*7c478bd9Sstevel@tonic-gate if (state != VISUAL) 410*7c478bd9Sstevel@tonic-gate continue; 411*7c478bd9Sstevel@tonic-gate if (!hadcnt) 412*7c478bd9Sstevel@tonic-gate cnt = 1; 413*7c478bd9Sstevel@tonic-gate /* Bottom line of file already on screen */ 414*7c478bd9Sstevel@tonic-gate forbid(lineDOL()-lineDOT() <= vcnt-1-vcline); 415*7c478bd9Sstevel@tonic-gate ind = vcnt - vcline - 1 + cnt; 416*7c478bd9Sstevel@tonic-gate vdown(ind, ind, 1); 417*7c478bd9Sstevel@tonic-gate vnline(cursor); 418*7c478bd9Sstevel@tonic-gate continue; 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate /* 421*7c478bd9Sstevel@tonic-gate * ^Y Like ^E but up 422*7c478bd9Sstevel@tonic-gate */ 423*7c478bd9Sstevel@tonic-gate case CTRL('y'): 424*7c478bd9Sstevel@tonic-gate if (state != VISUAL) 425*7c478bd9Sstevel@tonic-gate continue; 426*7c478bd9Sstevel@tonic-gate if (!hadcnt) 427*7c478bd9Sstevel@tonic-gate cnt = 1; 428*7c478bd9Sstevel@tonic-gate forbid(lineDOT()-1<=vcline); /* line 1 already there */ 429*7c478bd9Sstevel@tonic-gate ind = vcline + cnt; 430*7c478bd9Sstevel@tonic-gate vup(ind, ind, 1); 431*7c478bd9Sstevel@tonic-gate vnline(cursor); 432*7c478bd9Sstevel@tonic-gate continue; 433*7c478bd9Sstevel@tonic-gate 434*7c478bd9Sstevel@tonic-gate 435*7c478bd9Sstevel@tonic-gate /* 436*7c478bd9Sstevel@tonic-gate * m Mark position in mark register given 437*7c478bd9Sstevel@tonic-gate * by following letter. Return is 438*7c478bd9Sstevel@tonic-gate * accomplished via ' or `; former 439*7c478bd9Sstevel@tonic-gate * to beginning of line where mark 440*7c478bd9Sstevel@tonic-gate * was set, latter to column where marked. 441*7c478bd9Sstevel@tonic-gate */ 442*7c478bd9Sstevel@tonic-gate case 'm': 443*7c478bd9Sstevel@tonic-gate /* 444*7c478bd9Sstevel@tonic-gate * Getesc is generally used when a character 445*7c478bd9Sstevel@tonic-gate * is read as a latter part of a command 446*7c478bd9Sstevel@tonic-gate * to allow one to hit rubout/escape to cancel 447*7c478bd9Sstevel@tonic-gate * what you have typed so far. These characters 448*7c478bd9Sstevel@tonic-gate * are mapped to 0 by the subroutine. 449*7c478bd9Sstevel@tonic-gate */ 450*7c478bd9Sstevel@tonic-gate c = getesc(); 451*7c478bd9Sstevel@tonic-gate if (c == 0) 452*7c478bd9Sstevel@tonic-gate continue; 453*7c478bd9Sstevel@tonic-gate 454*7c478bd9Sstevel@tonic-gate /* 455*7c478bd9Sstevel@tonic-gate * Markreg checks that argument is a letter 456*7c478bd9Sstevel@tonic-gate * and also maps ' and ` to the end of the range 457*7c478bd9Sstevel@tonic-gate * to allow '' or `` to reference the previous 458*7c478bd9Sstevel@tonic-gate * context mark. 459*7c478bd9Sstevel@tonic-gate */ 460*7c478bd9Sstevel@tonic-gate c = markreg(c); 461*7c478bd9Sstevel@tonic-gate forbid (c == 0); 462*7c478bd9Sstevel@tonic-gate vsave(); 463*7c478bd9Sstevel@tonic-gate names[c - 'a'] = (*dot &~ 01); 464*7c478bd9Sstevel@tonic-gate ncols[c - 'a'] = cursor; 465*7c478bd9Sstevel@tonic-gate anymarks = 1; 466*7c478bd9Sstevel@tonic-gate continue; 467*7c478bd9Sstevel@tonic-gate 468*7c478bd9Sstevel@tonic-gate /* 469*7c478bd9Sstevel@tonic-gate * ^F Window forwards, with 2 lines of continuity. 470*7c478bd9Sstevel@tonic-gate * Count repeats. 471*7c478bd9Sstevel@tonic-gate */ 472*7c478bd9Sstevel@tonic-gate case CTRL('f'): 473*7c478bd9Sstevel@tonic-gate vsave(); 474*7c478bd9Sstevel@tonic-gate if (vcnt > 2) { 475*7c478bd9Sstevel@tonic-gate addr = dot + (vcnt - vcline) - 2 + (cnt-1)*basWLINES; 476*7c478bd9Sstevel@tonic-gate forbid(addr > dol); 477*7c478bd9Sstevel@tonic-gate dot = addr; 478*7c478bd9Sstevel@tonic-gate vcnt = vcline = 0; 479*7c478bd9Sstevel@tonic-gate } 480*7c478bd9Sstevel@tonic-gate vzop(0, 0, '+'); 481*7c478bd9Sstevel@tonic-gate continue; 482*7c478bd9Sstevel@tonic-gate 483*7c478bd9Sstevel@tonic-gate /* 484*7c478bd9Sstevel@tonic-gate * ^B Window backwards, with 2 lines of continuity. 485*7c478bd9Sstevel@tonic-gate * Inverse of ^F. 486*7c478bd9Sstevel@tonic-gate */ 487*7c478bd9Sstevel@tonic-gate case CTRL('b'): 488*7c478bd9Sstevel@tonic-gate vsave(); 489*7c478bd9Sstevel@tonic-gate if (one + vcline != dot && vcnt > 2) { 490*7c478bd9Sstevel@tonic-gate addr = dot - vcline + 2 - (cnt-1)*basWLINES; 491*7c478bd9Sstevel@tonic-gate forbid (addr <= zero); 492*7c478bd9Sstevel@tonic-gate dot = addr; 493*7c478bd9Sstevel@tonic-gate vcnt = vcline = 0; 494*7c478bd9Sstevel@tonic-gate } 495*7c478bd9Sstevel@tonic-gate vzop(0, 0, '^'); 496*7c478bd9Sstevel@tonic-gate continue; 497*7c478bd9Sstevel@tonic-gate 498*7c478bd9Sstevel@tonic-gate /* 499*7c478bd9Sstevel@tonic-gate * z Screen adjustment, taking a following character: 500*7c478bd9Sstevel@tonic-gate * zcarriage_return current line to top 501*7c478bd9Sstevel@tonic-gate * z<NL> like zcarriage_return 502*7c478bd9Sstevel@tonic-gate * z- current line to bottom 503*7c478bd9Sstevel@tonic-gate * also z+, z^ like ^F and ^B. 504*7c478bd9Sstevel@tonic-gate * A preceding count is line to use rather 505*7c478bd9Sstevel@tonic-gate * than current line. A count between z and 506*7c478bd9Sstevel@tonic-gate * specifier character changes the screen size 507*7c478bd9Sstevel@tonic-gate * for the redraw. 508*7c478bd9Sstevel@tonic-gate * 509*7c478bd9Sstevel@tonic-gate */ 510*7c478bd9Sstevel@tonic-gate case 'z': 511*7c478bd9Sstevel@tonic-gate if (state == VISUAL) { 512*7c478bd9Sstevel@tonic-gate i = vgetcnt(); 513*7c478bd9Sstevel@tonic-gate if (i > 0) 514*7c478bd9Sstevel@tonic-gate vsetsiz(i); 515*7c478bd9Sstevel@tonic-gate c = getesc(); 516*7c478bd9Sstevel@tonic-gate if (c == 0) 517*7c478bd9Sstevel@tonic-gate continue; 518*7c478bd9Sstevel@tonic-gate } 519*7c478bd9Sstevel@tonic-gate vsave(); 520*7c478bd9Sstevel@tonic-gate vzop(hadcnt, cnt, c); 521*7c478bd9Sstevel@tonic-gate continue; 522*7c478bd9Sstevel@tonic-gate 523*7c478bd9Sstevel@tonic-gate /* 524*7c478bd9Sstevel@tonic-gate * Y Yank lines, abbreviation for y_ or yy. 525*7c478bd9Sstevel@tonic-gate * Yanked lines can be put later if no 526*7c478bd9Sstevel@tonic-gate * changes intervene, or can be put in named 527*7c478bd9Sstevel@tonic-gate * buffers and put anytime in this session. 528*7c478bd9Sstevel@tonic-gate */ 529*7c478bd9Sstevel@tonic-gate case 'Y': 530*7c478bd9Sstevel@tonic-gate ungetkey('_'); 531*7c478bd9Sstevel@tonic-gate c = 'y'; 532*7c478bd9Sstevel@tonic-gate break; 533*7c478bd9Sstevel@tonic-gate 534*7c478bd9Sstevel@tonic-gate /* 535*7c478bd9Sstevel@tonic-gate * J Join lines, 2 by default. Count is number 536*7c478bd9Sstevel@tonic-gate * of lines to join (no join operator sorry.) 537*7c478bd9Sstevel@tonic-gate */ 538*7c478bd9Sstevel@tonic-gate case 'J': 539*7c478bd9Sstevel@tonic-gate forbid (dot == dol); 540*7c478bd9Sstevel@tonic-gate if (cnt == 1) 541*7c478bd9Sstevel@tonic-gate cnt = 2; 542*7c478bd9Sstevel@tonic-gate if (cnt > (i = dol - dot + 1)) 543*7c478bd9Sstevel@tonic-gate cnt = i; 544*7c478bd9Sstevel@tonic-gate vsave(); 545*7c478bd9Sstevel@tonic-gate vmacchng(1); 546*7c478bd9Sstevel@tonic-gate setLAST(); 547*7c478bd9Sstevel@tonic-gate cursor = strend(linebuf); 548*7c478bd9Sstevel@tonic-gate vremote(cnt, join, 0); 549*7c478bd9Sstevel@tonic-gate notenam = (unsigned char *)"join"; 550*7c478bd9Sstevel@tonic-gate vmoving = 0; 551*7c478bd9Sstevel@tonic-gate killU(); 552*7c478bd9Sstevel@tonic-gate vreplace(vcline, cnt, 1); 553*7c478bd9Sstevel@tonic-gate if (!*cursor && cursor > linebuf) 554*7c478bd9Sstevel@tonic-gate cursor--; 555*7c478bd9Sstevel@tonic-gate if (notecnt == 2) 556*7c478bd9Sstevel@tonic-gate notecnt = 0; 557*7c478bd9Sstevel@tonic-gate vrepaint(cursor); 558*7c478bd9Sstevel@tonic-gate continue; 559*7c478bd9Sstevel@tonic-gate 560*7c478bd9Sstevel@tonic-gate /* 561*7c478bd9Sstevel@tonic-gate * S Substitute text for whole lines, abbrev for c_. 562*7c478bd9Sstevel@tonic-gate * Count is number of lines to change. 563*7c478bd9Sstevel@tonic-gate */ 564*7c478bd9Sstevel@tonic-gate case 'S': 565*7c478bd9Sstevel@tonic-gate ungetkey('_'); 566*7c478bd9Sstevel@tonic-gate c = 'c'; 567*7c478bd9Sstevel@tonic-gate break; 568*7c478bd9Sstevel@tonic-gate 569*7c478bd9Sstevel@tonic-gate /* 570*7c478bd9Sstevel@tonic-gate * O Create a new line above current and accept new 571*7c478bd9Sstevel@tonic-gate * input text, to an escape, there. 572*7c478bd9Sstevel@tonic-gate * A count specifies, for dumb terminals when 573*7c478bd9Sstevel@tonic-gate * slowopen is not set, the number of physical 574*7c478bd9Sstevel@tonic-gate * line space to open on the screen. 575*7c478bd9Sstevel@tonic-gate * 576*7c478bd9Sstevel@tonic-gate * o Like O, but opens lines below. 577*7c478bd9Sstevel@tonic-gate */ 578*7c478bd9Sstevel@tonic-gate case 'O': 579*7c478bd9Sstevel@tonic-gate case 'o': 580*7c478bd9Sstevel@tonic-gate vmacchng(1); 581*7c478bd9Sstevel@tonic-gate voOpen(c, cnt); 582*7c478bd9Sstevel@tonic-gate continue; 583*7c478bd9Sstevel@tonic-gate 584*7c478bd9Sstevel@tonic-gate /* 585*7c478bd9Sstevel@tonic-gate * C Change text to end of line, short for c$. 586*7c478bd9Sstevel@tonic-gate */ 587*7c478bd9Sstevel@tonic-gate case 'C': 588*7c478bd9Sstevel@tonic-gate if (*cursor) { 589*7c478bd9Sstevel@tonic-gate ungetkey('$'), c = 'c'; 590*7c478bd9Sstevel@tonic-gate break; 591*7c478bd9Sstevel@tonic-gate } 592*7c478bd9Sstevel@tonic-gate goto appnd; 593*7c478bd9Sstevel@tonic-gate 594*7c478bd9Sstevel@tonic-gate /* 595*7c478bd9Sstevel@tonic-gate * ~ Switch case of letter under cursor 596*7c478bd9Sstevel@tonic-gate */ 597*7c478bd9Sstevel@tonic-gate case '~': 598*7c478bd9Sstevel@tonic-gate { 599*7c478bd9Sstevel@tonic-gate unsigned char mbuf[2049]; 600*7c478bd9Sstevel@tonic-gate unsigned char *ccursor = cursor; 601*7c478bd9Sstevel@tonic-gate #ifdef PRESUNEUC 602*7c478bd9Sstevel@tonic-gate int tmp, length; 603*7c478bd9Sstevel@tonic-gate wchar_t wchar; 604*7c478bd9Sstevel@tonic-gate #else 605*7c478bd9Sstevel@tonic-gate int tmp, len, n; 606*7c478bd9Sstevel@tonic-gate wchar_t wc; 607*7c478bd9Sstevel@tonic-gate #endif /* PRESUNEUC */ 608*7c478bd9Sstevel@tonic-gate unsigned char tmp1; 609*7c478bd9Sstevel@tonic-gate setLAST(); 610*7c478bd9Sstevel@tonic-gate for (tmp = 0; tmp + 3 < 2048; ) { 611*7c478bd9Sstevel@tonic-gate /* 612*7c478bd9Sstevel@tonic-gate * Use multiple 'r' commands to replace 613*7c478bd9Sstevel@tonic-gate * alpha with alternate case. 614*7c478bd9Sstevel@tonic-gate */ 615*7c478bd9Sstevel@tonic-gate 616*7c478bd9Sstevel@tonic-gate if(cnt-- <= 0) 617*7c478bd9Sstevel@tonic-gate break; 618*7c478bd9Sstevel@tonic-gate #ifdef PRESUNEUC 619*7c478bd9Sstevel@tonic-gate length = mbtowc(&wchar, (char *)ccursor, MULTI_BYTE_MAX); 620*7c478bd9Sstevel@tonic-gate #else 621*7c478bd9Sstevel@tonic-gate len = mbtowc(&wc, (char *)ccursor, MULTI_BYTE_MAX); 622*7c478bd9Sstevel@tonic-gate #endif /* PRESUNEUC */ 623*7c478bd9Sstevel@tonic-gate #ifdef PRESUNEUC 624*7c478bd9Sstevel@tonic-gate if(length > 1) { 625*7c478bd9Sstevel@tonic-gate #else 626*7c478bd9Sstevel@tonic-gate n = iswalpha(wc); 627*7c478bd9Sstevel@tonic-gate if(len > 1 && !iswalpha(wc)) { 628*7c478bd9Sstevel@tonic-gate #endif /* PRESUNEUC */ 629*7c478bd9Sstevel@tonic-gate mbuf[tmp+0] = ' '; 630*7c478bd9Sstevel@tonic-gate tmp++; 631*7c478bd9Sstevel@tonic-gate #ifdef PRESUNEUC 632*7c478bd9Sstevel@tonic-gate ccursor += length; 633*7c478bd9Sstevel@tonic-gate #else 634*7c478bd9Sstevel@tonic-gate ccursor += len; 635*7c478bd9Sstevel@tonic-gate #endif /* PRESUNEUC */ 636*7c478bd9Sstevel@tonic-gate continue; 637*7c478bd9Sstevel@tonic-gate } 638*7c478bd9Sstevel@tonic-gate mbuf[tmp] = 'r'; 639*7c478bd9Sstevel@tonic-gate #ifdef PRESUNEUC 640*7c478bd9Sstevel@tonic-gate mbuf[tmp+1] = *ccursor++; 641*7c478bd9Sstevel@tonic-gate #else 642*7c478bd9Sstevel@tonic-gate ccursor += ((len > 0) ? len : 1); 643*7c478bd9Sstevel@tonic-gate #endif /* PRESUNEUC */ 644*7c478bd9Sstevel@tonic-gate /* 645*7c478bd9Sstevel@tonic-gate * If pointing to an alpha character, 646*7c478bd9Sstevel@tonic-gate * change the case. 647*7c478bd9Sstevel@tonic-gate */ 648*7c478bd9Sstevel@tonic-gate 649*7c478bd9Sstevel@tonic-gate tmp1 = mbuf[tmp+1]; 650*7c478bd9Sstevel@tonic-gate #ifdef PRESUNEUC 651*7c478bd9Sstevel@tonic-gate if (isupper((unsigned char)tmp1)) 652*7c478bd9Sstevel@tonic-gate mbuf[tmp+1] = tolower((unsigned char)tmp1); 653*7c478bd9Sstevel@tonic-gate else 654*7c478bd9Sstevel@tonic-gate mbuf[tmp+1] = toupper((unsigned char)tmp1); 655*7c478bd9Sstevel@tonic-gate #else 656*7c478bd9Sstevel@tonic-gate if (iswupper(wc)) 657*7c478bd9Sstevel@tonic-gate len = wctomb((char *)(mbuf + tmp + 1), 658*7c478bd9Sstevel@tonic-gate (wc = towlower(wc))); 659*7c478bd9Sstevel@tonic-gate else 660*7c478bd9Sstevel@tonic-gate len = wctomb((char *)(mbuf + tmp + 1), 661*7c478bd9Sstevel@tonic-gate (wc = towupper(wc))); 662*7c478bd9Sstevel@tonic-gate tmp += len - 1; 663*7c478bd9Sstevel@tonic-gate #endif /* PRESUNEUC */ 664*7c478bd9Sstevel@tonic-gate if(*ccursor) 665*7c478bd9Sstevel@tonic-gate /* 666*7c478bd9Sstevel@tonic-gate * If at end of line do not advance 667*7c478bd9Sstevel@tonic-gate * to the next character, else use a 668*7c478bd9Sstevel@tonic-gate * space to advance 1 column. 669*7c478bd9Sstevel@tonic-gate */ 670*7c478bd9Sstevel@tonic-gate mbuf[tmp+2] = ' '; 671*7c478bd9Sstevel@tonic-gate else { 672*7c478bd9Sstevel@tonic-gate mbuf[tmp+2] = '\0'; 673*7c478bd9Sstevel@tonic-gate tmp +=3; 674*7c478bd9Sstevel@tonic-gate break; 675*7c478bd9Sstevel@tonic-gate } 676*7c478bd9Sstevel@tonic-gate tmp += 3; 677*7c478bd9Sstevel@tonic-gate } 678*7c478bd9Sstevel@tonic-gate 679*7c478bd9Sstevel@tonic-gate mbuf[tmp] = 0; 680*7c478bd9Sstevel@tonic-gate macpush(mbuf, 1); 681*7c478bd9Sstevel@tonic-gate } 682*7c478bd9Sstevel@tonic-gate continue; 683*7c478bd9Sstevel@tonic-gate 684*7c478bd9Sstevel@tonic-gate 685*7c478bd9Sstevel@tonic-gate /* 686*7c478bd9Sstevel@tonic-gate * A Append at end of line, short for $a. 687*7c478bd9Sstevel@tonic-gate */ 688*7c478bd9Sstevel@tonic-gate case 'A': 689*7c478bd9Sstevel@tonic-gate operate('$', 1); 690*7c478bd9Sstevel@tonic-gate appnd: 691*7c478bd9Sstevel@tonic-gate c = 'a'; 692*7c478bd9Sstevel@tonic-gate /* fall into ... */ 693*7c478bd9Sstevel@tonic-gate 694*7c478bd9Sstevel@tonic-gate /* 695*7c478bd9Sstevel@tonic-gate * a Appends text after cursor. Text can continue 696*7c478bd9Sstevel@tonic-gate * through arbitrary number of lines. 697*7c478bd9Sstevel@tonic-gate */ 698*7c478bd9Sstevel@tonic-gate case 'a': 699*7c478bd9Sstevel@tonic-gate if (*cursor) { 700*7c478bd9Sstevel@tonic-gate wchar_t wchar; 701*7c478bd9Sstevel@tonic-gate int length = mbtowc(&wchar, (char *)cursor, MULTI_BYTE_MAX); 702*7c478bd9Sstevel@tonic-gate if (state == HARDOPEN) { 703*7c478bd9Sstevel@tonic-gate if(length < 0) { 704*7c478bd9Sstevel@tonic-gate putoctal = 1; 705*7c478bd9Sstevel@tonic-gate putchar(*cursor); 706*7c478bd9Sstevel@tonic-gate putoctal = 0; 707*7c478bd9Sstevel@tonic-gate } else 708*7c478bd9Sstevel@tonic-gate putchar(wchar); 709*7c478bd9Sstevel@tonic-gate } 710*7c478bd9Sstevel@tonic-gate if(length < 0) 711*7c478bd9Sstevel@tonic-gate cursor++; 712*7c478bd9Sstevel@tonic-gate else 713*7c478bd9Sstevel@tonic-gate cursor += length; 714*7c478bd9Sstevel@tonic-gate } 715*7c478bd9Sstevel@tonic-gate goto insrt; 716*7c478bd9Sstevel@tonic-gate 717*7c478bd9Sstevel@tonic-gate /* 718*7c478bd9Sstevel@tonic-gate * I Insert at beginning of whitespace of line, 719*7c478bd9Sstevel@tonic-gate * short for ^i. 720*7c478bd9Sstevel@tonic-gate */ 721*7c478bd9Sstevel@tonic-gate case 'I': 722*7c478bd9Sstevel@tonic-gate operate('^', 1); 723*7c478bd9Sstevel@tonic-gate c = 'i'; 724*7c478bd9Sstevel@tonic-gate /* fall into ... */ 725*7c478bd9Sstevel@tonic-gate 726*7c478bd9Sstevel@tonic-gate /* 727*7c478bd9Sstevel@tonic-gate * R Replace characters, one for one, by input 728*7c478bd9Sstevel@tonic-gate * (logically), like repeated r commands. 729*7c478bd9Sstevel@tonic-gate * 730*7c478bd9Sstevel@tonic-gate * BUG: This is like the typeover mode of many other 731*7c478bd9Sstevel@tonic-gate * editors, and is only rarely useful. Its 732*7c478bd9Sstevel@tonic-gate * implementation is a hack in a low level 733*7c478bd9Sstevel@tonic-gate * routine and it doesn't work very well, e.g. 734*7c478bd9Sstevel@tonic-gate * you can't move around within a R, etc. 735*7c478bd9Sstevel@tonic-gate */ 736*7c478bd9Sstevel@tonic-gate case 'R': 737*7c478bd9Sstevel@tonic-gate /* fall into... */ 738*7c478bd9Sstevel@tonic-gate 739*7c478bd9Sstevel@tonic-gate /* 740*7c478bd9Sstevel@tonic-gate * i Insert text to an escape in the buffer. 741*7c478bd9Sstevel@tonic-gate * Text is arbitrary. This command reminds of 742*7c478bd9Sstevel@tonic-gate * the i command in bare teco. 743*7c478bd9Sstevel@tonic-gate */ 744*7c478bd9Sstevel@tonic-gate case 'i': 745*7c478bd9Sstevel@tonic-gate insrt: 746*7c478bd9Sstevel@tonic-gate /* 747*7c478bd9Sstevel@tonic-gate * Common code for all the insertion commands. 748*7c478bd9Sstevel@tonic-gate * Save for redo, position cursor, prepare for append 749*7c478bd9Sstevel@tonic-gate * at command and in visual undo. Note that nothing 750*7c478bd9Sstevel@tonic-gate * is doomed, unless R when all is, and save the 751*7c478bd9Sstevel@tonic-gate * current line in a the undo temporary buffer. 752*7c478bd9Sstevel@tonic-gate */ 753*7c478bd9Sstevel@tonic-gate vmacchng(1); 754*7c478bd9Sstevel@tonic-gate setLAST(); 755*7c478bd9Sstevel@tonic-gate vcursat(cursor); 756*7c478bd9Sstevel@tonic-gate prepapp(); 757*7c478bd9Sstevel@tonic-gate vnoapp(); 758*7c478bd9Sstevel@tonic-gate doomed = c == 'R' ? 10000 : 0; 759*7c478bd9Sstevel@tonic-gate if(FIXUNDO) 760*7c478bd9Sstevel@tonic-gate vundkind = VCHNG; 761*7c478bd9Sstevel@tonic-gate vmoving = 0; 762*7c478bd9Sstevel@tonic-gate CP(vutmp, linebuf); 763*7c478bd9Sstevel@tonic-gate 764*7c478bd9Sstevel@tonic-gate /* 765*7c478bd9Sstevel@tonic-gate * If this is a repeated command, then suppress 766*7c478bd9Sstevel@tonic-gate * fake insert mode on dumb terminals which looks 767*7c478bd9Sstevel@tonic-gate * ridiculous and wastes lots of time even at 9600B. 768*7c478bd9Sstevel@tonic-gate */ 769*7c478bd9Sstevel@tonic-gate if (vglobp) 770*7c478bd9Sstevel@tonic-gate hold = HOLDQIK; 771*7c478bd9Sstevel@tonic-gate vappend(c, cnt, 0); 772*7c478bd9Sstevel@tonic-gate continue; 773*7c478bd9Sstevel@tonic-gate 774*7c478bd9Sstevel@tonic-gate /* 775*7c478bd9Sstevel@tonic-gate * An attention, normally a DEL, just beeps. 776*7c478bd9Sstevel@tonic-gate * If you are a vi command within ex, then 777*7c478bd9Sstevel@tonic-gate * two ATTN's will drop you back to command mode. 778*7c478bd9Sstevel@tonic-gate */ 779*7c478bd9Sstevel@tonic-gate case ATTN: 780*7c478bd9Sstevel@tonic-gate beep(); 781*7c478bd9Sstevel@tonic-gate if (initev || peekkey() != ATTN) 782*7c478bd9Sstevel@tonic-gate continue; 783*7c478bd9Sstevel@tonic-gate /* fall into... */ 784*7c478bd9Sstevel@tonic-gate 785*7c478bd9Sstevel@tonic-gate /* 786*7c478bd9Sstevel@tonic-gate * ^\ A quit always gets command mode. 787*7c478bd9Sstevel@tonic-gate */ 788*7c478bd9Sstevel@tonic-gate case QUIT: 789*7c478bd9Sstevel@tonic-gate /* 790*7c478bd9Sstevel@tonic-gate * Have to be careful if we were called 791*7c478bd9Sstevel@tonic-gate * g/xxx/vi 792*7c478bd9Sstevel@tonic-gate * since a return will just start up again. 793*7c478bd9Sstevel@tonic-gate * So we simulate an interrupt. 794*7c478bd9Sstevel@tonic-gate */ 795*7c478bd9Sstevel@tonic-gate if (inglobal) 796*7c478bd9Sstevel@tonic-gate onintr(0); 797*7c478bd9Sstevel@tonic-gate /* fall into... */ 798*7c478bd9Sstevel@tonic-gate 799*7c478bd9Sstevel@tonic-gate #ifdef notdef 800*7c478bd9Sstevel@tonic-gate /* 801*7c478bd9Sstevel@tonic-gate * q Quit back to command mode, unless called as 802*7c478bd9Sstevel@tonic-gate * vi on command line in which case dont do it 803*7c478bd9Sstevel@tonic-gate */ 804*7c478bd9Sstevel@tonic-gate case 'q': /* quit */ 805*7c478bd9Sstevel@tonic-gate if (initev) { 806*7c478bd9Sstevel@tonic-gate vsave(); 807*7c478bd9Sstevel@tonic-gate CATCH 808*7c478bd9Sstevel@tonic-gate error(gettext("Q gets ex command mode, :q leaves vi")); 809*7c478bd9Sstevel@tonic-gate ENDCATCH 810*7c478bd9Sstevel@tonic-gate splitw = 0; 811*7c478bd9Sstevel@tonic-gate getDOT(); 812*7c478bd9Sstevel@tonic-gate vrepaint(cursor); 813*7c478bd9Sstevel@tonic-gate continue; 814*7c478bd9Sstevel@tonic-gate } 815*7c478bd9Sstevel@tonic-gate #endif 816*7c478bd9Sstevel@tonic-gate /* fall into... */ 817*7c478bd9Sstevel@tonic-gate 818*7c478bd9Sstevel@tonic-gate /* 819*7c478bd9Sstevel@tonic-gate * Q Is like q, but always gets to command mode 820*7c478bd9Sstevel@tonic-gate * even if command line invocation was as vi. 821*7c478bd9Sstevel@tonic-gate */ 822*7c478bd9Sstevel@tonic-gate case 'Q': 823*7c478bd9Sstevel@tonic-gate vsave(); 824*7c478bd9Sstevel@tonic-gate /* 825*7c478bd9Sstevel@tonic-gate * If we are in the middle of a macro, throw away 826*7c478bd9Sstevel@tonic-gate * the rest and fix up undo. 827*7c478bd9Sstevel@tonic-gate * This code copied from getbr(). 828*7c478bd9Sstevel@tonic-gate */ 829*7c478bd9Sstevel@tonic-gate if (vmacp) { 830*7c478bd9Sstevel@tonic-gate vmacp = 0; 831*7c478bd9Sstevel@tonic-gate if (inopen == -1) /* don't mess up undo for esc esc */ 832*7c478bd9Sstevel@tonic-gate vundkind = VMANY; 833*7c478bd9Sstevel@tonic-gate inopen = 1; /* restore old setting now that macro done */ 834*7c478bd9Sstevel@tonic-gate } 835*7c478bd9Sstevel@tonic-gate ixlatctl(1); 836*7c478bd9Sstevel@tonic-gate return; 837*7c478bd9Sstevel@tonic-gate 838*7c478bd9Sstevel@tonic-gate 839*7c478bd9Sstevel@tonic-gate /* 840*7c478bd9Sstevel@tonic-gate * ZZ Like :x 841*7c478bd9Sstevel@tonic-gate */ 842*7c478bd9Sstevel@tonic-gate case 'Z': 843*7c478bd9Sstevel@tonic-gate forbid(getkey() != 'Z'); 844*7c478bd9Sstevel@tonic-gate oglobp = globp; 845*7c478bd9Sstevel@tonic-gate globp = (unsigned char *)"x"; 846*7c478bd9Sstevel@tonic-gate vclrech(0); 847*7c478bd9Sstevel@tonic-gate goto gogo; 848*7c478bd9Sstevel@tonic-gate 849*7c478bd9Sstevel@tonic-gate /* 850*7c478bd9Sstevel@tonic-gate * P Put back text before cursor or before current 851*7c478bd9Sstevel@tonic-gate * line. If text was whole lines goes back 852*7c478bd9Sstevel@tonic-gate * as whole lines. If part of a single line 853*7c478bd9Sstevel@tonic-gate * or parts of whole lines splits up current 854*7c478bd9Sstevel@tonic-gate * line to form many new lines. 855*7c478bd9Sstevel@tonic-gate * May specify a named buffer, or the delete 856*7c478bd9Sstevel@tonic-gate * saving buffers 1-9. 857*7c478bd9Sstevel@tonic-gate * 858*7c478bd9Sstevel@tonic-gate * p Like P but after rather than before. 859*7c478bd9Sstevel@tonic-gate */ 860*7c478bd9Sstevel@tonic-gate case 'P': 861*7c478bd9Sstevel@tonic-gate case 'p': 862*7c478bd9Sstevel@tonic-gate vmoving = 0; 863*7c478bd9Sstevel@tonic-gate #ifdef XPG4 864*7c478bd9Sstevel@tonic-gate P_cursor_offset = 0; 865*7c478bd9Sstevel@tonic-gate #endif 866*7c478bd9Sstevel@tonic-gate #ifdef notdef 867*7c478bd9Sstevel@tonic-gate forbid (!vreg && value(vi_UNDOMACRO) && inopen < 0); 868*7c478bd9Sstevel@tonic-gate #endif 869*7c478bd9Sstevel@tonic-gate /* 870*7c478bd9Sstevel@tonic-gate * If previous delete was partial line, use an 871*7c478bd9Sstevel@tonic-gate * append or insert to put it back so as to 872*7c478bd9Sstevel@tonic-gate * use insert mode on intelligent terminals. 873*7c478bd9Sstevel@tonic-gate */ 874*7c478bd9Sstevel@tonic-gate if (!vreg && DEL[0]) { 875*7c478bd9Sstevel@tonic-gate setLAST(); 876*7c478bd9Sstevel@tonic-gate forbid ((unsigned char)DEL[128] == 0200); 877*7c478bd9Sstevel@tonic-gate vglobp = DEL; 878*7c478bd9Sstevel@tonic-gate ungetkey(c == 'p' ? 'a' : 'i'); 879*7c478bd9Sstevel@tonic-gate goto reread; 880*7c478bd9Sstevel@tonic-gate } 881*7c478bd9Sstevel@tonic-gate 882*7c478bd9Sstevel@tonic-gate /* 883*7c478bd9Sstevel@tonic-gate * If a register wasn't specified, then make 884*7c478bd9Sstevel@tonic-gate * sure there is something to put back. 885*7c478bd9Sstevel@tonic-gate */ 886*7c478bd9Sstevel@tonic-gate forbid (!vreg && unddol == dol); 887*7c478bd9Sstevel@tonic-gate /* 888*7c478bd9Sstevel@tonic-gate * If we just did a macro the whole buffer is in 889*7c478bd9Sstevel@tonic-gate * the undo save area. We don't want to put THAT. 890*7c478bd9Sstevel@tonic-gate */ 891*7c478bd9Sstevel@tonic-gate forbid (vundkind == VMANY && undkind==UNDALL); 892*7c478bd9Sstevel@tonic-gate vsave(); 893*7c478bd9Sstevel@tonic-gate vmacchng(1); 894*7c478bd9Sstevel@tonic-gate setLAST(); 895*7c478bd9Sstevel@tonic-gate i = 0; 896*7c478bd9Sstevel@tonic-gate if (vreg && partreg(vreg) || !vreg && pkill[0]) { 897*7c478bd9Sstevel@tonic-gate /* 898*7c478bd9Sstevel@tonic-gate * Restoring multiple lines which were partial 899*7c478bd9Sstevel@tonic-gate * lines; will leave cursor in middle 900*7c478bd9Sstevel@tonic-gate * of line after shoving restored text in to 901*7c478bd9Sstevel@tonic-gate * split the current line. 902*7c478bd9Sstevel@tonic-gate */ 903*7c478bd9Sstevel@tonic-gate i++; 904*7c478bd9Sstevel@tonic-gate if (c == 'p' && *cursor) 905*7c478bd9Sstevel@tonic-gate cursor = nextchr(cursor); 906*7c478bd9Sstevel@tonic-gate } else { 907*7c478bd9Sstevel@tonic-gate /* 908*7c478bd9Sstevel@tonic-gate * In whole line case, have to back up dot 909*7c478bd9Sstevel@tonic-gate * for P; also want to clear cursor so 910*7c478bd9Sstevel@tonic-gate * cursor will eventually be positioned 911*7c478bd9Sstevel@tonic-gate * at the beginning of the first put line. 912*7c478bd9Sstevel@tonic-gate */ 913*7c478bd9Sstevel@tonic-gate cursor = 0; 914*7c478bd9Sstevel@tonic-gate if (c == 'P') { 915*7c478bd9Sstevel@tonic-gate dot--, vcline--; 916*7c478bd9Sstevel@tonic-gate c = 'p'; 917*7c478bd9Sstevel@tonic-gate } 918*7c478bd9Sstevel@tonic-gate } 919*7c478bd9Sstevel@tonic-gate killU(); 920*7c478bd9Sstevel@tonic-gate 921*7c478bd9Sstevel@tonic-gate /* 922*7c478bd9Sstevel@tonic-gate * The call to putreg can potentially 923*7c478bd9Sstevel@tonic-gate * bomb since there may be nothing in a named buffer. 924*7c478bd9Sstevel@tonic-gate * We thus put a catch in here. If we didn't and 925*7c478bd9Sstevel@tonic-gate * there was an error we would end up in command mode. 926*7c478bd9Sstevel@tonic-gate */ 927*7c478bd9Sstevel@tonic-gate addr = dol; /* old dol */ 928*7c478bd9Sstevel@tonic-gate CATCH 929*7c478bd9Sstevel@tonic-gate vremote(1, vreg ? putreg : put, vreg); 930*7c478bd9Sstevel@tonic-gate ONERR 931*7c478bd9Sstevel@tonic-gate if (vreg == -1) { 932*7c478bd9Sstevel@tonic-gate splitw = 0; 933*7c478bd9Sstevel@tonic-gate if (op == 'P') 934*7c478bd9Sstevel@tonic-gate dot++, vcline++; 935*7c478bd9Sstevel@tonic-gate goto pfixup; 936*7c478bd9Sstevel@tonic-gate } 937*7c478bd9Sstevel@tonic-gate ENDCATCH 938*7c478bd9Sstevel@tonic-gate splitw = 0; 939*7c478bd9Sstevel@tonic-gate nlput = dol - addr + 1; 940*7c478bd9Sstevel@tonic-gate if (!i) { 941*7c478bd9Sstevel@tonic-gate /* 942*7c478bd9Sstevel@tonic-gate * Increment undap1, undap2 to make up 943*7c478bd9Sstevel@tonic-gate * for their incorrect initialization in the 944*7c478bd9Sstevel@tonic-gate * routine vremote before calling put/putreg. 945*7c478bd9Sstevel@tonic-gate */ 946*7c478bd9Sstevel@tonic-gate if (FIXUNDO) 947*7c478bd9Sstevel@tonic-gate undap1++, undap2++; 948*7c478bd9Sstevel@tonic-gate vcline++; 949*7c478bd9Sstevel@tonic-gate nlput--; 950*7c478bd9Sstevel@tonic-gate 951*7c478bd9Sstevel@tonic-gate /* 952*7c478bd9Sstevel@tonic-gate * After a put want current line first line, 953*7c478bd9Sstevel@tonic-gate * and dot was made the last line put in code 954*7c478bd9Sstevel@tonic-gate * run so far. This is why we increment vcline 955*7c478bd9Sstevel@tonic-gate * above and decrease dot here. 956*7c478bd9Sstevel@tonic-gate */ 957*7c478bd9Sstevel@tonic-gate dot -= nlput - 1; 958*7c478bd9Sstevel@tonic-gate } 959*7c478bd9Sstevel@tonic-gate #ifdef TRACE 960*7c478bd9Sstevel@tonic-gate if (trace) 961*7c478bd9Sstevel@tonic-gate fprintf(trace, "vreplace(%d, %d, %d), undap1=%d, undap2=%d, dot=%d\n", vcline, i, nlput, lineno(undap1), lineno(undap2), lineno(dot)); 962*7c478bd9Sstevel@tonic-gate #endif 963*7c478bd9Sstevel@tonic-gate vreplace(vcline, i, nlput); 964*7c478bd9Sstevel@tonic-gate #ifdef XPG4 965*7c478bd9Sstevel@tonic-gate if (op == 'P' && i > 0) { 966*7c478bd9Sstevel@tonic-gate dot += nlput - 1; 967*7c478bd9Sstevel@tonic-gate vcline += nlput - 1; 968*7c478bd9Sstevel@tonic-gate cursor += P_cursor_offset; 969*7c478bd9Sstevel@tonic-gate } 970*7c478bd9Sstevel@tonic-gate #endif 971*7c478bd9Sstevel@tonic-gate if (state != VISUAL) { 972*7c478bd9Sstevel@tonic-gate /* 973*7c478bd9Sstevel@tonic-gate * Special case in open mode. 974*7c478bd9Sstevel@tonic-gate * Force action on the screen when a single 975*7c478bd9Sstevel@tonic-gate * line is put even if it is identical to 976*7c478bd9Sstevel@tonic-gate * the current line, e.g. on YP; otherwise 977*7c478bd9Sstevel@tonic-gate * you can't tell anything happened. 978*7c478bd9Sstevel@tonic-gate */ 979*7c478bd9Sstevel@tonic-gate vjumpto(dot, cursor, '.'); 980*7c478bd9Sstevel@tonic-gate continue; 981*7c478bd9Sstevel@tonic-gate } 982*7c478bd9Sstevel@tonic-gate pfixup: 983*7c478bd9Sstevel@tonic-gate vrepaint(cursor); 984*7c478bd9Sstevel@tonic-gate vfixcurs(); 985*7c478bd9Sstevel@tonic-gate continue; 986*7c478bd9Sstevel@tonic-gate 987*7c478bd9Sstevel@tonic-gate /* 988*7c478bd9Sstevel@tonic-gate * ^^ Return to previous file. 989*7c478bd9Sstevel@tonic-gate * Like a :e #, and thus can be used after a 990*7c478bd9Sstevel@tonic-gate * "No Write" diagnostic. 991*7c478bd9Sstevel@tonic-gate */ 992*7c478bd9Sstevel@tonic-gate case CTRL('^'): 993*7c478bd9Sstevel@tonic-gate forbid (hadcnt); 994*7c478bd9Sstevel@tonic-gate vsave(); 995*7c478bd9Sstevel@tonic-gate ckaw(); 996*7c478bd9Sstevel@tonic-gate oglobp = globp; 997*7c478bd9Sstevel@tonic-gate if (value(vi_AUTOWRITE) && !value(vi_READONLY)) 998*7c478bd9Sstevel@tonic-gate globp = (unsigned char *)"e! #"; 999*7c478bd9Sstevel@tonic-gate else 1000*7c478bd9Sstevel@tonic-gate globp = (unsigned char *)"e #"; 1001*7c478bd9Sstevel@tonic-gate goto gogo; 1002*7c478bd9Sstevel@tonic-gate 1003*7c478bd9Sstevel@tonic-gate #ifdef TAG_STACK 1004*7c478bd9Sstevel@tonic-gate /* 1005*7c478bd9Sstevel@tonic-gate * ^T Pop the tag stack if enabled or else reset it 1006*7c478bd9Sstevel@tonic-gate * if not. 1007*7c478bd9Sstevel@tonic-gate */ 1008*7c478bd9Sstevel@tonic-gate case CTRL('t'): 1009*7c478bd9Sstevel@tonic-gate forbid (hadcnt); 1010*7c478bd9Sstevel@tonic-gate vsave(); 1011*7c478bd9Sstevel@tonic-gate oglobp = globp; 1012*7c478bd9Sstevel@tonic-gate globp = (unsigned char *) "pop"; 1013*7c478bd9Sstevel@tonic-gate goto gogo; 1014*7c478bd9Sstevel@tonic-gate #endif 1015*7c478bd9Sstevel@tonic-gate /* 1016*7c478bd9Sstevel@tonic-gate * ^] Takes word after cursor as tag, and then does 1017*7c478bd9Sstevel@tonic-gate * tag command. Read ``go right to''. 1018*7c478bd9Sstevel@tonic-gate * This is not a search, so the wrapscan setting 1019*7c478bd9Sstevel@tonic-gate * must be ignored. If set, then it is unset 1020*7c478bd9Sstevel@tonic-gate * here and restored later. 1021*7c478bd9Sstevel@tonic-gate */ 1022*7c478bd9Sstevel@tonic-gate case CTRL(']'): 1023*7c478bd9Sstevel@tonic-gate grabtag(); 1024*7c478bd9Sstevel@tonic-gate oglobp = globp; 1025*7c478bd9Sstevel@tonic-gate if (value(vi_WRAPSCAN) == 0) { 1026*7c478bd9Sstevel@tonic-gate tag_reset_wrap = 1; 1027*7c478bd9Sstevel@tonic-gate value(vi_WRAPSCAN) = 1; 1028*7c478bd9Sstevel@tonic-gate } 1029*7c478bd9Sstevel@tonic-gate globp = (unsigned char *)"tag"; 1030*7c478bd9Sstevel@tonic-gate goto gogo; 1031*7c478bd9Sstevel@tonic-gate 1032*7c478bd9Sstevel@tonic-gate /* 1033*7c478bd9Sstevel@tonic-gate * & Like :& 1034*7c478bd9Sstevel@tonic-gate */ 1035*7c478bd9Sstevel@tonic-gate case '&': 1036*7c478bd9Sstevel@tonic-gate oglobp = globp; 1037*7c478bd9Sstevel@tonic-gate globp = (unsigned char *)"&"; 1038*7c478bd9Sstevel@tonic-gate goto gogo; 1039*7c478bd9Sstevel@tonic-gate 1040*7c478bd9Sstevel@tonic-gate /* 1041*7c478bd9Sstevel@tonic-gate * ^G Bring up a status line at the bottom of 1042*7c478bd9Sstevel@tonic-gate * the screen, like a :file command. 1043*7c478bd9Sstevel@tonic-gate * 1044*7c478bd9Sstevel@tonic-gate * BUG: Was ^S but doesn't work in cbreak mode 1045*7c478bd9Sstevel@tonic-gate */ 1046*7c478bd9Sstevel@tonic-gate case CTRL('g'): 1047*7c478bd9Sstevel@tonic-gate oglobp = globp; 1048*7c478bd9Sstevel@tonic-gate globp = (unsigned char *)"file"; 1049*7c478bd9Sstevel@tonic-gate gogo: 1050*7c478bd9Sstevel@tonic-gate addr = dot; 1051*7c478bd9Sstevel@tonic-gate vsave(); 1052*7c478bd9Sstevel@tonic-gate goto doinit; 1053*7c478bd9Sstevel@tonic-gate 1054*7c478bd9Sstevel@tonic-gate #ifdef SIGTSTP 1055*7c478bd9Sstevel@tonic-gate /* 1056*7c478bd9Sstevel@tonic-gate * ^Z: suspend editor session and temporarily return 1057*7c478bd9Sstevel@tonic-gate * to shell. Only works with Berkeley/IIASA process 1058*7c478bd9Sstevel@tonic-gate * control in kernel. 1059*7c478bd9Sstevel@tonic-gate */ 1060*7c478bd9Sstevel@tonic-gate case CTRL('z'): 1061*7c478bd9Sstevel@tonic-gate forbid(dosusp == 0); 1062*7c478bd9Sstevel@tonic-gate vsave(); 1063*7c478bd9Sstevel@tonic-gate oglobp = globp; 1064*7c478bd9Sstevel@tonic-gate globp = (unsigned char *)"stop"; 1065*7c478bd9Sstevel@tonic-gate goto gogo; 1066*7c478bd9Sstevel@tonic-gate #endif 1067*7c478bd9Sstevel@tonic-gate 1068*7c478bd9Sstevel@tonic-gate /* 1069*7c478bd9Sstevel@tonic-gate * : Read a command from the echo area and 1070*7c478bd9Sstevel@tonic-gate * execute it in command mode. 1071*7c478bd9Sstevel@tonic-gate */ 1072*7c478bd9Sstevel@tonic-gate case ':': 1073*7c478bd9Sstevel@tonic-gate forbid (hadcnt); 1074*7c478bd9Sstevel@tonic-gate vsave(); 1075*7c478bd9Sstevel@tonic-gate i = tchng; 1076*7c478bd9Sstevel@tonic-gate addr = dot; 1077*7c478bd9Sstevel@tonic-gate if (readecho(c)) { 1078*7c478bd9Sstevel@tonic-gate esave[0] = 0; 1079*7c478bd9Sstevel@tonic-gate goto fixup; 1080*7c478bd9Sstevel@tonic-gate } 1081*7c478bd9Sstevel@tonic-gate getDOT(); 1082*7c478bd9Sstevel@tonic-gate /* 1083*7c478bd9Sstevel@tonic-gate * Use the visual undo buffer to store the global 1084*7c478bd9Sstevel@tonic-gate * string for command mode, since it is idle right now. 1085*7c478bd9Sstevel@tonic-gate */ 1086*7c478bd9Sstevel@tonic-gate oglobp = globp; strcpy(vutmp, genbuf+1); globp = vutmp; 1087*7c478bd9Sstevel@tonic-gate doinit: 1088*7c478bd9Sstevel@tonic-gate esave[0] = 0; 1089*7c478bd9Sstevel@tonic-gate fixech(); 1090*7c478bd9Sstevel@tonic-gate 1091*7c478bd9Sstevel@tonic-gate /* 1092*7c478bd9Sstevel@tonic-gate * Have to finagle around not to lose last 1093*7c478bd9Sstevel@tonic-gate * character after this command (when run from ex 1094*7c478bd9Sstevel@tonic-gate * command mode). This is clumsy. 1095*7c478bd9Sstevel@tonic-gate */ 1096*7c478bd9Sstevel@tonic-gate d = peekc; ungetchar(0); 1097*7c478bd9Sstevel@tonic-gate if (shouldpo) { 1098*7c478bd9Sstevel@tonic-gate /* 1099*7c478bd9Sstevel@tonic-gate * So after a "Hit return..." ":", we do 1100*7c478bd9Sstevel@tonic-gate * another "Hit return..." the next time 1101*7c478bd9Sstevel@tonic-gate */ 1102*7c478bd9Sstevel@tonic-gate pofix(); 1103*7c478bd9Sstevel@tonic-gate shouldpo = 0; 1104*7c478bd9Sstevel@tonic-gate } 1105*7c478bd9Sstevel@tonic-gate CATCH 1106*7c478bd9Sstevel@tonic-gate /* 1107*7c478bd9Sstevel@tonic-gate * Save old values of options so we can 1108*7c478bd9Sstevel@tonic-gate * notice when they change; switch into 1109*7c478bd9Sstevel@tonic-gate * cooked mode so we are interruptible. 1110*7c478bd9Sstevel@tonic-gate */ 1111*7c478bd9Sstevel@tonic-gate onumber = value(vi_NUMBER); 1112*7c478bd9Sstevel@tonic-gate olist = value(vi_LIST); 1113*7c478bd9Sstevel@tonic-gate OPline = Pline; 1114*7c478bd9Sstevel@tonic-gate OPutchar = Putchar; 1115*7c478bd9Sstevel@tonic-gate #ifndef CBREAK 1116*7c478bd9Sstevel@tonic-gate vcook(); 1117*7c478bd9Sstevel@tonic-gate #endif 1118*7c478bd9Sstevel@tonic-gate commands(1, 1); 1119*7c478bd9Sstevel@tonic-gate if (dot == zero && dol > zero) 1120*7c478bd9Sstevel@tonic-gate dot = one; 1121*7c478bd9Sstevel@tonic-gate #ifndef CBREAK 1122*7c478bd9Sstevel@tonic-gate vraw(); 1123*7c478bd9Sstevel@tonic-gate #endif 1124*7c478bd9Sstevel@tonic-gate ONERR 1125*7c478bd9Sstevel@tonic-gate #ifndef CBREAK 1126*7c478bd9Sstevel@tonic-gate vraw(); 1127*7c478bd9Sstevel@tonic-gate #endif 1128*7c478bd9Sstevel@tonic-gate copy(esave, vtube[WECHO], TUBECOLS * sizeof(wchar_t)); 1129*7c478bd9Sstevel@tonic-gate ENDCATCH 1130*7c478bd9Sstevel@tonic-gate fixol(); 1131*7c478bd9Sstevel@tonic-gate Pline = OPline; 1132*7c478bd9Sstevel@tonic-gate Putchar = OPutchar; 1133*7c478bd9Sstevel@tonic-gate ungetchar(d); 1134*7c478bd9Sstevel@tonic-gate globp = oglobp; 1135*7c478bd9Sstevel@tonic-gate 1136*7c478bd9Sstevel@tonic-gate /* 1137*7c478bd9Sstevel@tonic-gate * If we ended up with no lines in the buffer, make 1138*7c478bd9Sstevel@tonic-gate * a line. 1139*7c478bd9Sstevel@tonic-gate */ 1140*7c478bd9Sstevel@tonic-gate if (dot == zero) { 1141*7c478bd9Sstevel@tonic-gate fixzero(); 1142*7c478bd9Sstevel@tonic-gate } 1143*7c478bd9Sstevel@tonic-gate splitw = 0; 1144*7c478bd9Sstevel@tonic-gate 1145*7c478bd9Sstevel@tonic-gate /* 1146*7c478bd9Sstevel@tonic-gate * Special case: did list/number options change? 1147*7c478bd9Sstevel@tonic-gate */ 1148*7c478bd9Sstevel@tonic-gate if (onumber != value(vi_NUMBER)) 1149*7c478bd9Sstevel@tonic-gate setnumb(value(vi_NUMBER)); 1150*7c478bd9Sstevel@tonic-gate if (olist != value(vi_LIST)) 1151*7c478bd9Sstevel@tonic-gate setlist(value(vi_LIST)); 1152*7c478bd9Sstevel@tonic-gate 1153*7c478bd9Sstevel@tonic-gate fixup: 1154*7c478bd9Sstevel@tonic-gate /* 1155*7c478bd9Sstevel@tonic-gate * If a change occurred, other than 1156*7c478bd9Sstevel@tonic-gate * a write which clears changes, then 1157*7c478bd9Sstevel@tonic-gate * we should allow an undo even if . 1158*7c478bd9Sstevel@tonic-gate * didn't move. 1159*7c478bd9Sstevel@tonic-gate * 1160*7c478bd9Sstevel@tonic-gate * BUG: You can make this wrong by 1161*7c478bd9Sstevel@tonic-gate * tricking around with multiple commands 1162*7c478bd9Sstevel@tonic-gate * on one line of : escape, and including 1163*7c478bd9Sstevel@tonic-gate * a write command there, but it's not 1164*7c478bd9Sstevel@tonic-gate * worth worrying about. 1165*7c478bd9Sstevel@tonic-gate */ 1166*7c478bd9Sstevel@tonic-gate if (FIXUNDO && tchng && tchng != i) 1167*7c478bd9Sstevel@tonic-gate vundkind = VMANY, cursor = 0; 1168*7c478bd9Sstevel@tonic-gate 1169*7c478bd9Sstevel@tonic-gate /* 1170*7c478bd9Sstevel@tonic-gate * If we are about to do another :, hold off 1171*7c478bd9Sstevel@tonic-gate * updating of screen. 1172*7c478bd9Sstevel@tonic-gate */ 1173*7c478bd9Sstevel@tonic-gate if (vcnt < 0 && Peekkey == ':') { 1174*7c478bd9Sstevel@tonic-gate getDOT(); 1175*7c478bd9Sstevel@tonic-gate shouldpo = 1; 1176*7c478bd9Sstevel@tonic-gate continue; 1177*7c478bd9Sstevel@tonic-gate } 1178*7c478bd9Sstevel@tonic-gate shouldpo = 0; 1179*7c478bd9Sstevel@tonic-gate 1180*7c478bd9Sstevel@tonic-gate /* 1181*7c478bd9Sstevel@tonic-gate * In the case where the file being edited is 1182*7c478bd9Sstevel@tonic-gate * new; e.g. if the initial state hasn't been 1183*7c478bd9Sstevel@tonic-gate * saved yet, then do so now. 1184*7c478bd9Sstevel@tonic-gate */ 1185*7c478bd9Sstevel@tonic-gate if (unddol == truedol) { 1186*7c478bd9Sstevel@tonic-gate vundkind = VNONE; 1187*7c478bd9Sstevel@tonic-gate Vlines = lineDOL(); 1188*7c478bd9Sstevel@tonic-gate if (!inglobal) 1189*7c478bd9Sstevel@tonic-gate savevis(); 1190*7c478bd9Sstevel@tonic-gate addr = zero; 1191*7c478bd9Sstevel@tonic-gate vcnt = 0; 1192*7c478bd9Sstevel@tonic-gate if (esave[0] == 0) 1193*7c478bd9Sstevel@tonic-gate copy(esave, vtube[WECHO], TUBECOLS * sizeof(wchar_t)); 1194*7c478bd9Sstevel@tonic-gate } 1195*7c478bd9Sstevel@tonic-gate 1196*7c478bd9Sstevel@tonic-gate /* 1197*7c478bd9Sstevel@tonic-gate * If the current line moved reset the cursor position. 1198*7c478bd9Sstevel@tonic-gate */ 1199*7c478bd9Sstevel@tonic-gate if (dot != addr) { 1200*7c478bd9Sstevel@tonic-gate vmoving = 0; 1201*7c478bd9Sstevel@tonic-gate cursor = 0; 1202*7c478bd9Sstevel@tonic-gate } 1203*7c478bd9Sstevel@tonic-gate 1204*7c478bd9Sstevel@tonic-gate /* 1205*7c478bd9Sstevel@tonic-gate * If current line is not on screen or if we are 1206*7c478bd9Sstevel@tonic-gate * in open mode and . moved, then redraw. 1207*7c478bd9Sstevel@tonic-gate */ 1208*7c478bd9Sstevel@tonic-gate i = vcline + (dot - addr); 1209*7c478bd9Sstevel@tonic-gate if(windowchg) 1210*7c478bd9Sstevel@tonic-gate windowinit(); 1211*7c478bd9Sstevel@tonic-gate if (i < 0 || i >= vcnt && i >= -vcnt || state != VISUAL && dot != addr) { 1212*7c478bd9Sstevel@tonic-gate if (state == CRTOPEN) 1213*7c478bd9Sstevel@tonic-gate vup1(); 1214*7c478bd9Sstevel@tonic-gate if (vcnt > 0) 1215*7c478bd9Sstevel@tonic-gate vcnt = 0; 1216*7c478bd9Sstevel@tonic-gate vjumpto(dot, (char *) 0, '.'); 1217*7c478bd9Sstevel@tonic-gate } else { 1218*7c478bd9Sstevel@tonic-gate /* 1219*7c478bd9Sstevel@tonic-gate * Current line IS on screen. 1220*7c478bd9Sstevel@tonic-gate * If we did a [Hit return...] then 1221*7c478bd9Sstevel@tonic-gate * restore vcnt and clear screen if in visual 1222*7c478bd9Sstevel@tonic-gate */ 1223*7c478bd9Sstevel@tonic-gate vcline = i; 1224*7c478bd9Sstevel@tonic-gate if (vcnt < 0) { 1225*7c478bd9Sstevel@tonic-gate vcnt = -vcnt; 1226*7c478bd9Sstevel@tonic-gate if (state == VISUAL) 1227*7c478bd9Sstevel@tonic-gate vclear(); 1228*7c478bd9Sstevel@tonic-gate else if (state == CRTOPEN) { 1229*7c478bd9Sstevel@tonic-gate vcnt = 0; 1230*7c478bd9Sstevel@tonic-gate } 1231*7c478bd9Sstevel@tonic-gate } 1232*7c478bd9Sstevel@tonic-gate 1233*7c478bd9Sstevel@tonic-gate /* 1234*7c478bd9Sstevel@tonic-gate * Limit max value of vcnt based on $ 1235*7c478bd9Sstevel@tonic-gate */ 1236*7c478bd9Sstevel@tonic-gate i = vcline + lineDOL() - lineDOT() + 1; 1237*7c478bd9Sstevel@tonic-gate if (i < vcnt) 1238*7c478bd9Sstevel@tonic-gate vcnt = i; 1239*7c478bd9Sstevel@tonic-gate 1240*7c478bd9Sstevel@tonic-gate /* 1241*7c478bd9Sstevel@tonic-gate * Dirty and repaint. 1242*7c478bd9Sstevel@tonic-gate */ 1243*7c478bd9Sstevel@tonic-gate vdirty(0, lines); 1244*7c478bd9Sstevel@tonic-gate vrepaint(cursor); 1245*7c478bd9Sstevel@tonic-gate } 1246*7c478bd9Sstevel@tonic-gate 1247*7c478bd9Sstevel@tonic-gate /* 1248*7c478bd9Sstevel@tonic-gate * If in visual, put back the echo area 1249*7c478bd9Sstevel@tonic-gate * if it was clobbered. 1250*7c478bd9Sstevel@tonic-gate */ 1251*7c478bd9Sstevel@tonic-gate if (state == VISUAL) { 1252*7c478bd9Sstevel@tonic-gate int sdc = destcol, sdl = destline; 1253*7c478bd9Sstevel@tonic-gate 1254*7c478bd9Sstevel@tonic-gate splitw++; 1255*7c478bd9Sstevel@tonic-gate vigoto(WECHO, 0); 1256*7c478bd9Sstevel@tonic-gate for (i = 0; i < TUBECOLS - 1; i++) { 1257*7c478bd9Sstevel@tonic-gate if (esave[i] == 0) 1258*7c478bd9Sstevel@tonic-gate break; 1259*7c478bd9Sstevel@tonic-gate if(esave[i] != FILLER) 1260*7c478bd9Sstevel@tonic-gate vputchar(esave[i]); 1261*7c478bd9Sstevel@tonic-gate } 1262*7c478bd9Sstevel@tonic-gate splitw = 0; 1263*7c478bd9Sstevel@tonic-gate vgoto(sdl, sdc); 1264*7c478bd9Sstevel@tonic-gate } 1265*7c478bd9Sstevel@tonic-gate if (tag_reset_wrap == 1) { 1266*7c478bd9Sstevel@tonic-gate tag_reset_wrap = 0; 1267*7c478bd9Sstevel@tonic-gate value(vi_WRAPSCAN) = 0; 1268*7c478bd9Sstevel@tonic-gate } 1269*7c478bd9Sstevel@tonic-gate continue; 1270*7c478bd9Sstevel@tonic-gate 1271*7c478bd9Sstevel@tonic-gate /* 1272*7c478bd9Sstevel@tonic-gate * u undo the last changing command. 1273*7c478bd9Sstevel@tonic-gate */ 1274*7c478bd9Sstevel@tonic-gate case 'u': 1275*7c478bd9Sstevel@tonic-gate vundo(1); 1276*7c478bd9Sstevel@tonic-gate continue; 1277*7c478bd9Sstevel@tonic-gate 1278*7c478bd9Sstevel@tonic-gate /* 1279*7c478bd9Sstevel@tonic-gate * U restore current line to initial state. 1280*7c478bd9Sstevel@tonic-gate */ 1281*7c478bd9Sstevel@tonic-gate case 'U': 1282*7c478bd9Sstevel@tonic-gate vUndo(); 1283*7c478bd9Sstevel@tonic-gate continue; 1284*7c478bd9Sstevel@tonic-gate 1285*7c478bd9Sstevel@tonic-gate fonfon: 1286*7c478bd9Sstevel@tonic-gate beep(); 1287*7c478bd9Sstevel@tonic-gate vmacp = 0; 1288*7c478bd9Sstevel@tonic-gate inopen = 1; /* might have been -1 */ 1289*7c478bd9Sstevel@tonic-gate continue; 1290*7c478bd9Sstevel@tonic-gate } 1291*7c478bd9Sstevel@tonic-gate 1292*7c478bd9Sstevel@tonic-gate /* 1293*7c478bd9Sstevel@tonic-gate * Rest of commands are decoded by the operate 1294*7c478bd9Sstevel@tonic-gate * routine. 1295*7c478bd9Sstevel@tonic-gate */ 1296*7c478bd9Sstevel@tonic-gate operate(c, cnt); 1297*7c478bd9Sstevel@tonic-gate } 1298*7c478bd9Sstevel@tonic-gate } 1299*7c478bd9Sstevel@tonic-gate 1300*7c478bd9Sstevel@tonic-gate /* 1301*7c478bd9Sstevel@tonic-gate * Grab the word after the cursor so we can look for it as a tag. 1302*7c478bd9Sstevel@tonic-gate */ 1303*7c478bd9Sstevel@tonic-gate grabtag() 1304*7c478bd9Sstevel@tonic-gate { 1305*7c478bd9Sstevel@tonic-gate register unsigned char *cp, *dp; 1306*7c478bd9Sstevel@tonic-gate 1307*7c478bd9Sstevel@tonic-gate cp = vpastwh(cursor); 1308*7c478bd9Sstevel@tonic-gate if (*cp) { 1309*7c478bd9Sstevel@tonic-gate dp = lasttag; 1310*7c478bd9Sstevel@tonic-gate do { 1311*7c478bd9Sstevel@tonic-gate if (dp < &lasttag[sizeof lasttag - 2]) 1312*7c478bd9Sstevel@tonic-gate *dp++ = *cp; 1313*7c478bd9Sstevel@tonic-gate cp++; 1314*7c478bd9Sstevel@tonic-gate /* only allow ascii alphabetics */ 1315*7c478bd9Sstevel@tonic-gate } while ((isascii(*cp) && isalpha(*cp)) || isdigit(*cp) || *cp == '_'); 1316*7c478bd9Sstevel@tonic-gate *dp++ = 0; 1317*7c478bd9Sstevel@tonic-gate } 1318*7c478bd9Sstevel@tonic-gate } 1319*7c478bd9Sstevel@tonic-gate 1320*7c478bd9Sstevel@tonic-gate /* 1321*7c478bd9Sstevel@tonic-gate * Before appending lines, set up addr1 and 1322*7c478bd9Sstevel@tonic-gate * the command mode undo information. 1323*7c478bd9Sstevel@tonic-gate */ 1324*7c478bd9Sstevel@tonic-gate prepapp() 1325*7c478bd9Sstevel@tonic-gate { 1326*7c478bd9Sstevel@tonic-gate 1327*7c478bd9Sstevel@tonic-gate addr1 = dot; 1328*7c478bd9Sstevel@tonic-gate deletenone(); 1329*7c478bd9Sstevel@tonic-gate addr1++; 1330*7c478bd9Sstevel@tonic-gate appendnone(); 1331*7c478bd9Sstevel@tonic-gate } 1332*7c478bd9Sstevel@tonic-gate 1333*7c478bd9Sstevel@tonic-gate /* 1334*7c478bd9Sstevel@tonic-gate * Execute function f with the address bounds addr1 1335*7c478bd9Sstevel@tonic-gate * and addr2 surrounding cnt lines starting at dot. 1336*7c478bd9Sstevel@tonic-gate */ 1337*7c478bd9Sstevel@tonic-gate vremote(cnt, f, arg) 1338*7c478bd9Sstevel@tonic-gate int cnt, (*f)(), arg; 1339*7c478bd9Sstevel@tonic-gate { 1340*7c478bd9Sstevel@tonic-gate register int oing = inglobal; 1341*7c478bd9Sstevel@tonic-gate 1342*7c478bd9Sstevel@tonic-gate addr1 = dot; 1343*7c478bd9Sstevel@tonic-gate addr2 = dot + cnt - 1; 1344*7c478bd9Sstevel@tonic-gate inglobal = 0; 1345*7c478bd9Sstevel@tonic-gate if (FIXUNDO) 1346*7c478bd9Sstevel@tonic-gate undap1 = undap2 = dot; 1347*7c478bd9Sstevel@tonic-gate (*f)(arg); 1348*7c478bd9Sstevel@tonic-gate inglobal = oing; 1349*7c478bd9Sstevel@tonic-gate if (FIXUNDO) 1350*7c478bd9Sstevel@tonic-gate vundkind = VMANY; 1351*7c478bd9Sstevel@tonic-gate vmcurs = 0; 1352*7c478bd9Sstevel@tonic-gate } 1353*7c478bd9Sstevel@tonic-gate 1354*7c478bd9Sstevel@tonic-gate /* 1355*7c478bd9Sstevel@tonic-gate * Save the current contents of linebuf, if it has changed. 1356*7c478bd9Sstevel@tonic-gate */ 1357*7c478bd9Sstevel@tonic-gate vsave() 1358*7c478bd9Sstevel@tonic-gate { 1359*7c478bd9Sstevel@tonic-gate unsigned char temp[LBSIZE]; 1360*7c478bd9Sstevel@tonic-gate 1361*7c478bd9Sstevel@tonic-gate strncpy(temp, linebuf, sizeof (temp)); 1362*7c478bd9Sstevel@tonic-gate if (FIXUNDO && vundkind == VCHNG || vundkind == VCAPU) { 1363*7c478bd9Sstevel@tonic-gate /* 1364*7c478bd9Sstevel@tonic-gate * If the undo state is saved in the temporary buffer 1365*7c478bd9Sstevel@tonic-gate * vutmp, then we sync this into the temp file so that 1366*7c478bd9Sstevel@tonic-gate * we will be able to undo even after we have moved off 1367*7c478bd9Sstevel@tonic-gate * the line. It would be possible to associate a line 1368*7c478bd9Sstevel@tonic-gate * with vutmp but we assume that vutmp is only associated 1369*7c478bd9Sstevel@tonic-gate * with line dot (e.g. in case ':') above, so beware. 1370*7c478bd9Sstevel@tonic-gate */ 1371*7c478bd9Sstevel@tonic-gate prepapp(); 1372*7c478bd9Sstevel@tonic-gate strcLIN(vutmp); 1373*7c478bd9Sstevel@tonic-gate putmark(dot); 1374*7c478bd9Sstevel@tonic-gate vremote(1, yank, 0); 1375*7c478bd9Sstevel@tonic-gate vundkind = VMCHNG; 1376*7c478bd9Sstevel@tonic-gate notecnt = 0; 1377*7c478bd9Sstevel@tonic-gate undkind = UNDCHANGE; 1378*7c478bd9Sstevel@tonic-gate } 1379*7c478bd9Sstevel@tonic-gate /* 1380*7c478bd9Sstevel@tonic-gate * Get the line out of the temp file and do nothing if it hasn't 1381*7c478bd9Sstevel@tonic-gate * changed. This may seem like a loss, but the line will 1382*7c478bd9Sstevel@tonic-gate * almost always be in a read buffer so this may well avoid disk i/o. 1383*7c478bd9Sstevel@tonic-gate */ 1384*7c478bd9Sstevel@tonic-gate getDOT(); 1385*7c478bd9Sstevel@tonic-gate if (strncmp(linebuf, temp, sizeof (temp)) == 0) 1386*7c478bd9Sstevel@tonic-gate return; 1387*7c478bd9Sstevel@tonic-gate strcLIN(temp); 1388*7c478bd9Sstevel@tonic-gate putmark(dot); 1389*7c478bd9Sstevel@tonic-gate } 1390*7c478bd9Sstevel@tonic-gate 1391*7c478bd9Sstevel@tonic-gate #undef forbid 1392*7c478bd9Sstevel@tonic-gate #define forbid(a) if (a) { beep(); return; } 1393*7c478bd9Sstevel@tonic-gate 1394*7c478bd9Sstevel@tonic-gate /* 1395*7c478bd9Sstevel@tonic-gate * Do a z operation. 1396*7c478bd9Sstevel@tonic-gate * Code here is rather long, and very uninteresting. 1397*7c478bd9Sstevel@tonic-gate */ 1398*7c478bd9Sstevel@tonic-gate vzop(hadcnt, cnt, c) 1399*7c478bd9Sstevel@tonic-gate bool hadcnt; 1400*7c478bd9Sstevel@tonic-gate int cnt; 1401*7c478bd9Sstevel@tonic-gate register int c; 1402*7c478bd9Sstevel@tonic-gate { 1403*7c478bd9Sstevel@tonic-gate register line *addr; 1404*7c478bd9Sstevel@tonic-gate 1405*7c478bd9Sstevel@tonic-gate if (state != VISUAL) { 1406*7c478bd9Sstevel@tonic-gate /* 1407*7c478bd9Sstevel@tonic-gate * Z from open; always like a z=. 1408*7c478bd9Sstevel@tonic-gate * This code is a mess and should be cleaned up. 1409*7c478bd9Sstevel@tonic-gate */ 1410*7c478bd9Sstevel@tonic-gate vmoveitup(1, 1); 1411*7c478bd9Sstevel@tonic-gate vgoto(outline, 0); 1412*7c478bd9Sstevel@tonic-gate ostop(normf); 1413*7c478bd9Sstevel@tonic-gate setoutt(); 1414*7c478bd9Sstevel@tonic-gate addr2 = dot; 1415*7c478bd9Sstevel@tonic-gate vclear(); 1416*7c478bd9Sstevel@tonic-gate destline = WECHO; 1417*7c478bd9Sstevel@tonic-gate zop2(Xhadcnt ? Xcnt : value(vi_WINDOW) - 1, '='); 1418*7c478bd9Sstevel@tonic-gate if (state == CRTOPEN) 1419*7c478bd9Sstevel@tonic-gate putnl(); 1420*7c478bd9Sstevel@tonic-gate putNFL(); 1421*7c478bd9Sstevel@tonic-gate termreset(); 1422*7c478bd9Sstevel@tonic-gate Outchar = vputchar; 1423*7c478bd9Sstevel@tonic-gate (void)ostart(); 1424*7c478bd9Sstevel@tonic-gate vcnt = 0; 1425*7c478bd9Sstevel@tonic-gate outline = destline = 0; 1426*7c478bd9Sstevel@tonic-gate vjumpto(dot, cursor, 0); 1427*7c478bd9Sstevel@tonic-gate return; 1428*7c478bd9Sstevel@tonic-gate } 1429*7c478bd9Sstevel@tonic-gate if (hadcnt) { 1430*7c478bd9Sstevel@tonic-gate addr = zero + cnt; 1431*7c478bd9Sstevel@tonic-gate if (addr < one) 1432*7c478bd9Sstevel@tonic-gate addr = one; 1433*7c478bd9Sstevel@tonic-gate if (addr > dol) 1434*7c478bd9Sstevel@tonic-gate addr = dol; 1435*7c478bd9Sstevel@tonic-gate markit(addr); 1436*7c478bd9Sstevel@tonic-gate } else 1437*7c478bd9Sstevel@tonic-gate switch (c) { 1438*7c478bd9Sstevel@tonic-gate 1439*7c478bd9Sstevel@tonic-gate case '+': 1440*7c478bd9Sstevel@tonic-gate addr = dot + vcnt - vcline; 1441*7c478bd9Sstevel@tonic-gate break; 1442*7c478bd9Sstevel@tonic-gate 1443*7c478bd9Sstevel@tonic-gate case '^': 1444*7c478bd9Sstevel@tonic-gate addr = dot - vcline - 1; 1445*7c478bd9Sstevel@tonic-gate forbid (addr < one); 1446*7c478bd9Sstevel@tonic-gate c = '-'; 1447*7c478bd9Sstevel@tonic-gate break; 1448*7c478bd9Sstevel@tonic-gate 1449*7c478bd9Sstevel@tonic-gate default: 1450*7c478bd9Sstevel@tonic-gate addr = dot; 1451*7c478bd9Sstevel@tonic-gate break; 1452*7c478bd9Sstevel@tonic-gate } 1453*7c478bd9Sstevel@tonic-gate switch (c) { 1454*7c478bd9Sstevel@tonic-gate 1455*7c478bd9Sstevel@tonic-gate case '.': 1456*7c478bd9Sstevel@tonic-gate case '-': 1457*7c478bd9Sstevel@tonic-gate break; 1458*7c478bd9Sstevel@tonic-gate 1459*7c478bd9Sstevel@tonic-gate case '^': 1460*7c478bd9Sstevel@tonic-gate forbid (addr <= one); 1461*7c478bd9Sstevel@tonic-gate break; 1462*7c478bd9Sstevel@tonic-gate 1463*7c478bd9Sstevel@tonic-gate case '+': 1464*7c478bd9Sstevel@tonic-gate forbid (addr >= dol); 1465*7c478bd9Sstevel@tonic-gate /* fall into ... */ 1466*7c478bd9Sstevel@tonic-gate 1467*7c478bd9Sstevel@tonic-gate case CR: 1468*7c478bd9Sstevel@tonic-gate case NL: 1469*7c478bd9Sstevel@tonic-gate c = CR; 1470*7c478bd9Sstevel@tonic-gate break; 1471*7c478bd9Sstevel@tonic-gate 1472*7c478bd9Sstevel@tonic-gate default: 1473*7c478bd9Sstevel@tonic-gate beep(); 1474*7c478bd9Sstevel@tonic-gate return; 1475*7c478bd9Sstevel@tonic-gate } 1476*7c478bd9Sstevel@tonic-gate vmoving = 0; 1477*7c478bd9Sstevel@tonic-gate vjumpto(addr, NOSTR, c); 1478*7c478bd9Sstevel@tonic-gate } 1479