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 #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 void ovend(ttymode); 86 87 wchar_t atube[TUBESIZE]; 88 jmp_buf venv; 89 int windowchg; 90 int sigok; 91 92 /* reinitialize window size after SIGWINCH */ 93 void windowinit() 94 { 95 windowchg = 0; 96 setsize(); 97 if(value(vi_WINDOW) >= lines || options[vi_WINDOW].odefault == value(vi_WINDOW)) 98 value(vi_WINDOW) = lines -1; 99 options[vi_WINDOW].odefault = lines - 1; 100 if(options[vi_SCROLL].odefault == value(vi_SCROLL)) 101 value(vi_SCROLL) = value(vi_WINDOW)/2; 102 options[vi_SCROLL].odefault = (lines - 1)/2; 103 vsetsiz(value(vi_WINDOW)); 104 setwind(); 105 vok(atube, 1); 106 } 107 108 void redraw() 109 { 110 vsave(); 111 windowinit(); 112 vclear(); 113 vdirty(0, lines); 114 if(state != VISUAL) { 115 vclean(); 116 vmoveto(dot, cursor, 0); 117 } else { 118 vredraw(WTOP); 119 vrepaint(cursor); 120 vfixcurs(); 121 } 122 } 123 124 /*ARGSUSED*/ 125 void 126 #ifdef __STDC__ 127 winch(int sig) 128 #else 129 winch(sig) 130 int sig; 131 #endif 132 { 133 struct winsize jwin; 134 int l; 135 136 if(ioctl(0, TIOCGWINSZ, &jwin) != -1) { 137 #ifdef XPG4 138 oldlines = jwin.ws_row; 139 oldcolumns = jwin.ws_col; 140 #endif /* XPG4 */ 141 if (sigok) { 142 if (columns != jwin.ws_col || lines != jwin.ws_row) 143 redraw(); 144 } 145 } 146 else 147 windowchg++; 148 (void)signal(SIGWINCH, winch); 149 } 150 151 void 152 setsize() 153 { 154 struct winsize jwin; 155 int l; 156 157 if(ioctl(0, TIOCGWINSZ, &jwin) != -1) { 158 if (jwin.ws_col > 0) 159 columns = jwin.ws_col; 160 if (jwin.ws_row > 0) 161 lines = jwin.ws_row; 162 } 163 164 #ifdef XPG4 165 if (envlines != -1) { 166 lines = envlines; 167 } 168 169 if (envcolumns != -1) { 170 columns = envcolumns; 171 } 172 173 if (envlines != -1 || envcolumns != -1) { 174 jwin.ws_row = lines; 175 jwin.ws_col = columns; 176 177 if (ioctl(0, TIOCSWINSZ, &jwin) == -1) { 178 jwin.ws_row = oldlines; 179 jwin.ws_col = oldcolumns; 180 181 ioctl(0, TIOCSWINSZ, &jwin); 182 } 183 } 184 #endif /* XPG4 */ 185 186 if (lines <= 1) 187 lines = 24; 188 l = lines; 189 if (columns <= 4) 190 columns = 1000; 191 value(vi_WINDOW) = options[vi_WINDOW].odefault = l - 1; 192 } 193 194 /* 195 * Enter open mode 196 */ 197 void 198 oop(void) 199 { 200 unsigned char *ic; 201 ttymode f; /* was register */ 202 int resize; 203 204 windowchg = 0; 205 (void)signal(SIGWINCH, winch); 206 ovbeg(); 207 if (peekchar() == '/') { 208 (void)vi_compile(getchar(), 1); 209 savere(&scanre); 210 if (execute(0, dot) == 0) 211 error(value(vi_TERSE) ? gettext("Fail") : 212 gettext("Pattern not found on addressed line")); 213 ic = (unsigned char *)loc1; 214 if (ic > linebuf && *ic == 0) 215 ic--; 216 } else { 217 getDOT(); 218 ic = vskipwh(linebuf); 219 } 220 donewline(); 221 222 /* 223 * If overstrike then have to HARDOPEN 224 * else if can move cursor up off current line can use CRTOPEN (~~vi1) 225 * otherwise have to use ONEOPEN (like adm3) 226 */ 227 if (over_strike && !erase_overstrike) 228 bastate = HARDOPEN; 229 else if (cursor_address || cursor_up) 230 bastate = CRTOPEN; 231 else 232 bastate = ONEOPEN; 233 setwind(); 234 235 /* 236 * To avoid bombing on glass-crt's when the line is too long 237 * pretend that such terminals are 160 columns wide. 238 * If a line is too wide for display, we will dynamically 239 * switch to hardcopy open mode. 240 */ 241 if (state != CRTOPEN) 242 WCOLS = TUBECOLS; 243 if (!inglobal) 244 savevis(); 245 vok(atube, 0); 246 if (state != CRTOPEN) 247 columns = WCOLS; 248 Outchar = vputchar; 249 f = ostart(); 250 if (state == CRTOPEN) { 251 if (outcol == UKCOL) 252 outcol = 0; 253 vmoveitup(1, 1); 254 } else 255 outline = destline = WBOT; 256 vshow(dot, NOLINE); 257 vnline(ic); 258 vmain(); 259 if (state != CRTOPEN) 260 vclean(); 261 Command = (unsigned char *)"open"; 262 ovend(f); 263 (void)signal(SIGWINCH, SIG_DFL); 264 } 265 266 void 267 ovbeg(void) 268 { 269 270 if (inopen) 271 error(gettext("Recursive open/visual not allowed")); 272 Vlines = lineDOL(); 273 fixzero(); 274 setdot(); 275 pastwh(); 276 dot = addr2; 277 } 278 279 void 280 ovend(ttymode f) 281 { 282 283 splitw++; 284 vgoto(WECHO, 0); 285 vclreol(); 286 vgoto(WECHO, 0); 287 holdcm = 0; 288 splitw = 0; 289 ostop(f); 290 setoutt(); 291 undvis(); 292 columns = OCOLUMNS; 293 inopen = 0; 294 flusho(); 295 netchHAD(Vlines); 296 } 297 298 /* 299 * Enter visual mode 300 */ 301 void 302 vop(void) 303 { 304 int c; 305 ttymode f; /* was register */ 306 extern unsigned char termtype[]; 307 308 if (!cursor_address && !cursor_up) { 309 if (initev) { 310 toopen: 311 if (generic_type) 312 merror(gettext("I don't know what kind of terminal you are on - all I have is '%s'."), termtype); 313 putNFL(); 314 merror(gettext("[Using open mode]")); 315 putNFL(); 316 oop(); 317 return; 318 } 319 error(gettext("Visual needs addressable cursor or upline capability")); 320 } 321 if (over_strike && !erase_overstrike) { 322 if (initev) 323 goto toopen; 324 error(gettext("Can't use visual on a terminal which overstrikes")); 325 } 326 if (!clear_screen) { 327 if (initev) 328 goto toopen; 329 error(gettext("Visual requires clear screen capability")); 330 } 331 if (!scroll_forward) { 332 if (initev) 333 goto toopen; 334 error(gettext("Visual requires scrolling")); 335 } 336 windowchg = 0; 337 (void)signal(SIGWINCH, winch); 338 ovbeg(); 339 bastate = VISUAL; 340 c = 0; 341 if (any(peekchar(), "+-^.")) 342 c = getchar(); 343 pastwh(); 344 vsetsiz(isdigit(peekchar()) ? getnum() : value(vi_WINDOW)); 345 setwind(); 346 donewline(); 347 vok(atube, 0); 348 if (!inglobal) 349 savevis(); 350 Outchar = vputchar; 351 vmoving = 0; 352 f = ostart(); 353 if (initev == 0) { 354 vcontext(dot, c); 355 vnline((unsigned char *)NOSTR); 356 } 357 vmain(); 358 Command = (unsigned char *)"visual"; 359 ovend(f); 360 (void)signal(SIGWINCH, SIG_DFL); 361 } 362 363 /* 364 * Hack to allow entry to visual with 365 * empty buffer since routines internally 366 * demand at least one line. 367 */ 368 void 369 fixzero(void) 370 { 371 372 if (dol == zero) { 373 bool ochng = chng; 374 375 vdoappend((unsigned char *)""); 376 if (!ochng) 377 sync(); 378 addr1 = addr2 = one; 379 } else if (addr2 == zero) 380 addr2 = one; 381 } 382 383 /* 384 * Save lines before visual between unddol and truedol. 385 * Accomplish this by throwing away current [unddol,truedol] 386 * and then saving all the lines in the buffer and moving 387 * unddol back to dol. Don't do this if in a global. 388 * 389 * If you do 390 * g/xxx/vi. 391 * and then do a 392 * :e xxxx 393 * at some point, and then quit from the visual and undo 394 * you get the old file back. Somewhat weird. 395 */ 396 void 397 savevis(void) 398 { 399 400 if (inglobal) 401 return; 402 truedol = unddol; 403 saveall(); 404 unddol = dol; 405 undkind = UNDNONE; 406 } 407 408 /* 409 * Restore a sensible state after a visual/open, moving the saved 410 * stuff back to [unddol,dol], and killing the partial line kill indicators. 411 */ 412 void 413 undvis(void) 414 { 415 416 if (ruptible) 417 signal(SIGINT, onintr); 418 squish(); 419 pkill[0] = pkill[1] = 0; 420 unddol = truedol; 421 unddel = zero; 422 undap1 = one; 423 undap2 = dol + 1; 424 undkind = UNDALL; 425 if (undadot <= zero || undadot > dol) 426 undadot = zero+1; 427 } 428 429 /* 430 * Set the window parameters based on the base state bastate 431 * and the available buffer space. 432 */ 433 void 434 setwind(void) 435 { 436 437 WCOLS = columns; 438 switch (bastate) { 439 440 case ONEOPEN: 441 if (auto_right_margin) 442 WCOLS--; 443 /* fall into ... */ 444 445 case HARDOPEN: 446 basWTOP = WTOP = WBOT = WECHO = 0; 447 ZERO = 0; 448 holdcm++; 449 break; 450 451 case CRTOPEN: 452 basWTOP = lines - 2; 453 /* fall into */ 454 455 case VISUAL: 456 ZERO = lines - TUBESIZE / WCOLS; 457 if (ZERO < 0) 458 ZERO = 0; 459 if (ZERO > basWTOP) 460 error(gettext("Screen too large for internal buffer")); 461 WTOP = basWTOP; WBOT = lines - 2; WECHO = lines - 1; 462 break; 463 } 464 state = bastate; 465 basWLINES = WLINES = WBOT - WTOP + 1; 466 } 467 468 /* 469 * Can we hack an open/visual on this terminal? 470 * If so, then divide the screen buffer up into lines, 471 * and initialize a bunch of state variables before we start. 472 */ 473 static unsigned char vlinebuf[LBSIZE]; 474 475 void 476 vok(wchar_t *atube, int undo) 477 { 478 int i; 479 static int beenhere; 480 481 if (WCOLS == 1000) 482 serror((unsigned char *) 483 gettext("Don't know enough about your terminal to use %s"), 484 Command); 485 if (WCOLS > TUBECOLS) 486 error(gettext("Terminal too wide")); 487 if (WLINES >= TUBELINES || WCOLS * (WECHO - ZERO + 1) > TUBESIZE) 488 error(gettext("Screen too large")); 489 490 vtube0 = atube; 491 if(beenhere) 492 vclrbyte(atube, WCOLS * (WECHO - ZERO + 1)); 493 for (i = 0; i < ZERO; i++) 494 vtube[i] = (wchar_t *) 0; 495 for (; i <= WECHO; i++) 496 vtube[i] = atube, atube += WCOLS; 497 if(beenhere++) { 498 for (; i < TUBELINES; i++) 499 vtube[i] = (wchar_t *) 0; 500 } 501 vutmp = vlinebuf; 502 if(!undo) { 503 vundkind = VNONE; 504 vUNDdot = 0; 505 } 506 OCOLUMNS = columns; 507 inopen = 1; 508 #ifdef CBREAK 509 signal(SIGINT, vintr); 510 #endif 511 vmoving = 0; 512 splitw = 0; 513 doomed = 0; 514 holdupd = 0; 515 if(!undo) 516 Peekkey = 0; 517 vcnt = vcline = 0; 518 if (vSCROLL == 0) 519 vSCROLL = value(vi_SCROLL); 520 } 521 522 #ifdef CBREAK 523 /*ARGSUSED*/ 524 void 525 #ifdef __STDC__ 526 vintr(int sig) 527 #else 528 vintr(sig) 529 int sig; 530 #endif 531 { 532 533 signal(SIGINT, vintr); 534 if (vcatch) 535 onintr(0); 536 ungetkey(ATTN); 537 draino(); 538 } 539 #endif 540 541 /* 542 * Set the size of the screen to size lines, to take effect the 543 * next time the screen is redrawn. 544 */ 545 void 546 vsetsiz(int size) 547 { 548 int b; 549 550 if (bastate != VISUAL) 551 return; 552 b = lines - 1 - size; 553 if (b >= lines - 1) 554 b = lines - 2; 555 if (b < 0) 556 b = 0; 557 basWTOP = b; 558 basWLINES = WBOT - b + 1; 559 } 560