1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1995 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 /* Copyright (c) 1981 Regents of the University of California */ 32 33 #pragma ident "%Z%%M% %I% %E% SMI" 34 35 #include "ex.h" 36 #include "ex_re.h" 37 #include "ex_tty.h" 38 #include "ex_vis.h" 39 40 /* 41 * Entry points to open and visual from command mode processor. 42 * The open/visual code breaks down roughly as follows: 43 * 44 * ex_v.c entry points, checking of terminal characteristics 45 * 46 * ex_vadj.c logical screen control, use of intelligent operations 47 * insert/delete line and coordination with screen image; 48 * updating of screen after changes. 49 * 50 * ex_vget.c input of single keys and reading of input lines 51 * from the echo area, handling of \ escapes on input for 52 * uppercase only terminals, handling of memory for repeated 53 * commands and small saved texts from inserts and partline 54 * deletes, notification of multi line changes in the echo 55 * area. 56 * 57 * ex_vmain.c main command decoding, some command processing. 58 * 59 * ex_voperate.c decoding of operator/operand sequences and 60 * contextual scans, implementation of word motions. 61 * 62 * ex_vops.c major operator interfaces, undos, motions, deletes, 63 * changes, opening new lines, shifts, replacements and yanks 64 * coordinating logical and physical changes. 65 * 66 * ex_vops2.c subroutines for operator interfaces in ex_vops.c, 67 * insert mode, read input line processing at lowest level. 68 * 69 * ex_vops3.c structured motion definitions of ( ) { } and [ ] operators, 70 * indent for lisp routines, () and {} balancing. 71 * 72 * ex_vput.c output routines, clearing, physical mapping of logical cursor 73 * positioning, cursor motions, handling of insert character 74 * and delete character functions of intelligent and unintelligent 75 * terminals, visual mode tracing routines (for debugging), 76 * control of screen image and its updating. 77 * 78 * ex_vwind.c window level control of display, forward and backward rolls, 79 * absolute motions, contextual displays, line depth determination 80 */ 81 82 void setsize(); 83 void winch(); 84 void vintr(); 85 86 wchar_t atube[TUBESIZE]; 87 jmp_buf venv; 88 int windowchg; 89 int sigok; 90 91 /* reinitialize window size after SIGWINCH */ 92 void windowinit() 93 { 94 windowchg = 0; 95 setsize(); 96 if(value(vi_WINDOW) >= lines || options[vi_WINDOW].odefault == value(vi_WINDOW)) 97 value(vi_WINDOW) = lines -1; 98 options[vi_WINDOW].odefault = lines - 1; 99 if(options[vi_SCROLL].odefault == value(vi_SCROLL)) 100 value(vi_SCROLL) = value(vi_WINDOW)/2; 101 options[vi_SCROLL].odefault = (lines - 1)/2; 102 vsetsiz(value(vi_WINDOW)); 103 setwind(); 104 vok(atube, 1); 105 } 106 107 void redraw() 108 { 109 vsave(); 110 windowinit(); 111 vclear(); 112 vdirty(0, lines); 113 if(state != VISUAL) { 114 vclean(); 115 vmoveto(dot, cursor, 0); 116 } else { 117 vredraw(WTOP); 118 vrepaint(cursor); 119 vfixcurs(); 120 } 121 } 122 123 /*ARGSUSED*/ 124 void 125 #ifdef __STDC__ 126 winch(int sig) 127 #else 128 winch(sig) 129 int sig; 130 #endif 131 { 132 struct winsize jwin; 133 register int l; 134 135 if(ioctl(0, TIOCGWINSZ, &jwin) != -1) { 136 #ifdef XPG4 137 oldlines = jwin.ws_row; 138 oldcolumns = jwin.ws_col; 139 #endif /* XPG4 */ 140 if (sigok) { 141 if (columns != jwin.ws_col || lines != jwin.ws_row) 142 redraw(); 143 } 144 } 145 else 146 windowchg++; 147 (void)signal(SIGWINCH, winch); 148 } 149 150 void 151 setsize() 152 { 153 struct winsize jwin; 154 register int l; 155 156 if(ioctl(0, TIOCGWINSZ, &jwin) != -1) { 157 if (jwin.ws_col > 0) 158 columns = jwin.ws_col; 159 if (jwin.ws_row > 0) 160 lines = jwin.ws_row; 161 } 162 163 #ifdef XPG4 164 if (envlines != -1) { 165 lines = envlines; 166 } 167 168 if (envcolumns != -1) { 169 columns = envcolumns; 170 } 171 172 if (envlines != -1 || envcolumns != -1) { 173 jwin.ws_row = lines; 174 jwin.ws_col = columns; 175 176 if (ioctl(0, TIOCSWINSZ, &jwin) == -1) { 177 jwin.ws_row = oldlines; 178 jwin.ws_col = oldcolumns; 179 180 ioctl(0, TIOCSWINSZ, &jwin); 181 } 182 } 183 #endif /* XPG4 */ 184 185 if (lines <= 1) 186 lines = 24; 187 l = lines; 188 if (columns <= 4) 189 columns = 1000; 190 value(vi_WINDOW) = options[vi_WINDOW].odefault = l - 1; 191 } 192 193 /* 194 * Enter open mode 195 */ 196 oop() 197 { 198 register unsigned char *ic; 199 ttymode f; /* was register */ 200 int resize; 201 202 windowchg = 0; 203 (void)signal(SIGWINCH, winch); 204 ovbeg(); 205 if (peekchar() == '/') { 206 (void)vi_compile(getchar(), 1); 207 savere(&scanre); 208 if (execute(0, dot) == 0) 209 error(value(vi_TERSE) ? gettext("Fail") : 210 gettext("Pattern not found on addressed line")); 211 ic = (unsigned char *)loc1; 212 if (ic > linebuf && *ic == 0) 213 ic--; 214 } else { 215 getDOT(); 216 ic = vskipwh(linebuf); 217 } 218 donewline(); 219 220 /* 221 * If overstrike then have to HARDOPEN 222 * else if can move cursor up off current line can use CRTOPEN (~~vi1) 223 * otherwise have to use ONEOPEN (like adm3) 224 */ 225 if (over_strike && !erase_overstrike) 226 bastate = HARDOPEN; 227 else if (cursor_address || cursor_up) 228 bastate = CRTOPEN; 229 else 230 bastate = ONEOPEN; 231 setwind(); 232 233 /* 234 * To avoid bombing on glass-crt's when the line is too long 235 * pretend that such terminals are 160 columns wide. 236 * If a line is too wide for display, we will dynamically 237 * switch to hardcopy open mode. 238 */ 239 if (state != CRTOPEN) 240 WCOLS = TUBECOLS; 241 if (!inglobal) 242 savevis(); 243 vok(atube, 0); 244 if (state != CRTOPEN) 245 columns = WCOLS; 246 Outchar = vputchar; 247 f = ostart(); 248 if (state == CRTOPEN) { 249 if (outcol == UKCOL) 250 outcol = 0; 251 vmoveitup(1, 1); 252 } else 253 outline = destline = WBOT; 254 vshow(dot, NOLINE); 255 vnline(ic); 256 vmain(); 257 if (state != CRTOPEN) 258 vclean(); 259 Command = (unsigned char *)"open"; 260 ovend(f); 261 (void)signal(SIGWINCH, SIG_DFL); 262 } 263 264 ovbeg() 265 { 266 267 if (inopen) 268 error(gettext("Recursive open/visual not allowed")); 269 Vlines = lineDOL(); 270 fixzero(); 271 setdot(); 272 pastwh(); 273 dot = addr2; 274 } 275 276 ovend(f) 277 ttymode f; 278 { 279 280 splitw++; 281 vgoto(WECHO, 0); 282 vclreol(); 283 vgoto(WECHO, 0); 284 holdcm = 0; 285 splitw = 0; 286 ostop(f); 287 setoutt(); 288 undvis(); 289 columns = OCOLUMNS; 290 inopen = 0; 291 flusho(); 292 netchHAD(Vlines); 293 } 294 295 /* 296 * Enter visual mode 297 */ 298 vop() 299 { 300 register int c; 301 ttymode f; /* was register */ 302 extern unsigned char termtype[]; 303 304 if (!cursor_address && !cursor_up) { 305 if (initev) { 306 toopen: 307 if (generic_type) 308 merror(gettext("I don't know what kind of terminal you are on - all I have is '%s'."), termtype); 309 putNFL(); 310 merror(gettext("[Using open mode]")); 311 putNFL(); 312 oop(); 313 return; 314 } 315 error(gettext("Visual needs addressable cursor or upline capability")); 316 } 317 if (over_strike && !erase_overstrike) { 318 if (initev) 319 goto toopen; 320 error(gettext("Can't use visual on a terminal which overstrikes")); 321 } 322 if (!clear_screen) { 323 if (initev) 324 goto toopen; 325 error(gettext("Visual requires clear screen capability")); 326 } 327 if (!scroll_forward) { 328 if (initev) 329 goto toopen; 330 error(gettext("Visual requires scrolling")); 331 } 332 windowchg = 0; 333 (void)signal(SIGWINCH, winch); 334 ovbeg(); 335 bastate = VISUAL; 336 c = 0; 337 if (any(peekchar(), "+-^.")) 338 c = getchar(); 339 pastwh(); 340 vsetsiz(isdigit(peekchar()) ? getnum() : value(vi_WINDOW)); 341 setwind(); 342 donewline(); 343 vok(atube, 0); 344 if (!inglobal) 345 savevis(); 346 Outchar = vputchar; 347 vmoving = 0; 348 f = ostart(); 349 if (initev == 0) { 350 vcontext(dot, c); 351 vnline(NOSTR); 352 } 353 vmain(); 354 Command = (unsigned char *)"visual"; 355 ovend(f); 356 (void)signal(SIGWINCH, SIG_DFL); 357 } 358 359 /* 360 * Hack to allow entry to visual with 361 * empty buffer since routines internally 362 * demand at least one line. 363 */ 364 fixzero() 365 { 366 367 if (dol == zero) { 368 register bool ochng = chng; 369 370 vdoappend(""); 371 if (!ochng) 372 sync(); 373 addr1 = addr2 = one; 374 } else if (addr2 == zero) 375 addr2 = one; 376 } 377 378 /* 379 * Save lines before visual between unddol and truedol. 380 * Accomplish this by throwing away current [unddol,truedol] 381 * and then saving all the lines in the buffer and moving 382 * unddol back to dol. Don't do this if in a global. 383 * 384 * If you do 385 * g/xxx/vi. 386 * and then do a 387 * :e xxxx 388 * at some point, and then quit from the visual and undo 389 * you get the old file back. Somewhat weird. 390 */ 391 savevis() 392 { 393 394 if (inglobal) 395 return; 396 truedol = unddol; 397 saveall(); 398 unddol = dol; 399 undkind = UNDNONE; 400 } 401 402 /* 403 * Restore a sensible state after a visual/open, moving the saved 404 * stuff back to [unddol,dol], and killing the partial line kill indicators. 405 */ 406 undvis() 407 { 408 409 if (ruptible) 410 signal(SIGINT, onintr); 411 squish(); 412 pkill[0] = pkill[1] = 0; 413 unddol = truedol; 414 unddel = zero; 415 undap1 = one; 416 undap2 = dol + 1; 417 undkind = UNDALL; 418 if (undadot <= zero || undadot > dol) 419 undadot = zero+1; 420 } 421 422 /* 423 * Set the window parameters based on the base state bastate 424 * and the available buffer space. 425 */ 426 setwind() 427 { 428 429 WCOLS = columns; 430 switch (bastate) { 431 432 case ONEOPEN: 433 if (auto_right_margin) 434 WCOLS--; 435 /* fall into ... */ 436 437 case HARDOPEN: 438 basWTOP = WTOP = WBOT = WECHO = 0; 439 ZERO = 0; 440 holdcm++; 441 break; 442 443 case CRTOPEN: 444 basWTOP = lines - 2; 445 /* fall into */ 446 447 case VISUAL: 448 ZERO = lines - TUBESIZE / WCOLS; 449 if (ZERO < 0) 450 ZERO = 0; 451 if (ZERO > basWTOP) 452 error(gettext("Screen too large for internal buffer")); 453 WTOP = basWTOP; WBOT = lines - 2; WECHO = lines - 1; 454 break; 455 } 456 state = bastate; 457 basWLINES = WLINES = WBOT - WTOP + 1; 458 } 459 460 /* 461 * Can we hack an open/visual on this terminal? 462 * If so, then divide the screen buffer up into lines, 463 * and initialize a bunch of state variables before we start. 464 */ 465 static unsigned char vlinebuf[LBSIZE]; 466 467 vok(atube, undo) 468 register wchar_t *atube; 469 { 470 register int i; 471 static int beenhere; 472 473 if (WCOLS == 1000) 474 serror(gettext("Don't know enough about your terminal to use %s"), 475 Command); 476 if (WCOLS > TUBECOLS) 477 error(gettext("Terminal too wide")); 478 if (WLINES >= TUBELINES || WCOLS * (WECHO - ZERO + 1) > TUBESIZE) 479 error(gettext("Screen too large")); 480 481 vtube0 = atube; 482 if(beenhere) 483 vclrbyte(atube, WCOLS * (WECHO - ZERO + 1)); 484 for (i = 0; i < ZERO; i++) 485 vtube[i] = (wchar_t *) 0; 486 for (; i <= WECHO; i++) 487 vtube[i] = atube, atube += WCOLS; 488 if(beenhere++) { 489 for (; i < TUBELINES; i++) 490 vtube[i] = (wchar_t *) 0; 491 } 492 vutmp = vlinebuf; 493 if(!undo) { 494 vundkind = VNONE; 495 vUNDdot = 0; 496 } 497 OCOLUMNS = columns; 498 inopen = 1; 499 #ifdef CBREAK 500 signal(SIGINT, vintr); 501 #endif 502 vmoving = 0; 503 splitw = 0; 504 doomed = 0; 505 holdupd = 0; 506 if(!undo) 507 Peekkey = 0; 508 vcnt = vcline = 0; 509 if (vSCROLL == 0) 510 vSCROLL = value(vi_SCROLL); 511 } 512 513 #ifdef CBREAK 514 /*ARGSUSED*/ 515 void 516 #ifdef __STDC__ 517 vintr(int sig) 518 #else 519 vintr(sig) 520 int sig; 521 #endif 522 { 523 524 signal(SIGINT, vintr); 525 if (vcatch) 526 onintr(0); 527 ungetkey(ATTN); 528 draino(); 529 } 530 #endif 531 532 /* 533 * Set the size of the screen to size lines, to take effect the 534 * next time the screen is redrawn. 535 */ 536 vsetsiz(size) 537 int size; 538 { 539 register int b; 540 541 if (bastate != VISUAL) 542 return; 543 b = lines - 1 - size; 544 if (b >= lines - 1) 545 b = lines - 2; 546 if (b < 0) 547 b = 0; 548 basWTOP = b; 549 basWLINES = WBOT - b + 1; 550 } 551