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 2000 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_tune.h" 37 #include "ex_tty.h" 38 #include "ex_vis.h" 39 40 /* 41 * Routines to deal with management of logical versus physical 42 * display, opening and redisplaying lines on the screen, and 43 * use of intelligent terminal operations. Routines to deal with 44 * screen cleanup after a change. 45 */ 46 47 /* 48 * Display a new line at physical line p, returning 49 * the depth of the newly displayed line. We may decide 50 * to expand the window on an intelligent terminal if it is 51 * less than a full screen by deleting a line above the top of the 52 * window before doing an insert line to keep all the good text 53 * on the screen in which case the line may actually end up 54 * somewhere other than line p. 55 */ 56 vopen(tp, p) 57 line *tp; 58 int p; 59 { 60 register int cnt; 61 register struct vlinfo *vp, *vpc; 62 63 #ifdef ADEBUG 64 if (trace != NULL) 65 tfixnl(), fprintf(trace, "vopen(%d, %d)\n", lineno(tp), p); 66 #endif 67 if (state != VISUAL) { 68 if (vcnt) 69 if (hold & HOLDROL) 70 vup1(); 71 else 72 vclean(); 73 74 /* 75 * Forget all that we once knew. 76 */ 77 vcnt = vcline = 0; 78 p = WBOT; LASTLINE = WBOT + 1; 79 state = bastate; 80 WTOP = basWTOP; 81 WLINES = basWLINES; 82 } 83 vpc = &vlinfo[vcline]; 84 for (vp = &vlinfo[vcnt]; vp >= vpc; vp--) 85 vlcopy(vp[1], vp[0]); 86 vcnt++; 87 if (Pline == numbline) 88 /* 89 * Dirtying all the lines is rather inefficient 90 * internally, but number mode is used rarely 91 * and so it's not worth optimizing. 92 */ 93 vdirty(vcline+1, WECHO); 94 getline(*tp); 95 96 /* 97 * If we are opening at the top of the window, can try a window 98 * expansion at the top. 99 */ 100 if (state == VISUAL && vcline == 0 && vcnt > 1 && p > ZERO) { 101 cnt = p + vdepth() - LINE(1); 102 if (cnt > 0) { 103 p -= cnt; 104 if (p < ZERO) 105 p = ZERO; 106 WTOP = p; 107 WLINES = WBOT - WTOP + 1; 108 } 109 } 110 vpc->vliny = p, vpc->vdepth = 0, vpc->vflags = 0; 111 cnt = vreopen(p, lineno(tp), vcline); 112 if (vcline + 1 == vcnt) 113 LINE(vcnt) = LINE(vcline) + cnt; 114 } 115 116 /* 117 * Redisplay logical line l at physical line p with line number lineno. 118 */ 119 vreopen(p, lineno, l) 120 int p, lineno, l; 121 { 122 register int d; 123 register struct vlinfo *vp = &vlinfo[l]; 124 125 d = vp->vdepth; 126 if (d == 0 || (vp->vflags & VDIRT)) 127 vp->vdepth = d = vdepth(); 128 vp->vliny = p, vp->vflags &= ~VDIRT; 129 130 /* 131 * Try to win by making the screen larger rather than inserting 132 * a line and driving text off the bottom. 133 */ 134 p = vglitchup(l, 0); 135 136 /* 137 * BUG: Should consider using clr_eol here to clear to end of line. 138 * As it stands we always strike over the current text. 139 * Since often the current text is the same as what 140 * we are overstriking with, it tends not to show. 141 * On the other hand if it is different and we end up 142 * spacing out a lot of text, we could have won with 143 * a clr_eol. This is probably worthwhile at low speed 144 * only however, since clearly computation will be 145 * necessary to determine which way to go. 146 */ 147 vigoto(p, 0); 148 pline(lineno); 149 150 if (state == VISUAL && l == vcline && vp->vliny < 0) { 151 vp->vliny = 0; 152 vscrap(); 153 return d; 154 } 155 156 /* 157 * When we are typing part of a line for hardcopy open, don't 158 * want to type the '$' marking an end of line if in list mode. 159 */ 160 if (hold & HOLDDOL) 161 return (d); 162 if (Putchar == listchar) 163 putchar('$'); 164 165 /* 166 * Optimization of cursor motion may prevent screen rollup if the 167 * line has blanks/tabs at the end unless we force the cursor to appear 168 * on the last line segment. 169 */ 170 if (vp->vliny + d - 1 > WBOT) 171 vcsync(); 172 173 /* 174 * Switch into hardcopy open mode if we are in one line (adm3) 175 * open mode and this line is now too long. If in hardcopy 176 * open mode, then call sethard to move onto the next line 177 * with appropriate positioning. 178 */ 179 if (state == ONEOPEN) { 180 WCOLS = OCOLUMNS; 181 if (vdepth() > 1) { 182 WCOLS = TUBECOLS; 183 sethard(); 184 } else 185 WCOLS = TUBECOLS; 186 } else if (state == HARDOPEN) 187 sethard(); 188 189 /* 190 * Unless we filled (completely) the last line we typed on, 191 * we have to clear to the end of the line 192 * in case stuff is left from before. 193 */ 194 if (vp->vliny + d > destline) { 195 if (insert_null_glitch && destcol == WCOLS) 196 vigoto(vp->vliny + d - 1, 0); 197 vclreol(); 198 } 199 return (d); 200 } 201 202 /* 203 * Real work for winning growing of window at top 204 * when inserting in the middle of a partially full 205 * screen on an intelligent terminal. We have as argument 206 * the logical line number to be inserted after, and the offset 207 * from that line where the insert will go. 208 * We look at the picture of depths and positions, and if we can 209 * delete some (blank) lines from the top of the screen so that 210 * later inserts will not push stuff off the bottom. 211 */ 212 vglitchup(l, o) 213 int l, o; 214 { 215 register struct vlinfo *vp = &vlinfo[l]; 216 register int need; 217 register int p = vp->vliny; 218 short oldhold, oldheldech; 219 bool glitched = 0; 220 221 if (l < vcnt - 1) { 222 need = p + vp->vdepth - (vp+1)->vliny; 223 if (need > 0) { 224 if (state == VISUAL && WTOP - ZERO >= need && insert_line && delete_line) { 225 glitched++; 226 WTOP -= need; 227 WLINES = WBOT - WTOP + 1; 228 p -= need; 229 if (p + o == WTOP) { 230 vp->vliny = WTOP; 231 return (WTOP + o); 232 } 233 vdellin(WTOP, need, -1); 234 oldheldech = heldech; 235 oldhold = hold; 236 hold |= HOLDECH; 237 } 238 vinslin((vp+1)->vliny, need, l); 239 if (glitched) { 240 hold = oldhold; 241 heldech = oldheldech; 242 } 243 } 244 } else 245 vp[1].vliny = vp[0].vliny + vp->vdepth; 246 return (p + o); 247 } 248 249 /* 250 * Insert cnt blank lines before line p, 251 * logically and (if supported) physically. 252 */ 253 vinslin(p, cnt, l) 254 register int p, cnt; 255 int l; 256 { 257 register int i; 258 bool could = 1; 259 260 #ifdef ADEBUG 261 if (trace) 262 tfixnl(), fprintf(trace, "vinslin(%d, %d, %d)\n", p, cnt, l); 263 #endif 264 if (p + cnt > WBOT && clr_eos) { 265 /* 266 * Really quick -- clear to end of screen. 267 */ 268 cnt = WECHO + 1 - p; 269 vgoto(p, 0), vputp(clr_eos, cnt); 270 vclrech(1); 271 vadjAL(p, cnt); 272 } else if (scroll_reverse && p == WTOP && costSR < costAL) { 273 /* 274 * Use reverse scroll mode of the terminal, at 275 * the top of the window. Reverse linefeed works 276 * too, since we only use it from line WTOP. 277 */ 278 for (i = cnt; i > 0; i--) { 279 vgoto(p, 0), vputp(scroll_reverse, 0); 280 if (i > 1 && (hold & HOLDAT) == 0) 281 putchar('@'); 282 /* 283 * If we are at the top of the screen, and the 284 * terminal retains display above, then we 285 * should try to clear to end of line. 286 * Have to use clr_eol since we don't remember what is 287 * actually on the line. 288 */ 289 if (clr_eol && (memory_above || p != 0)) 290 vputp(clr_eol, 1); 291 } 292 vadjAL(p, cnt); 293 } else if (insert_line) { 294 /* 295 * Use insert line. 296 */ 297 vgoto(p, 0); 298 if (parm_insert_line && (cnt>1 || *insert_line==0)) { 299 /* insert cnt lines. Should do @'s too. */ 300 vputp(tparm(parm_insert_line, cnt, p), WECHO+1-p); 301 } 302 else if (change_scroll_region && *insert_line==0) { 303 /* vt100 change scrolling region to fake insert_line */ 304 vputp(save_cursor, 1); 305 vputp(tparm(change_scroll_region, p, lines-1), 1); 306 vputp(restore_cursor, 1); /* change_scroll_region homes stupid cursor */ 307 for (i=cnt; i>0; i--) 308 vputp(scroll_reverse, 1); /* should do @'s */ 309 vputp(tparm(change_scroll_region, 0, lines-1), 1); 310 vputp(restore_cursor, 1); /* Once again put it back */ 311 } 312 else { 313 vputp(insert_line, WECHO + 1 - p); 314 for (i = cnt - 1; i > 0; i--) { 315 vgoto(outline+1, 0); 316 vputp(insert_line, WECHO + 1 - outline); 317 if ((hold & HOLDAT) == 0) 318 putchar('@'); 319 } 320 } 321 vadjAL(p, cnt); 322 } else 323 could = 0; 324 vopenup(cnt, could, l); 325 } 326 327 /* 328 * Logically open up after line l, cnt of them. 329 * We need to know if it was done ``physically'' since in this 330 * case we accept what the hardware gives us. If we have to do 331 * it ourselves (brute force) we will squish out @ lines in the process 332 * if this will save us work. 333 */ 334 vopenup(cnt, could, l) 335 int cnt; 336 bool could; 337 { 338 register struct vlinfo *vc = &vlinfo[l + 1]; 339 register struct vlinfo *ve = &vlinfo[vcnt]; 340 341 #ifdef ADEBUG 342 if (trace) 343 tfixnl(), fprintf(trace, "vopenup(%d, %d, %d)\n", cnt, could, l); 344 #endif 345 if (could) 346 /* 347 * This will push @ lines down the screen, 348 * just as the hardware did. Since the default 349 * for intelligent terminals is to never have @ 350 * lines on the screen, this should never happen, 351 * and the code makes no special effort to be nice in this 352 * case, e.g. squishing out the @ lines by delete lines 353 * before doing append lines. 354 */ 355 for (; vc <= ve; vc++) 356 vc->vliny += cnt; 357 else { 358 /* 359 * Will have to clean up brute force eventually, 360 * so push the line data around as little as possible. 361 */ 362 vc->vliny += cnt, vc->vflags |= VDIRT; 363 while (vc < ve) { 364 register int i = vc->vliny + vc->vdepth; 365 366 vc++; 367 if (i <= vc->vliny) 368 break; 369 vc->vliny = i, vc->vflags |= VDIRT; 370 } 371 } 372 vscrap(); 373 } 374 375 /* 376 * Adjust data structure internally to account for insertion of 377 * blank lines on the screen. 378 */ 379 vadjAL(p, cnt) 380 int p, cnt; 381 { 382 wchar_t *tlines[TUBELINES]; 383 register int from, to; 384 385 #ifdef ADEBUG 386 if (trace) 387 tfixnl(), fprintf(trace, "vadjal(%d, %d)\n", p, cnt); 388 #endif 389 copy(tlines, vtube, sizeof vtube); /*SASSIGN*/ 390 for (from = p, to = p + cnt; to <= WECHO; from++, to++) 391 vtube[to] = tlines[from]; 392 for (to = p; from <= WECHO; from++, to++) { 393 vtube[to] = tlines[from]; 394 vclrbyte(vtube[to], WCOLS); 395 } 396 /* 397 * Have to clear the echo area since its contents aren't 398 * necessarily consistent with the rest of the display. 399 */ 400 vclrech(0); 401 } 402 403 /* 404 * Roll the screen up logically and physically 405 * so that line dl is the bottom line on the screen. 406 */ 407 vrollup(dl) 408 int dl; 409 { 410 register int cnt; 411 register int dc = destcol; 412 413 #ifdef ADEBUG 414 if (trace) 415 tfixnl(), fprintf(trace, "vrollup(%d)\n", dl); 416 #endif 417 cnt = dl - (splitw ? WECHO : WBOT); 418 if (splitw && (state == VISUAL || state == CRTOPEN)) 419 holdupd = 1; 420 vmoveitup(cnt, 1); 421 vscroll(cnt); 422 destline = dl - cnt, destcol = dc; 423 } 424 425 vup1() 426 { 427 428 vrollup(WBOT + 1); 429 } 430 431 /* 432 * Scroll the screen up cnt lines physically. 433 * If doclr is true, do a clear eol if the terminal 434 * has standout (to prevent it from scrolling up) 435 */ 436 vmoveitup(cnt, doclr) 437 register int cnt; 438 bool doclr; 439 { 440 441 if (cnt == 0) 442 return; 443 #ifdef ADEBUG 444 if (trace) 445 tfixnl(), fprintf(trace, "vmoveitup(%d)\n", cnt); 446 #endif 447 if (doclr) 448 vclrech(0); 449 if (scroll_forward) { 450 destline = WECHO; 451 destcol = (NONL ? 0 : outcol % WCOLS); 452 fgoto(); 453 while (cnt > 0) 454 vputp(scroll_forward, 0), cnt--; 455 } 456 else { 457 destline = WECHO + cnt; 458 destcol = (NONL ? 0 : outcol % WCOLS); 459 fgoto(); 460 if (state == ONEOPEN || state == HARDOPEN) { 461 outline = destline = 0; 462 vclrbyte(vtube[0], WCOLS); 463 } 464 } 465 /* Get rid of line we just rolled up */ 466 if (doclr && memory_below && clr_eol) 467 vclrech(0); 468 } 469 470 /* 471 * Scroll the screen up cnt lines logically. 472 */ 473 vscroll(cnt) 474 register int cnt; 475 { 476 register int from, to; 477 wchar_t *tlines[TUBELINES]; 478 479 #ifdef ADEBUG 480 if (trace) 481 fprintf(trace, "vscroll(%d)\n", cnt); 482 #endif 483 if (cnt < 0 || cnt > TUBELINES) 484 error(gettext("Internal error: vscroll")); 485 if (cnt == 0) 486 return; 487 copy(tlines, vtube, sizeof vtube); 488 for (to = ZERO, from = ZERO + cnt; to <= WECHO - cnt; to++, from++) 489 vtube[to] = tlines[from]; 490 for (from = ZERO; to <= WECHO; to++, from++) { 491 vtube[to] = tlines[from]; 492 vclrbyte(vtube[to], WCOLS); 493 } 494 for (from = 0; from <= vcnt; from++) 495 LINE(from) -= cnt; 496 } 497 498 /* 499 * Discard logical lines due to physical wandering off the screen. 500 */ 501 vscrap() 502 { 503 register int i, j; 504 505 #ifdef ADEBUG 506 if (trace) 507 tfixnl(), fprintf(trace, "vscrap\n"), tvliny(); 508 #endif 509 if (splitw) 510 return; 511 if (vcnt && WBOT != WECHO && LINE(0) < WTOP && LINE(0) >= ZERO) { 512 WTOP = LINE(0); 513 WLINES = WBOT - WTOP + 1; 514 } 515 for (j = 0; j < vcnt; j++) 516 if (LINE(j) >= WTOP) { 517 if (j == 0) 518 break; 519 /* 520 * Discard the first j physical lines off the top. 521 */ 522 vcnt -= j, vcline -= j; 523 for (i = 0; i <= vcnt; i++) 524 vlcopy(vlinfo[i], vlinfo[i + j]); 525 break; 526 } 527 /* 528 * Discard lines off the bottom. 529 */ 530 if (vcnt) { 531 for (j = 0; j <= vcnt; j++) 532 if (LINE(j) > WBOT || LINE(j) + DEPTH(j) - 1 > WBOT) { 533 vcnt = j; 534 break; 535 } 536 if (vcnt == 0) 537 LASTLINE = 0; 538 else 539 LASTLINE = LINE(vcnt-1) + DEPTH(vcnt-1); 540 } 541 #ifdef ADEBUG 542 if (trace) 543 tvliny(); 544 #endif 545 /* 546 * May have no lines! 547 */ 548 } 549 550 /* 551 * Repaint the screen, with cursor at curs, aftern an arbitrary change. 552 * Handle notification on large changes. 553 */ 554 vrepaint(curs) 555 unsigned char *curs; 556 { 557 558 wdot = NOLINE; 559 /* 560 * In open want to notify first. 561 */ 562 noteit(0); 563 vscrap(); 564 565 /* 566 * Deal with a totally useless display. 567 */ 568 if (vcnt == 0 || vcline < 0 || vcline > vcnt || holdupd && state != VISUAL) { 569 register line *odol = dol; 570 571 vcnt = 0; 572 if (holdupd) 573 if (state == VISUAL) 574 (void)peekkey(); 575 else 576 vup1(); 577 holdupd = 0; 578 if (odol == zero) 579 fixzero(); 580 vcontext(dot, '.'); 581 noteit(1); 582 if (noteit(1) == 0 && odol == zero) { 583 CATCH 584 error(gettext("No lines in buffer")); 585 ENDCATCH 586 linebuf[0] = 0; 587 splitw = 0; 588 } 589 vnline(curs); 590 return; 591 } 592 593 /* 594 * Have some useful displayed text; refresh it. 595 */ 596 getDOT(); 597 598 /* 599 * This is for boundary conditions in open mode. 600 */ 601 if (FLAGS(0) & VDIRT) 602 vsync(WTOP); 603 604 /* 605 * If the current line is after the last displayed line 606 * or the bottom of the screen, then special effort is needed 607 * to get it on the screen. We first try a redraw at the 608 * last line on the screen, hoping it will fill in where @ 609 * lines are now. If this doesn't work, then roll it onto 610 * the screen. 611 */ 612 if (vcline >= vcnt || LINE(vcline) > WBOT) { 613 short oldhold = hold; 614 hold |= HOLDAT, vredraw(LASTLINE), hold = oldhold; 615 if (vcline >= vcnt) { 616 register int i = vcline - vcnt + 1; 617 618 dot -= i; 619 vcline -= i; 620 vroll(i); 621 } else 622 vsyncCL(); 623 } else 624 vsync(vcline > 0 ? LINE(vcline - 1) : WTOP); 625 626 /* 627 * Notification on large change for visual 628 * has to be done last or we may lose 629 * the echo area with redisplay. 630 */ 631 noteit(1); 632 633 /* 634 * Finally. Move the cursor onto the current line. 635 */ 636 vnline(curs); 637 } 638 639 /* 640 * Fully cleanup the screen, leaving no @ lines except at end when 641 * line after last won't completely fit. The routine vsync is 642 * more conservative and much less work on dumb terminals. 643 */ 644 vredraw(p) 645 register int p; 646 { 647 register int l; 648 register line *tp; 649 unsigned char temp[LBSIZE]; 650 bool anydl = 0; 651 short oldhold = hold; 652 653 #ifdef ADEBUG 654 if (trace) 655 tfixnl(), fprintf(trace, "vredraw(%d)\n", p), tvliny(); 656 #endif 657 if (holdupd) { 658 holdupd = 3; 659 return; 660 } 661 if (state == HARDOPEN || splitw) 662 return; 663 if (p < 0 /* || p > WECHO */) 664 error(gettext("Internal error: vredraw")); 665 666 /* 667 * Trim the ragged edges (lines which are off the screen but 668 * not yet logically discarded), save the current line, and 669 * search for first logical line affected by the redraw. 670 */ 671 vscrap(); 672 CP(temp, linebuf); 673 l = 0; 674 tp = dot - vcline; 675 if (vcnt == 0) 676 LINE(0) = WTOP; 677 while (l < vcnt && LINE(l) < p) 678 l++, tp++; 679 680 /* 681 * We hold off echo area clearing during the redraw in deference 682 * to a final clear of the echo area at the end if appropriate. 683 */ 684 heldech = 0; 685 hold |= HOLDECH; 686 for (; l < vcnt && Peekkey != ATTN; l++) { 687 if (l == vcline) 688 strcLIN(temp); 689 else 690 getline(*tp); 691 692 /* 693 * Delete junk between displayed lines. 694 */ 695 if (LINE(l) != LINE(l + 1) && LINE(l) != p) { 696 if (anydl == 0 && memory_below && clr_eos) { 697 hold = oldhold; 698 vclrech(0); 699 anydl = 1; 700 hold |= HOLDECH; 701 heldech = 0; 702 } 703 vdellin(p, LINE(l) - p, l); 704 } 705 706 /* 707 * If line image is not know to be up to date, then 708 * redisplay it; else just skip onward. 709 */ 710 LINE(l) = p; 711 if (FLAGS(l) & VDIRT) { 712 DEPTH(l) = vdepth(); 713 if (l != vcline && p + DEPTH(l) - 1 > WBOT) { 714 vscrap(); 715 break; 716 } 717 FLAGS(l) &= ~VDIRT; 718 vreopen(p, lineno(tp), l); 719 p = LINE(l) + DEPTH(l); 720 } else 721 p += DEPTH(l); 722 tp++; 723 } 724 725 /* 726 * That takes care of lines which were already partially displayed. 727 * Now try to fill the rest of the screen with text. 728 */ 729 if (state == VISUAL && p <= WBOT) { 730 int ovcline = vcline; 731 732 vcline = l; 733 for (; tp <= dol && Peekkey != ATTN; tp++) { 734 getline(*tp); 735 if (p + vdepth() - 1 > WBOT) 736 break; 737 vopen(tp, p); 738 p += DEPTH(vcline); 739 vcline++; 740 } 741 vcline = ovcline; 742 } 743 744 /* 745 * That's all the text we can get on. 746 * Now rest of lines (if any) get either a ~ if they 747 * are past end of file, or an @ if the next line won't fit. 748 */ 749 for (; p <= WBOT && Peekkey != ATTN; p++) 750 vclrlin(p, tp); 751 strcLIN(temp); 752 hold = oldhold; 753 if (heldech) 754 vclrech(0); 755 #ifdef ADEBUG 756 if (trace) 757 tvliny(); 758 #endif 759 } 760 761 /* 762 * Do the real work in deleting cnt lines starting at line p from 763 * the display. First affected line is line l. 764 */ 765 vdellin(p, cnt, l) 766 int p, cnt, l; 767 { 768 register int i; 769 770 if (cnt == 0) 771 return; 772 if (delete_line == NOSTR || cnt < 0) { 773 /* 774 * Can't do it; just remember that line l is munged. 775 */ 776 FLAGS(l) |= VDIRT; 777 return; 778 } 779 #ifdef ADEBUG 780 if (trace) 781 tfixnl(), fprintf(trace, "vdellin(%d, %d, %d)\n", p, cnt, l); 782 #endif 783 /* 784 * Send the deletes to the screen and then adjust logical 785 * and physical internal data structures. 786 */ 787 vgoto(p, 0); 788 if (parm_delete_line && (cnt>1 || *delete_line==0)) { 789 vputp(tparm(parm_delete_line, cnt, p), WECHO-p); 790 } 791 else if (change_scroll_region && *delete_line==0) { 792 /* vt100: fake delete_line by changing scrolling region */ 793 vputp(save_cursor, 1); /* Save since change_scroll_region homes stupid cursor */ 794 vputp(tparm(change_scroll_region, p, lines-1), 1); 795 vputp(tparm(cursor_address, lines-1, 0), 1);/* Go to lower left corner */ 796 for (i=0; i<cnt; i++) /* .. and scroll cnt times */ 797 putch('\n'); /* should check NL too */ 798 vputp(tparm(change_scroll_region, 0, lines-1), 1);/* restore scrolling region */ 799 vputp(restore_cursor, 1); /* put cursor back */ 800 } 801 else { 802 for (i = 0; i < cnt; i++) 803 vputp(delete_line, WECHO - p); 804 } 805 vadjDL(p, cnt); 806 vcloseup(l, cnt); 807 } 808 /* 809 * Adjust internal physical screen image to account for deleted lines. 810 */ 811 vadjDL(p, cnt) 812 int p, cnt; 813 { 814 wchar_t *tlines[TUBELINES]; 815 register int from, to; 816 817 #ifdef ADEBUG 818 if (trace) 819 tfixnl(), fprintf(trace, "vadjDL(%d, %d)\n", p, cnt); 820 #endif 821 /* 822 * Would like to use structured assignment but early 823 * v7 compiler (released with phototypesetter for v6) 824 * can't hack it. 825 */ 826 copy(tlines, vtube, sizeof vtube); /*SASSIGN*/ 827 for (from = p + cnt, to = p; from <= WECHO; from++, to++) 828 vtube[to] = tlines[from]; 829 for (from = p; to <= WECHO; from++, to++) { 830 vtube[to] = tlines[from]; 831 vclrbyte(vtube[to], WCOLS); 832 } 833 } 834 /* 835 * Sync the screen, like redraw but more lazy and willing to leave 836 * @ lines on the screen. VsyncCL syncs starting at the current line. 837 * In any case, if the redraw option is set then all syncs map to redraws 838 * as if vsync didn't exist. 839 */ 840 vsyncCL() 841 { 842 843 vsync(LINE(vcline)); 844 } 845 846 vsync(p) 847 register int p; 848 { 849 850 if (value(vi_REDRAW)) 851 vredraw(p); 852 else 853 vsync1(p); 854 } 855 856 /* 857 * The guts of a sync. Similar to redraw but 858 * just less ambitious. 859 */ 860 vsync1(p) 861 register int p; 862 { 863 register int l; 864 unsigned char temp[LBSIZE]; 865 register struct vlinfo *vp = &vlinfo[0]; 866 short oldhold = hold; 867 868 #ifdef ADEBUG 869 if (trace) 870 tfixnl(), fprintf(trace, "vsync1(%d)\n", p), tvliny(); 871 #endif 872 if (holdupd) { 873 if (holdupd < 3) 874 holdupd = 2; 875 return; 876 } 877 if (state == HARDOPEN || splitw) 878 return; 879 vscrap(); 880 CP(temp, linebuf); 881 if (vcnt == 0) 882 LINE(0) = WTOP; 883 l = 0; 884 while (l < vcnt && vp->vliny < p) 885 l++, vp++; 886 heldech = 0; 887 hold |= HOLDECH; 888 while (p <= WBOT && Peekkey != ATTN) { 889 /* 890 * Want to put a line here if not in visual and first line 891 * or if there are lies left and this line starts before 892 * the current line, or if this line is piled under the 893 * next line (vreplace does this and we undo it). 894 */ 895 if (l == 0 && state != VISUAL || 896 (l < vcnt && (vp->vliny <= p || vp[0].vliny == vp[1].vliny))) { 897 if (l == 0 || vp->vliny < p || (vp->vflags & VDIRT)) { 898 if (l == vcline) 899 strcLIN(temp); 900 else 901 getline(dot[l - vcline]); 902 /* 903 * Be careful that a long line doesn't cause the 904 * screen to shoot up. 905 */ 906 if (l != vcline && (vp->vflags & VDIRT)) { 907 vp->vdepth = vdepth(); 908 vp->vflags &= ~VDIRT; 909 if (p + vp->vdepth - 1 > WBOT) 910 break; 911 } 912 vreopen(p, lineDOT() + (l - vcline), l); 913 } 914 p = vp->vliny + vp->vdepth; 915 vp++; 916 l++; 917 } else 918 /* 919 * A physical line between logical lines, 920 * so we settle for an @ at the beginning. 921 */ 922 vclrlin(p, dot + (l - vcline)), p++; 923 } 924 strcLIN(temp); 925 hold = oldhold; 926 if (heldech) 927 vclrech(0); 928 } 929 930 /* 931 * Subtract (logically) cnt physical lines from the 932 * displayed position of lines starting with line l. 933 */ 934 vcloseup(l, cnt) 935 int l; 936 register int cnt; 937 { 938 register int i; 939 940 #ifdef ADEBUG 941 if (trace) 942 tfixnl(), fprintf(trace, "vcloseup(%d, %d)\n", l, cnt); 943 #endif 944 for (i = l + 1; i <= vcnt; i++) 945 LINE(i) -= cnt; 946 } 947 948 /* 949 * Workhorse for rearranging line descriptors on changes. 950 * The idea here is that, starting with line l, cnt lines 951 * have been replaced with newcnt lines. All of these may 952 * be ridiculous, i.e. l may be -1000, cnt 50 and newcnt 0, 953 * since we may be called from an undo after the screen has 954 * moved a lot. Thus we have to be careful. 955 * 956 * Many boundary conditions here. 957 */ 958 vreplace(l, cnt, newcnt) 959 int l, cnt, newcnt; 960 { 961 register int from, to, i; 962 bool savenote = 0; 963 964 #ifdef ADEBUG 965 if (trace) { 966 tfixnl(), fprintf(trace, "vreplace(%d, %d, %d)\n", l, cnt, newcnt); 967 tvliny(); 968 } 969 #endif 970 if (l >= vcnt) 971 return; 972 if (l < 0) { 973 if (l + cnt < 0) { 974 /* 975 * Nothing on the screen is relevant. 976 * Settle for redrawing from scratch (later). 977 */ 978 vcnt = 0; 979 return; 980 } 981 /* 982 * Normalize l to top of screen; the add is 983 * really a subtract from cnt since l is negative. 984 */ 985 cnt += l; 986 l = 0; 987 988 /* 989 * Unseen lines were affected so notify (later). 990 */ 991 savenote++; 992 } 993 994 /* 995 * These shouldn't happen 996 * but would cause great havoc. 997 */ 998 if (cnt < 0) 999 cnt = 0; 1000 if (newcnt < 0) 1001 newcnt = 0; 1002 1003 /* 1004 * Surely worthy of note if more than report 1005 * lines were changed. 1006 */ 1007 if (cnt > value(vi_REPORT) || newcnt > value(vi_REPORT)) 1008 savenote++; 1009 1010 /* 1011 * Same number of lines affected as on screen, and we 1012 * can insert and delete lines. Thus we just type 1013 * over them, since otherwise we will push them 1014 * slowly off the screen, a clear lose. 1015 */ 1016 if (cnt == newcnt || vcnt - l == newcnt && insert_line && delete_line) { 1017 if (cnt > 1 && l + cnt > vcnt) 1018 savenote++; 1019 vdirty(l, newcnt); 1020 } else { 1021 /* 1022 * Lines are going away, squish them out. 1023 */ 1024 if (cnt > 0) { 1025 /* 1026 * If non-displayed lines went away, 1027 * always notify. 1028 */ 1029 if (cnt > 1 && l + cnt > vcnt) 1030 savenote++; 1031 if (l + cnt >= vcnt) 1032 cnt = vcnt - l; 1033 else 1034 for (from = l + cnt, to = l; from <= vcnt; to++, from++) 1035 vlcopy(vlinfo[to], vlinfo[from]); 1036 vcnt -= cnt; 1037 } 1038 /* 1039 * Open up space for new lines appearing. 1040 * All new lines are piled in the same place, 1041 * and will be unpiled by vredraw/vsync, which 1042 * inserts lines in front as it unpiles. 1043 */ 1044 if (newcnt > 0) { 1045 /* 1046 * Newlines are appearing which may not show, 1047 * so notify (this is only approximately correct 1048 * when long lines are present). 1049 */ 1050 if (newcnt > 1 && l + newcnt > vcnt + 1) 1051 savenote++; 1052 1053 /* 1054 * If there will be more lines than fit, then 1055 * just throw way the rest of the stuff on the screen. 1056 */ 1057 if (l + newcnt > WBOT && insert_line && delete_line) { 1058 vcnt = l; 1059 goto skip; 1060 } 1061 from = vcnt, to = vcnt + newcnt; 1062 i = TUBELINES - to; 1063 if (i < 0) 1064 from += i, to += i; 1065 vcnt = to; 1066 for (; from >= l; from--, to--) 1067 vlcopy(vlinfo[to], vlinfo[from]); 1068 for (from = to + 1, to = l; to < l + newcnt && to <= WBOT + 1; to++) { 1069 LINE(to) = LINE(from); 1070 DEPTH(to) = 0; 1071 FLAGS(to) = VDIRT; 1072 } 1073 } 1074 } 1075 skip: 1076 if (Pline == numbline && cnt != newcnt) 1077 /* 1078 * When lines positions are shifted, the numbers 1079 * will be wrong. 1080 */ 1081 vdirty(l, WECHO); 1082 if (!savenote) 1083 notecnt = 0; 1084 #ifdef ADEBUG 1085 if (trace) 1086 tvliny(); 1087 #endif 1088 } 1089 1090 /* 1091 * Start harcopy open. 1092 * Print an image of the line to the left of the cursor 1093 * under the full print of the line and position the cursor. 1094 * If we are in a scroll ^D within hardcopy open then all this 1095 * is suppressed. 1096 */ 1097 sethard() 1098 { 1099 1100 if (state == VISUAL) 1101 return; 1102 rubble = 0; 1103 state = HARDOPEN; 1104 if (hold & HOLDROL) 1105 return; 1106 vup1(); 1107 LINE(0) = WBOT; 1108 if (Pline == numbline) 1109 vgoto(WBOT, 0), printf("%6d ", lineDOT()); 1110 } 1111 1112 /* 1113 * Mark the lines starting at base for i lines 1114 * as dirty so that they will be checked for correct 1115 * display at next sync/redraw. 1116 */ 1117 vdirty(base, i) 1118 register int base, i; 1119 { 1120 register int l; 1121 1122 for (l = base; l < vcnt; l++) { 1123 if (--i < 0) 1124 return; 1125 FLAGS(l) |= VDIRT; 1126 } 1127 } 1128