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 2005 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 #include "ex.h" 34 #include "ex_re.h" 35 #include "ex_tty.h" 36 #include "ex_vis.h" 37 38 /* 39 * Entry points to open and visual from command mode processor. 40 * The open/visual code breaks down roughly as follows: 41 * 42 * ex_v.c entry points, checking of terminal characteristics 43 * 44 * ex_vadj.c logical screen control, use of intelligent operations 45 * insert/delete line and coordination with screen image; 46 * updating of screen after changes. 47 * 48 * ex_vget.c input of single keys and reading of input lines 49 * from the echo area, handling of \ escapes on input for 50 * uppercase only terminals, handling of memory for repeated 51 * commands and small saved texts from inserts and partline 52 * deletes, notification of multi line changes in the echo 53 * area. 54 * 55 * ex_vmain.c main command decoding, some command processing. 56 * 57 * ex_voperate.c decoding of operator/operand sequences and 58 * contextual scans, implementation of word motions. 59 * 60 * ex_vops.c major operator interfaces, undos, motions, deletes, 61 * changes, opening new lines, shifts, replacements and yanks 62 * coordinating logical and physical changes. 63 * 64 * ex_vops2.c subroutines for operator interfaces in ex_vops.c, 65 * insert mode, read input line processing at lowest level. 66 * 67 * ex_vops3.c structured motion definitions of ( ) { } and [ ] operators, 68 * indent for lisp routines, () and {} balancing. 69 * 70 * ex_vput.c output routines, clearing, physical mapping of logical cursor 71 * positioning, cursor motions, handling of insert character 72 * and delete character functions of intelligent and unintelligent 73 * terminals, visual mode tracing routines (for debugging), 74 * control of screen image and its updating. 75 * 76 * ex_vwind.c window level control of display, forward and backward rolls, 77 * absolute motions, contextual displays, line depth determination 78 */ 79 80 void setsize(); 81 void winch(); 82 void vintr(); 83 void ovend(ttymode); 84 85 wchar_t atube[TUBESIZE]; 86 jmp_buf venv; 87 int windowchg; 88 int sigok; 89 90 /* reinitialize window size after SIGWINCH */ 91 void windowinit() 92 { 93 windowchg = 0; 94 setsize(); 95 if(value(vi_WINDOW) >= lines || options[vi_WINDOW].odefault == value(vi_WINDOW)) 96 value(vi_WINDOW) = lines -1; 97 options[vi_WINDOW].odefault = lines - 1; 98 if(options[vi_SCROLL].odefault == value(vi_SCROLL)) 99 value(vi_SCROLL) = value(vi_WINDOW)/2; 100 options[vi_SCROLL].odefault = (lines - 1)/2; 101 vsetsiz(value(vi_WINDOW)); 102 setwind(); 103 vok(atube, 1); 104 } 105 106 void redraw() 107 { 108 vsave(); 109 windowinit(); 110 vclear(); 111 vdirty(0, lines); 112 if(state != VISUAL) { 113 vclean(); 114 vmoveto(dot, cursor, 0); 115 } else { 116 vredraw(WTOP); 117 vrepaint(cursor); 118 vfixcurs(); 119 } 120 } 121 122 /*ARGSUSED*/ 123 void 124 #ifdef __STDC__ 125 winch(int sig) 126 #else 127 winch(sig) 128 int sig; 129 #endif 130 { 131 struct winsize jwin; 132 int l; 133 134 if(ioctl(0, TIOCGWINSZ, &jwin) != -1) { 135 #ifdef XPG4 136 oldlines = jwin.ws_row; 137 oldcolumns = jwin.ws_col; 138 #endif /* XPG4 */ 139 if (sigok) { 140 if (columns != jwin.ws_col || lines != jwin.ws_row) 141 redraw(); 142 } 143 } 144 else 145 windowchg++; 146 (void)signal(SIGWINCH, winch); 147 } 148 149 void 150 setsize() 151 { 152 struct winsize jwin; 153 int l; 154 155 if(ioctl(0, TIOCGWINSZ, &jwin) != -1) { 156 if (jwin.ws_col > 0) 157 columns = jwin.ws_col; 158 if (jwin.ws_row > 0) 159 lines = jwin.ws_row; 160 } 161 162 #ifdef XPG4 163 if (envlines != -1) { 164 lines = envlines; 165 } 166 167 if (envcolumns != -1) { 168 columns = envcolumns; 169 } 170 171 if (envlines != -1 || envcolumns != -1) { 172 jwin.ws_row = lines; 173 jwin.ws_col = columns; 174 175 if (ioctl(0, TIOCSWINSZ, &jwin) == -1) { 176 jwin.ws_row = oldlines; 177 jwin.ws_col = oldcolumns; 178 179 ioctl(0, TIOCSWINSZ, &jwin); 180 } 181 } 182 #endif /* XPG4 */ 183 184 if (lines <= 1) 185 lines = 24; 186 l = lines; 187 if (columns <= 4) 188 columns = 1000; 189 value(vi_WINDOW) = options[vi_WINDOW].odefault = l - 1; 190 } 191 192 /* 193 * Enter open mode 194 */ 195 void 196 oop(void) 197 { 198 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 void 265 ovbeg(void) 266 { 267 268 if (inopen) 269 error(gettext("Recursive open/visual not allowed")); 270 Vlines = lineDOL(); 271 fixzero(); 272 setdot(); 273 pastwh(); 274 dot = addr2; 275 } 276 277 void 278 ovend(ttymode f) 279 { 280 281 splitw++; 282 vgoto(WECHO, 0); 283 vclreol(); 284 vgoto(WECHO, 0); 285 holdcm = 0; 286 splitw = 0; 287 ostop(f); 288 setoutt(); 289 undvis(); 290 columns = OCOLUMNS; 291 inopen = 0; 292 flusho(); 293 netchHAD(Vlines); 294 } 295 296 /* 297 * Enter visual mode 298 */ 299 void 300 vop(void) 301 { 302 int c; 303 ttymode f; /* was register */ 304 extern unsigned char termtype[]; 305 306 if (!cursor_address && !cursor_up) { 307 if (initev) { 308 toopen: 309 if (generic_type) 310 merror(gettext("I don't know what kind of terminal you are on - all I have is '%s'."), termtype); 311 putNFL(); 312 merror(gettext("[Using open mode]")); 313 putNFL(); 314 oop(); 315 return; 316 } 317 error(gettext("Visual needs addressable cursor or upline capability")); 318 } 319 if (over_strike && !erase_overstrike) { 320 if (initev) 321 goto toopen; 322 error(gettext("Can't use visual on a terminal which overstrikes")); 323 } 324 if (!clear_screen) { 325 if (initev) 326 goto toopen; 327 error(gettext("Visual requires clear screen capability")); 328 } 329 if (!scroll_forward) { 330 if (initev) 331 goto toopen; 332 error(gettext("Visual requires scrolling")); 333 } 334 windowchg = 0; 335 (void)signal(SIGWINCH, winch); 336 ovbeg(); 337 bastate = VISUAL; 338 c = 0; 339 if (any(peekchar(), "+-^.")) 340 c = getchar(); 341 pastwh(); 342 vsetsiz(isdigit(peekchar()) ? getnum() : value(vi_WINDOW)); 343 setwind(); 344 donewline(); 345 vok(atube, 0); 346 if (!inglobal) 347 savevis(); 348 Outchar = vputchar; 349 vmoving = 0; 350 f = ostart(); 351 if (initev == 0) { 352 vcontext(dot, c); 353 vnline((unsigned char *)NOSTR); 354 } 355 vmain(); 356 Command = (unsigned char *)"visual"; 357 ovend(f); 358 (void)signal(SIGWINCH, SIG_DFL); 359 } 360 361 /* 362 * Hack to allow entry to visual with 363 * empty buffer since routines internally 364 * demand at least one line. 365 */ 366 void 367 fixzero(void) 368 { 369 370 if (dol == zero) { 371 bool ochng = chng; 372 373 vdoappend((unsigned char *)""); 374 if (!ochng) 375 sync(); 376 addr1 = addr2 = one; 377 } else if (addr2 == zero) 378 addr2 = one; 379 } 380 381 /* 382 * Save lines before visual between unddol and truedol. 383 * Accomplish this by throwing away current [unddol,truedol] 384 * and then saving all the lines in the buffer and moving 385 * unddol back to dol. Don't do this if in a global. 386 * 387 * If you do 388 * g/xxx/vi. 389 * and then do a 390 * :e xxxx 391 * at some point, and then quit from the visual and undo 392 * you get the old file back. Somewhat weird. 393 */ 394 void 395 savevis(void) 396 { 397 398 if (inglobal) 399 return; 400 truedol = unddol; 401 saveall(); 402 unddol = dol; 403 undkind = UNDNONE; 404 } 405 406 /* 407 * Restore a sensible state after a visual/open, moving the saved 408 * stuff back to [unddol,dol], and killing the partial line kill indicators. 409 */ 410 void 411 undvis(void) 412 { 413 414 if (ruptible) 415 signal(SIGINT, onintr); 416 squish(); 417 pkill[0] = pkill[1] = 0; 418 unddol = truedol; 419 unddel = zero; 420 undap1 = one; 421 undap2 = dol + 1; 422 undkind = UNDALL; 423 if (undadot <= zero || undadot > dol) 424 undadot = zero+1; 425 } 426 427 /* 428 * Set the window parameters based on the base state bastate 429 * and the available buffer space. 430 */ 431 void 432 setwind(void) 433 { 434 435 WCOLS = columns; 436 switch (bastate) { 437 438 case ONEOPEN: 439 if (auto_right_margin) 440 WCOLS--; 441 /* FALLTHROUGH */ 442 443 case HARDOPEN: 444 basWTOP = WTOP = WBOT = WECHO = 0; 445 ZERO = 0; 446 holdcm++; 447 break; 448 449 case CRTOPEN: 450 basWTOP = lines - 2; 451 /* FALLTHROUGH */ 452 453 case VISUAL: 454 ZERO = lines - TUBESIZE / WCOLS; 455 if (ZERO < 0) 456 ZERO = 0; 457 if (ZERO > basWTOP) 458 error(gettext("Screen too large for internal buffer")); 459 WTOP = basWTOP; WBOT = lines - 2; WECHO = lines - 1; 460 break; 461 } 462 state = bastate; 463 basWLINES = WLINES = WBOT - WTOP + 1; 464 } 465 466 /* 467 * Can we hack an open/visual on this terminal? 468 * If so, then divide the screen buffer up into lines, 469 * and initialize a bunch of state variables before we start. 470 */ 471 static unsigned char vlinebuf[LBSIZE]; 472 473 void 474 vok(wchar_t *atube, int undo) 475 { 476 int i; 477 static int beenhere; 478 479 if (WCOLS == 1000) 480 serror((unsigned char *) 481 gettext("Don't know enough about your terminal to use %s"), 482 Command); 483 if (WCOLS > TUBECOLS) 484 error(gettext("Terminal too wide")); 485 if (WLINES >= TUBELINES || WCOLS * (WECHO - ZERO + 1) > TUBESIZE) 486 error(gettext("Screen too large")); 487 488 vtube0 = atube; 489 if(beenhere) 490 vclrbyte(atube, WCOLS * (WECHO - ZERO + 1)); 491 for (i = 0; i < ZERO; i++) 492 vtube[i] = (wchar_t *) 0; 493 for (; i <= WECHO; i++) 494 vtube[i] = atube, atube += WCOLS; 495 if(beenhere++) { 496 for (; i < TUBELINES; i++) 497 vtube[i] = (wchar_t *) 0; 498 } 499 vutmp = vlinebuf; 500 if(!undo) { 501 vundkind = VNONE; 502 vUNDdot = 0; 503 } 504 OCOLUMNS = columns; 505 inopen = 1; 506 #ifdef CBREAK 507 signal(SIGINT, vintr); 508 #endif 509 vmoving = 0; 510 splitw = 0; 511 doomed = 0; 512 holdupd = 0; 513 if(!undo) 514 Peekkey = 0; 515 vcnt = vcline = 0; 516 if (vSCROLL == 0) 517 vSCROLL = value(vi_SCROLL); 518 } 519 520 #ifdef CBREAK 521 /*ARGSUSED*/ 522 void 523 #ifdef __STDC__ 524 vintr(int sig) 525 #else 526 vintr(sig) 527 int sig; 528 #endif 529 { 530 531 signal(SIGINT, vintr); 532 if (vcatch) 533 onintr(0); 534 ungetkey(ATTN); 535 draino(); 536 } 537 #endif 538 539 /* 540 * Set the size of the screen to size lines, to take effect the 541 * next time the screen is redrawn. 542 */ 543 void 544 vsetsiz(int size) 545 { 546 int b; 547 548 if (bastate != VISUAL) 549 return; 550 b = lines - 1 - size; 551 if (b >= lines - 1) 552 b = lines - 2; 553 if (b < 0) 554 b = 0; 555 basWTOP = b; 556 basWLINES = WBOT - b + 1; 557 } 558