1 /* 2 * Copyright (c) 1981, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)refresh.c 8.7 (Berkeley) 08/13/94"; 10 #endif /* not lint */ 11 12 #include <string.h> 13 14 #include "curses.h" 15 16 static int curwin; 17 static short ly, lx; 18 19 static void domvcur __P((int, int, int, int)); 20 static int makech __P((WINDOW *, int)); 21 static void quickch __P((WINDOW *)); 22 static void scrolln __P((WINDOW *, int, int, int, int, int)); 23 24 /* 25 * wrefresh -- 26 * Make the current screen look like "win" over the area coverd by 27 * win. 28 */ 29 int 30 wrefresh(win) 31 register WINDOW *win; 32 { 33 register __LINE *wlp; 34 register int retval; 35 register short wy; 36 int dnum; 37 38 /* Initialize loop parameters. */ 39 ly = curscr->cury; 40 lx = curscr->curx; 41 wy = 0; 42 curwin = (win == curscr); 43 44 if (!curwin) 45 for (wy = 0; wy < win->maxy; wy++) { 46 wlp = win->lines[wy]; 47 if (wlp->flags & __ISDIRTY) 48 wlp->hash = __hash((char *)wlp->line, 49 win->maxx * __LDATASIZE); 50 } 51 52 if (win->flags & __CLEAROK || curscr->flags & __CLEAROK || curwin) { 53 if ((win->flags & __FULLWIN) || curscr->flags & __CLEAROK) { 54 tputs(CL, 0, __cputchar); 55 ly = 0; 56 lx = 0; 57 if (!curwin) { 58 curscr->flags &= ~__CLEAROK; 59 curscr->cury = 0; 60 curscr->curx = 0; 61 werase(curscr); 62 } 63 __touchwin(win); 64 } 65 win->flags &= ~__CLEAROK; 66 } 67 if (!CA) { 68 if (win->curx != 0) 69 putchar('\n'); 70 if (!curwin) 71 werase(curscr); 72 } 73 #ifdef DEBUG 74 __CTRACE("wrefresh: (%0.2o): curwin = %d\n", win, curwin); 75 __CTRACE("wrefresh: \tfirstch\tlastch\n"); 76 #endif 77 78 #ifndef NOQCH 79 if ((win->flags & __FULLWIN) && !curwin) { 80 /* 81 * Invoke quickch() only if more than a quarter of the lines 82 * in the window are dirty. 83 */ 84 for (wy = 0, dnum = 0; wy < win->maxy; wy++) 85 if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT)) 86 dnum++; 87 if (!__noqch && dnum > (int) win->maxy / 4) 88 quickch(win); 89 } 90 #endif 91 92 #ifdef DEBUG 93 { int i, j; 94 __CTRACE("#####################################\n"); 95 for (i = 0; i < curscr->maxy; i++) { 96 __CTRACE("C: %d:", i); 97 __CTRACE(" 0x%x \n", curscr->lines[i]->hash); 98 for (j = 0; j < curscr->maxx; j++) 99 __CTRACE("%c", 100 curscr->lines[i]->line[j].ch); 101 __CTRACE("\n"); 102 for (j = 0; j < curscr->maxx; j++) 103 __CTRACE("%x", 104 curscr->lines[i]->line[j].attr); 105 __CTRACE("\n"); 106 __CTRACE("W: %d:", i); 107 __CTRACE(" 0x%x \n", win->lines[i]->hash); 108 __CTRACE(" 0x%x ", win->lines[i]->flags); 109 for (j = 0; j < win->maxx; j++) 110 __CTRACE("%c", 111 win->lines[i]->line[j].ch); 112 __CTRACE("\n"); 113 for (j = 0; j < win->maxx; j++) 114 __CTRACE("%x", 115 win->lines[i]->line[j].attr); 116 __CTRACE("\n"); 117 } 118 } 119 #endif /* DEBUG */ 120 121 for (wy = 0; wy < win->maxy; wy++) { 122 #ifdef DEBUG 123 __CTRACE("%d\t%d\t%d\n", 124 wy, *win->lines[wy]->firstchp, *win->lines[wy]->lastchp); 125 #endif 126 if (!curwin) 127 curscr->lines[wy]->hash = win->lines[wy]->hash; 128 if (win->lines[wy]->flags & (__ISDIRTY | __FORCEPAINT)) { 129 if (makech(win, wy) == ERR) 130 return (ERR); 131 else { 132 if (*win->lines[wy]->firstchp >= win->ch_off) 133 *win->lines[wy]->firstchp = win->maxx + 134 win->ch_off; 135 if (*win->lines[wy]->lastchp < win->maxx + 136 win->ch_off) 137 *win->lines[wy]->lastchp = win->ch_off; 138 if (*win->lines[wy]->lastchp < 139 *win->lines[wy]->firstchp) { 140 #ifdef DEBUG 141 __CTRACE("wrefresh: line %d notdirty \n", wy); 142 #endif 143 win->lines[wy]->flags &= ~__ISDIRTY; 144 } 145 } 146 147 } 148 #ifdef DEBUG 149 __CTRACE("\t%d\t%d\n", *win->lines[wy]->firstchp, 150 *win->lines[wy]->lastchp); 151 #endif 152 } 153 154 #ifdef DEBUG 155 __CTRACE("refresh: ly=%d, lx=%d\n", ly, lx); 156 #endif 157 158 if (win == curscr) 159 domvcur(ly, lx, win->cury, win->curx); 160 else { 161 if (win->flags & __LEAVEOK) { 162 curscr->cury = ly; 163 curscr->curx = lx; 164 ly -= win->begy; 165 lx -= win->begx; 166 if (ly >= 0 && ly < win->maxy && lx >= 0 && 167 lx < win->maxx) { 168 win->cury = ly; 169 win->curx = lx; 170 } else 171 win->cury = win->curx = 0; 172 } else { 173 domvcur(ly, lx, win->cury + win->begy, 174 win->curx + win->begx); 175 curscr->cury = win->cury + win->begy; 176 curscr->curx = win->curx + win->begx; 177 } 178 } 179 retval = OK; 180 181 (void)fflush(stdout); 182 return (retval); 183 } 184 185 /* 186 * makech -- 187 * Make a change on the screen. 188 */ 189 static int 190 makech(win, wy) 191 register WINDOW *win; 192 int wy; 193 { 194 static __LDATA blank = {' ', 0}; 195 __LDATA *nsp, *csp, *cp, *cep; 196 u_int force; 197 int clsp, nlsp; /* Last space in lines. */ 198 int lch, wx, y; 199 char *ce; 200 201 /* Is the cursor still on the end of the last line? */ 202 if (wy > 0 && win->lines[wy - 1]->flags & __ISPASTEOL) { 203 domvcur(ly, lx, ly + 1, 0); 204 ly++; 205 lx = 0; 206 } 207 wx = *win->lines[wy]->firstchp - win->ch_off; 208 if (wx < 0) 209 wx = 0; 210 else if (wx >= win->maxx) 211 return (OK); 212 lch = *win->lines[wy]->lastchp - win->ch_off; 213 if (lch < 0) 214 return (OK); 215 else if (lch >= (int) win->maxx) 216 lch = win->maxx - 1; 217 y = wy + win->begy; 218 219 if (curwin) 220 csp = ␣ 221 else 222 csp = &curscr->lines[wy + win->begy]->line[wx + win->begx]; 223 224 nsp = &win->lines[wy]->line[wx]; 225 force = win->lines[wy]->flags & __FORCEPAINT; 226 win->lines[wy]->flags &= ~__FORCEPAINT; 227 if (CE && !curwin) { 228 for (cp = &win->lines[wy]->line[win->maxx - 1]; 229 cp->ch == ' ' && cp->attr == 0; cp--) 230 if (cp <= win->lines[wy]->line) 231 break; 232 nlsp = cp - win->lines[wy]->line; 233 } 234 if (!curwin) 235 ce = CE; 236 else 237 ce = NULL; 238 239 if (force) { 240 if (CM) 241 tputs(tgoto(CM, lx, ly), 0, __cputchar); 242 else { 243 tputs(HO, 0, __cputchar); 244 __mvcur(0, 0, ly, lx, 1); 245 } 246 } 247 248 while (wx <= lch) { 249 if (!force && memcmp(nsp, csp, sizeof(__LDATA)) == 0) { 250 if (wx <= lch) { 251 while (wx <= lch && 252 memcmp(nsp, csp, sizeof(__LDATA)) == 0) { 253 nsp++; 254 if (!curwin) 255 ++csp; 256 ++wx; 257 } 258 continue; 259 } 260 break; 261 } 262 domvcur(ly, lx, y, wx + win->begx); 263 264 #ifdef DEBUG 265 __CTRACE("makech: 1: wx = %d, ly= %d, lx = %d, newy = %d, newx = %d, force =%d\n", 266 wx, ly, lx, y, wx + win->begx, force); 267 #endif 268 ly = y; 269 lx = wx + win->begx; 270 while ((force || memcmp(nsp, csp, sizeof(__LDATA)) != 0) 271 && wx <= lch) { 272 273 if (ce != NULL && 274 win->maxx + win->begx == curscr->maxx && 275 wx >= nlsp && nsp->ch == ' ' && nsp->attr == 0) { 276 /* Check for clear to end-of-line. */ 277 cep = &curscr->lines[wy]->line[win->maxx - 1]; 278 while (cep->ch == ' ' && cep->attr == 0) 279 if (cep-- <= csp) 280 break; 281 clsp = cep - curscr->lines[wy]->line - 282 win->begx * __LDATASIZE; 283 #ifdef DEBUG 284 __CTRACE("makech: clsp = %d, nlsp = %d\n", clsp, nlsp); 285 #endif 286 if ((clsp - nlsp >= strlen(CE) 287 && clsp < win->maxx * __LDATASIZE) || 288 wy == win->maxy - 1) { 289 if (curscr->flags & __WSTANDOUT) { 290 tputs(SE, 0, __cputchar); 291 curscr->flags &= ~__WSTANDOUT; 292 } 293 tputs(CE, 0, __cputchar); 294 lx = wx + win->begx; 295 while (wx++ <= clsp) { 296 csp->ch = ' '; 297 csp->attr = 0; 298 csp++; 299 } 300 return (OK); 301 } 302 ce = NULL; 303 } 304 305 /* 306 * Enter/exit standout mode as appropriate. 307 * XXX 308 * Should use UC if SO/SE not available. 309 */ 310 if (nsp->attr & __STANDOUT) { 311 if (!(curscr->flags & __WSTANDOUT) && 312 SO != NULL && SE != NULL) { 313 tputs(SO, 0, __cputchar); 314 curscr->flags |= __WSTANDOUT; 315 } 316 } else 317 if (curscr->flags & __WSTANDOUT && 318 SE != NULL) { 319 tputs(SE, 0, __cputchar); 320 curscr->flags &= ~__WSTANDOUT; 321 } 322 323 wx++; 324 if (wx >= win->maxx && wy == win->maxy - 1 && !curwin) 325 if (win->flags & __SCROLLOK) { 326 if (curscr->flags & __WSTANDOUT 327 && win->flags & __ENDLINE) 328 if (!MS) { 329 tputs(SE, 0, 330 __cputchar); 331 curscr->flags &= 332 ~__WSTANDOUT; 333 } 334 if (!(win->flags & __SCROLLWIN)) { 335 if (!curwin) { 336 csp->attr = nsp->attr; 337 putchar(csp->ch = nsp->ch); 338 } else 339 putchar(nsp->ch); 340 } 341 if (wx + win->begx < curscr->maxx) { 342 domvcur(ly, wx + win->begx, 343 win->begy + win->maxy - 1, 344 win->begx + win->maxx - 1); 345 } 346 ly = win->begy + win->maxy - 1; 347 lx = win->begx + win->maxx - 1; 348 return (OK); 349 } 350 if (wx < win->maxx || wy < win->maxy - 1 || 351 !(win->flags & __SCROLLWIN)) { 352 if (!curwin) { 353 csp->attr = nsp->attr; 354 putchar(csp->ch = nsp->ch); 355 csp++; 356 } else 357 putchar(nsp->ch); 358 } 359 #ifdef DEBUG 360 __CTRACE("makech: putchar(%c)\n", nsp->ch & 0177); 361 #endif 362 if (UC && (nsp->attr & __STANDOUT)) { 363 putchar('\b'); 364 tputs(UC, 0, __cputchar); 365 } 366 nsp++; 367 #ifdef DEBUG 368 __CTRACE("makech: 2: wx = %d, lx = %d\n", wx, lx); 369 #endif 370 } 371 if (lx == wx + win->begx) /* If no change. */ 372 break; 373 lx = wx + win->begx; 374 if (lx >= COLS && AM) 375 lx = COLS - 1; 376 else if (wx >= win->maxx) { 377 domvcur(ly, lx, ly, win->maxx + win->begx - 1); 378 lx = win->maxx + win->begx - 1; 379 } 380 381 #ifdef DEBUG 382 __CTRACE("makech: 3: wx = %d, lx = %d\n", wx, lx); 383 #endif 384 } 385 386 /* Don't leave the screen in standout mode. */ 387 if (curscr->flags & __WSTANDOUT) { 388 tputs(SE, 0, __cputchar); 389 curscr->flags &= ~__WSTANDOUT; 390 } 391 return (OK); 392 } 393 394 /* 395 * domvcur -- 396 * Do a mvcur, leaving standout mode if necessary. 397 */ 398 static void 399 domvcur(oy, ox, ny, nx) 400 int oy, ox, ny, nx; 401 { 402 if (curscr->flags & __WSTANDOUT && !MS) { 403 tputs(SE, 0, __cputchar); 404 curscr->flags &= ~__WSTANDOUT; 405 } 406 407 __mvcur(oy, ox, ny, nx, 1); 408 } 409 410 /* 411 * Quickch() attempts to detect a pattern in the change of the window 412 * in order to optimize the change, e.g., scroll n lines as opposed to 413 * repainting the screen line by line. 414 */ 415 416 static void 417 quickch(win) 418 WINDOW *win; 419 { 420 #define THRESH (int) win->maxy / 4 421 422 register __LINE *clp, *tmp1, *tmp2; 423 register int bsize, curs, curw, starts, startw, i, j; 424 int n, target, cur_period, bot, top, sc_region; 425 __LDATA buf[1024]; 426 u_int blank_hash; 427 428 /* 429 * Find how many lines from the top of the screen are unchanged. 430 */ 431 for (top = 0; top < win->maxy; top++) 432 if (win->lines[top]->flags & __FORCEPAINT || 433 win->lines[top]->hash != curscr->lines[top]->hash 434 || memcmp(win->lines[top]->line, 435 curscr->lines[top]->line, 436 win->maxx * __LDATASIZE) != 0) 437 break; 438 else 439 win->lines[top]->flags &= ~__ISDIRTY; 440 /* 441 * Find how many lines from bottom of screen are unchanged. 442 */ 443 for (bot = win->maxy - 1; bot >= 0; bot--) 444 if (win->lines[bot]->flags & __FORCEPAINT || 445 win->lines[bot]->hash != curscr->lines[bot]->hash 446 || memcmp(win->lines[bot]->line, 447 curscr->lines[bot]->line, 448 win->maxx * __LDATASIZE) != 0) 449 break; 450 else 451 win->lines[bot]->flags &= ~__ISDIRTY; 452 453 #ifdef NO_JERKINESS 454 /* 455 * If we have a bottom unchanged region return. Scrolling the 456 * bottom region up and then back down causes a screen jitter. 457 * This will increase the number of characters sent to the screen 458 * but it looks better. 459 */ 460 if (bot < win->maxy - 1) 461 return; 462 #endif /* NO_JERKINESS */ 463 464 /* 465 * Search for the largest block of text not changed. 466 * Invariants of the loop: 467 * - Startw is the index of the beginning of the examined block in win. 468 * - Starts is the index of the beginning of the examined block in 469 * curscr. 470 * - Curs is the index of one past the end of the exmined block in win. 471 * - Curw is the index of one past the end of the exmined block in 472 * curscr. 473 * - bsize is the current size of the examined block. 474 */ 475 for (bsize = bot - top; bsize >= THRESH; bsize--) { 476 for (startw = top; startw <= bot - bsize; startw++) 477 for (starts = top; starts <= bot - bsize; 478 starts++) { 479 for (curw = startw, curs = starts; 480 curs < starts + bsize; curw++, curs++) 481 if (win->lines[curw]->flags & 482 __FORCEPAINT || 483 (win->lines[curw]->hash != 484 curscr->lines[curs]->hash || 485 memcmp(win->lines[curw]->line, 486 curscr->lines[curs]->line, 487 win->maxx * __LDATASIZE) != 0)) 488 break; 489 if (curs == starts + bsize) 490 goto done; 491 } 492 } 493 done: 494 /* Did not find anything */ 495 if (bsize < THRESH) 496 return; 497 498 #ifdef DEBUG 499 __CTRACE("quickch:bsize=%d,starts=%d,startw=%d,curw=%d,curs=%d,top=%d,bot=%d\n", 500 bsize, starts, startw, curw, curs, top, bot); 501 #endif 502 503 /* 504 * Make sure that there is no overlap between the bottom and top 505 * regions and the middle scrolled block. 506 */ 507 if (bot < curs) 508 bot = curs - 1; 509 if (top > starts) 510 top = starts; 511 512 n = startw - starts; 513 514 #ifdef DEBUG 515 __CTRACE("#####################################\n"); 516 for (i = 0; i < curscr->maxy; i++) { 517 __CTRACE("C: %d:", i); 518 __CTRACE(" 0x%x \n", curscr->lines[i]->hash); 519 for (j = 0; j < curscr->maxx; j++) 520 __CTRACE("%c", 521 curscr->lines[i]->line[j].ch); 522 __CTRACE("\n"); 523 for (j = 0; j < curscr->maxx; j++) 524 __CTRACE("%x", 525 curscr->lines[i]->line[j].attr); 526 __CTRACE("\n"); 527 __CTRACE("W: %d:", i); 528 __CTRACE(" 0x%x \n", win->lines[i]->hash); 529 __CTRACE(" 0x%x ", win->lines[i]->flags); 530 for (j = 0; j < win->maxx; j++) 531 __CTRACE("%c", 532 win->lines[i]->line[j].ch); 533 __CTRACE("\n"); 534 for (j = 0; j < win->maxx; j++) 535 __CTRACE("%x", 536 win->lines[i]->line[j].attr); 537 __CTRACE("\n"); 538 } 539 #endif 540 541 /* So we don't have to call __hash() each time */ 542 for (i = 0; i < win->maxx; i++) { 543 buf[i].ch = ' '; 544 buf[i].attr = 0; 545 } 546 blank_hash = __hash((char *) buf, win->maxx * __LDATASIZE); 547 548 /* 549 * Perform the rotation to maintain the consistency of curscr. 550 * This is hairy since we are doing an *in place* rotation. 551 * Invariants of the loop: 552 * - I is the index of the current line. 553 * - Target is the index of the target of line i. 554 * - Tmp1 points to current line (i). 555 * - Tmp2 and points to target line (target); 556 * - Cur_period is the index of the end of the current period. 557 * (see below). 558 * 559 * There are 2 major issues here that make this rotation non-trivial: 560 * 1. Scrolling in a scrolling region bounded by the top 561 * and bottom regions determined (whose size is sc_region). 562 * 2. As a result of the use of the mod function, there may be a 563 * period introduced, i.e., 2 maps to 4, 4 to 6, n-2 to 0, and 564 * 0 to 2, which then causes all odd lines not to be rotated. 565 * To remedy this, an index of the end ( = beginning) of the 566 * current 'period' is kept, cur_period, and when it is reached, 567 * the next period is started from cur_period + 1 which is 568 * guaranteed not to have been reached since that would mean that 569 * all records would have been reached. (think about it...). 570 * 571 * Lines in the rotation can have 3 attributes which are marked on the 572 * line so that curscr is consistent with the visual screen. 573 * 1. Not dirty -- lines inside the scrolled block, top region or 574 * bottom region. 575 * 2. Blank lines -- lines in the differential of the scrolling 576 * region adjacent to top and bot regions 577 * depending on scrolling direction. 578 * 3. Dirty line -- all other lines are marked dirty. 579 */ 580 sc_region = bot - top + 1; 581 i = top; 582 tmp1 = curscr->lines[top]; 583 cur_period = top; 584 for (j = top; j <= bot; j++) { 585 target = (i - top + n + sc_region) % sc_region + top; 586 tmp2 = curscr->lines[target]; 587 curscr->lines[target] = tmp1; 588 /* Mark block as clean and blank out scrolled lines. */ 589 clp = curscr->lines[target]; 590 #ifdef DEBUG 591 __CTRACE("quickch: n=%d startw=%d curw=%d i = %d target=%d ", 592 n, startw, curw, i, target); 593 #endif 594 if ((target >= startw && target < curw) || target < top 595 || target > bot) { 596 #ifdef DEBUG 597 __CTRACE("-- notdirty"); 598 #endif 599 win->lines[target]->flags &= ~__ISDIRTY; 600 } else if ((n > 0 && target >= top && target < top + n) || 601 (n < 0 && target <= bot && target > bot + n)) { 602 if (clp->hash != blank_hash || memcmp(clp->line, 603 buf, win->maxx * __LDATASIZE) !=0) { 604 (void)memcpy(clp->line, buf, 605 win->maxx * __LDATASIZE); 606 #ifdef DEBUG 607 __CTRACE("-- blanked out: dirty"); 608 #endif 609 clp->hash = blank_hash; 610 __touchline(win, target, 0, win->maxx - 1, 0); 611 } else { 612 __touchline(win, target, 0, win->maxx - 1, 0); 613 #ifdef DEBUG 614 __CTRACE(" -- blank line already: dirty"); 615 #endif 616 } 617 } else { 618 #ifdef DEBUG 619 __CTRACE(" -- dirty"); 620 #endif 621 __touchline(win, target, 0, win->maxx - 1, 0); 622 } 623 #ifdef DEBUG 624 __CTRACE("\n"); 625 #endif 626 if (target == cur_period) { 627 i = target + 1; 628 tmp1 = curscr->lines[i]; 629 cur_period = i; 630 } else { 631 tmp1 = tmp2; 632 i = target; 633 } 634 } 635 #ifdef DEBUG 636 __CTRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n"); 637 for (i = 0; i < curscr->maxy; i++) { 638 __CTRACE("C: %d:", i); 639 for (j = 0; j < curscr->maxx; j++) 640 __CTRACE("%c", 641 curscr->lines[i]->line[j].ch); 642 __CTRACE("\n"); 643 __CTRACE("W: %d:", i); 644 for (j = 0; j < win->maxx; j++) 645 __CTRACE("%c", win->lines[i]->line[j].ch); 646 __CTRACE("\n"); 647 } 648 #endif 649 if (n != 0) { 650 WINDOW *wp; 651 scrolln(win, starts, startw, curs, bot, top); 652 /* 653 * Need to repoint any subwindow lines to the rotated 654 * line structured. 655 */ 656 for (wp = win->nextp; wp != win; wp = wp->nextp) 657 __set_subwin(win, wp); 658 } 659 } 660 661 /* 662 * scrolln -- 663 * Scroll n lines, where n is starts - startw. 664 */ 665 static void 666 scrolln(win, starts, startw, curs, bot, top) 667 WINDOW *win; 668 int starts, startw, curs, bot, top; 669 { 670 int i, oy, ox, n; 671 672 oy = curscr->cury; 673 ox = curscr->curx; 674 n = starts - startw; 675 676 /* 677 * XXX 678 * The initial tests that set __noqch don't let us reach here unless 679 * we have either CS + HO + SF/sf/SR/sr, or AL + DL. SF/sf and SR/sr 680 * scrolling can only shift the entire scrolling region, not just a 681 * part of it, which means that the quickch() routine is going to be 682 * sadly disappointed in us if we don't have CS as well. 683 * 684 * If CS, HO and SF/sf are set, can use the scrolling region. Because 685 * the cursor position after CS is undefined, we need HO which gives us 686 * the ability to move to somewhere without knowledge of the current 687 * location of the cursor. Still call __mvcur() anyway, to update its 688 * idea of where the cursor is. 689 * 690 * When the scrolling region has been set, the cursor has to be at the 691 * last line of the region to make the scroll happen. 692 * 693 * Doing SF/SR or AL/DL appears faster on the screen than either sf/sr 694 * or al/dl, and, some terminals have AL/DL, sf/sr, and CS, but not 695 * SF/SR. So, if we're scrolling almost all of the screen, try and use 696 * AL/DL, otherwise use the scrolling region. The "almost all" is a 697 * shameless hack for vi. 698 */ 699 if (n > 0) { 700 if (CS != NULL && HO != NULL && (SF != NULL || 701 (AL == NULL || DL == NULL || 702 top > 3 || bot + 3 < win->maxy) && sf != NULL)) { 703 tputs(__tscroll(CS, top, bot + 1), 0, __cputchar); 704 __mvcur(oy, ox, 0, 0, 1); 705 tputs(HO, 0, __cputchar); 706 __mvcur(0, 0, bot, 0, 1); 707 if (SF != NULL) 708 tputs(__tscroll(SF, n, 0), 0, __cputchar); 709 else 710 for (i = 0; i < n; i++) 711 tputs(sf, 0, __cputchar); 712 tputs(__tscroll(CS, 0, win->maxy), 0, __cputchar); 713 __mvcur(bot, 0, 0, 0, 1); 714 tputs(HO, 0, __cputchar); 715 __mvcur(0, 0, oy, ox, 1); 716 return; 717 } 718 719 /* Scroll up the block. */ 720 if (SF != NULL && top == 0) { 721 __mvcur(oy, ox, bot, 0, 1); 722 tputs(__tscroll(SF, n, 0), 0, __cputchar); 723 } else if (DL != NULL) { 724 __mvcur(oy, ox, top, 0, 1); 725 tputs(__tscroll(DL, n, 0), 0, __cputchar); 726 } else if (dl != NULL) { 727 __mvcur(oy, ox, top, 0, 1); 728 for (i = 0; i < n; i++) 729 tputs(dl, 0, __cputchar); 730 } else if (sf != NULL && top == 0) { 731 __mvcur(oy, ox, bot, 0, 1); 732 for (i = 0; i < n; i++) 733 tputs(sf, 0, __cputchar); 734 } else 735 abort(); 736 737 /* Push down the bottom region. */ 738 __mvcur(top, 0, bot - n + 1, 0, 1); 739 if (AL != NULL) 740 tputs(__tscroll(AL, n, 0), 0, __cputchar); 741 else if (al != NULL) 742 for (i = 0; i < n; i++) 743 tputs(al, 0, __cputchar); 744 else 745 abort(); 746 __mvcur(bot - n + 1, 0, oy, ox, 1); 747 } else { 748 /* 749 * !!! 750 * n < 0 751 * 752 * If CS, HO and SR/sr are set, can use the scrolling region. 753 * See the above comments for details. 754 */ 755 if (CS != NULL && HO != NULL && (SR != NULL || 756 (AL == NULL || DL == NULL || 757 top > 3 || bot + 3 < win->maxy) && sr != NULL)) { 758 tputs(__tscroll(CS, top, bot + 1), 0, __cputchar); 759 __mvcur(oy, ox, 0, 0, 1); 760 tputs(HO, 0, __cputchar); 761 __mvcur(0, 0, top, 0, 1); 762 763 if (SR != NULL) 764 tputs(__tscroll(SR, -n, 0), 0, __cputchar); 765 else 766 for (i = n; i < 0; i++) 767 tputs(sr, 0, __cputchar); 768 tputs(__tscroll(CS, 0, win->maxy), 0, __cputchar); 769 __mvcur(top, 0, 0, 0, 1); 770 tputs(HO, 0, __cputchar); 771 __mvcur(0, 0, oy, ox, 1); 772 return; 773 } 774 775 /* Preserve the bottom lines. */ 776 __mvcur(oy, ox, bot + n + 1, 0, 1); 777 if (SR != NULL && bot == win->maxy) 778 tputs(__tscroll(SR, -n, 0), 0, __cputchar); 779 else if (DL != NULL) 780 tputs(__tscroll(DL, -n, 0), 0, __cputchar); 781 else if (dl != NULL) 782 for (i = n; i < 0; i++) 783 tputs(dl, 0, __cputchar); 784 else if (sr != NULL && bot == win->maxy) 785 for (i = n; i < 0; i++) 786 tputs(sr, 0, __cputchar); 787 else 788 abort(); 789 790 /* Scroll the block down. */ 791 __mvcur(bot + n + 1, 0, top, 0, 1); 792 if (AL != NULL) 793 tputs(__tscroll(AL, -n, 0), 0, __cputchar); 794 else if (al != NULL) 795 for (i = n; i < 0; i++) 796 tputs(al, 0, __cputchar); 797 else 798 abort(); 799 __mvcur(top, 0, oy, ox, 1); 800 } 801 } 802