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