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.5 (Berkeley) 08/10/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 = 49 __hash((char *) wlp->line, 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 && win->maxx + win->begx == 274 curscr->maxx && wx >= nlsp && nsp->ch == ' ') { 275 /* Check for clear to end-of-line. */ 276 cep = &curscr->lines[wy]->line[win->maxx - 1]; 277 while (cep->ch == ' ' && cep->attr == 0) 278 if (cep-- <= csp) 279 break; 280 clsp = cep - curscr->lines[wy]->line - 281 win->begx * __LDATASIZE; 282 #ifdef DEBUG 283 __CTRACE("makech: clsp = %d, nlsp = %d\n", clsp, nlsp); 284 #endif 285 if ((clsp - nlsp >= strlen(CE) 286 && clsp < win->maxx * __LDATASIZE) || 287 wy == win->maxy - 1) { 288 #ifdef DEBUG 289 __CTRACE("makech: using CE\n"); 290 #endif 291 tputs(CE, 0, __cputchar); 292 lx = wx + win->begx; 293 while (wx++ <= clsp) { 294 csp->ch = ' '; 295 csp->attr = 0; 296 csp++; 297 } 298 return (OK); 299 } 300 ce = NULL; 301 } 302 303 /* 304 * Enter/exit standout mode as appropriate. 305 * XXX 306 * Should use UC if SO/SE not available. 307 */ 308 if (nsp->attr & __STANDOUT) { 309 if (!(curscr->flags & __WSTANDOUT) && 310 SO != NULL && SE != NULL) { 311 tputs(SO, 0, __cputchar); 312 curscr->flags |= __WSTANDOUT; 313 } 314 } else 315 if (curscr->flags & __WSTANDOUT && 316 SE != NULL) { 317 tputs(SE, 0, __cputchar); 318 curscr->flags &= ~__WSTANDOUT; 319 } 320 321 wx++; 322 if (wx >= win->maxx && wy == win->maxy - 1 && !curwin) 323 if (win->flags & __SCROLLOK) { 324 if (curscr->flags & __WSTANDOUT 325 && win->flags & __ENDLINE) 326 if (!MS) { 327 tputs(SE, 0, 328 __cputchar); 329 curscr->flags &= 330 ~__WSTANDOUT; 331 } 332 if (!(win->flags & __SCROLLWIN)) { 333 if (!curwin) { 334 csp->attr = nsp->attr; 335 putchar(csp->ch = nsp->ch); 336 } else 337 putchar(nsp->ch); 338 } 339 if (wx + win->begx < curscr->maxx) { 340 domvcur(ly, wx + win->begx, 341 win->begy + win->maxy - 1, 342 win->begx + win->maxx - 1); 343 } 344 ly = win->begy + win->maxy - 1; 345 lx = win->begx + win->maxx - 1; 346 return (OK); 347 } 348 if (wx < win->maxx || wy < win->maxy - 1 || 349 !(win->flags & __SCROLLWIN)) { 350 if (!curwin) { 351 csp->attr = nsp->attr; 352 putchar(csp->ch = nsp->ch); 353 csp++; 354 } else 355 putchar(nsp->ch); 356 } 357 #ifdef DEBUG 358 __CTRACE("makech: putchar(%c)\n", nsp->ch & 0177); 359 #endif 360 if (UC && (nsp->attr & __STANDOUT)) { 361 putchar('\b'); 362 tputs(UC, 0, __cputchar); 363 } 364 nsp++; 365 #ifdef DEBUG 366 __CTRACE("makech: 2: wx = %d, lx = %d\n", wx, lx); 367 #endif 368 } 369 if (lx == wx + win->begx) /* If no change. */ 370 break; 371 lx = wx + win->begx; 372 if (lx >= COLS && AM) 373 lx = COLS - 1; 374 else if (wx >= win->maxx) { 375 domvcur(ly, lx, ly, win->maxx + win->begx - 1); 376 lx = win->maxx + win->begx - 1; 377 } 378 379 #ifdef DEBUG 380 __CTRACE("makech: 3: wx = %d, lx = %d\n", wx, lx); 381 #endif 382 } 383 return (OK); 384 } 385 386 /* 387 * domvcur -- 388 * Do a mvcur, leaving standout mode if necessary. 389 */ 390 static void 391 domvcur(oy, ox, ny, nx) 392 int oy, ox, ny, nx; 393 { 394 if (curscr->flags & __WSTANDOUT && !MS) { 395 tputs(SE, 0, __cputchar); 396 curscr->flags &= ~__WSTANDOUT; 397 } 398 399 __mvcur(oy, ox, ny, nx, 1); 400 } 401 402 /* 403 * Quickch() attempts to detect a pattern in the change of the window 404 * in order to optimize the change, e.g., scroll n lines as opposed to 405 * repainting the screen line by line. 406 */ 407 408 static void 409 quickch(win) 410 WINDOW *win; 411 { 412 #define THRESH (int) win->maxy / 4 413 414 register __LINE *clp, *tmp1, *tmp2; 415 register int bsize, curs, curw, starts, startw, i, j; 416 int n, target, cur_period, bot, top, sc_region; 417 __LDATA buf[1024]; 418 u_int blank_hash; 419 420 /* 421 * Find how many lines from the top of the screen are unchanged. 422 */ 423 for (top = 0; top < win->maxy; top++) 424 if (win->lines[top]->flags & __FORCEPAINT || 425 win->lines[top]->hash != curscr->lines[top]->hash 426 || memcmp(win->lines[top]->line, 427 curscr->lines[top]->line, 428 win->maxx * __LDATASIZE) != 0) 429 break; 430 else 431 win->lines[top]->flags &= ~__ISDIRTY; 432 /* 433 * Find how many lines from bottom of screen are unchanged. 434 */ 435 for (bot = win->maxy - 1; bot >= 0; bot--) 436 if (win->lines[bot]->flags & __FORCEPAINT || 437 win->lines[bot]->hash != curscr->lines[bot]->hash 438 || memcmp(win->lines[bot]->line, 439 curscr->lines[bot]->line, 440 win->maxx * __LDATASIZE) != 0) 441 break; 442 else 443 win->lines[bot]->flags &= ~__ISDIRTY; 444 445 #ifdef NO_JERKINESS 446 /* 447 * If we have a bottom unchanged region return. Scrolling the 448 * bottom region up and then back down causes a screen jitter. 449 * This will increase the number of characters sent to the screen 450 * but it looks better. 451 */ 452 if (bot < win->maxy - 1) 453 return; 454 #endif /* NO_JERKINESS */ 455 456 /* 457 * Search for the largest block of text not changed. 458 * Invariants of the loop: 459 * - Startw is the index of the beginning of the examined block in win. 460 * - Starts is the index of the beginning of the examined block in 461 * curscr. 462 * - Curs is the index of one past the end of the exmined block in win. 463 * - Curw is the index of one past the end of the exmined block in 464 * curscr. 465 * - bsize is the current size of the examined block. 466 */ 467 for (bsize = bot - top; bsize >= THRESH; bsize--) { 468 for (startw = top; startw <= bot - bsize; startw++) 469 for (starts = top; starts <= bot - bsize; 470 starts++) { 471 for (curw = startw, curs = starts; 472 curs < starts + bsize; curw++, curs++) 473 if (win->lines[curw]->flags & 474 __FORCEPAINT || 475 (win->lines[curw]->hash != 476 curscr->lines[curs]->hash || 477 memcmp(win->lines[curw]->line, 478 curscr->lines[curs]->line, 479 win->maxx * __LDATASIZE) != 0)) 480 break; 481 if (curs == starts + bsize) 482 goto done; 483 } 484 } 485 done: 486 /* Did not find anything */ 487 if (bsize < THRESH) 488 return; 489 490 #ifdef DEBUG 491 __CTRACE("quickch:bsize=%d,starts=%d,startw=%d,curw=%d,curs=%d,top=%d,bot=%d\n", 492 bsize, starts, startw, curw, curs, top, bot); 493 #endif 494 495 /* 496 * Make sure that there is no overlap between the bottom and top 497 * regions and the middle scrolled block. 498 */ 499 if (bot < curs) 500 bot = curs - 1; 501 if (top > starts) 502 top = starts; 503 504 n = startw - starts; 505 506 #ifdef DEBUG 507 __CTRACE("#####################################\n"); 508 for (i = 0; i < curscr->maxy; i++) { 509 __CTRACE("C: %d:", i); 510 __CTRACE(" 0x%x \n", curscr->lines[i]->hash); 511 for (j = 0; j < curscr->maxx; j++) 512 __CTRACE("%c", 513 curscr->lines[i]->line[j].ch); 514 __CTRACE("\n"); 515 for (j = 0; j < curscr->maxx; j++) 516 __CTRACE("%x", 517 curscr->lines[i]->line[j].attr); 518 __CTRACE("\n"); 519 __CTRACE("W: %d:", i); 520 __CTRACE(" 0x%x \n", win->lines[i]->hash); 521 __CTRACE(" 0x%x ", win->lines[i]->flags); 522 for (j = 0; j < win->maxx; j++) 523 __CTRACE("%c", 524 win->lines[i]->line[j].ch); 525 __CTRACE("\n"); 526 for (j = 0; j < win->maxx; j++) 527 __CTRACE("%x", 528 win->lines[i]->line[j].attr); 529 __CTRACE("\n"); 530 } 531 #endif 532 533 /* So we don't have to call __hash() each time */ 534 for (i = 0; i < win->maxx; i++) { 535 buf[i].ch = ' '; 536 buf[i].attr = 0; 537 } 538 blank_hash = __hash((char *) buf, win->maxx * __LDATASIZE); 539 540 /* 541 * Perform the rotation to maintain the consistency of curscr. 542 * This is hairy since we are doing an *in place* rotation. 543 * Invariants of the loop: 544 * - I is the index of the current line. 545 * - Target is the index of the target of line i. 546 * - Tmp1 points to current line (i). 547 * - Tmp2 and points to target line (target); 548 * - Cur_period is the index of the end of the current period. 549 * (see below). 550 * 551 * There are 2 major issues here that make this rotation non-trivial: 552 * 1. Scrolling in a scrolling region bounded by the top 553 * and bottom regions determined (whose size is sc_region). 554 * 2. As a result of the use of the mod function, there may be a 555 * period introduced, i.e., 2 maps to 4, 4 to 6, n-2 to 0, and 556 * 0 to 2, which then causes all odd lines not to be rotated. 557 * To remedy this, an index of the end ( = beginning) of the 558 * current 'period' is kept, cur_period, and when it is reached, 559 * the next period is started from cur_period + 1 which is 560 * guaranteed not to have been reached since that would mean that 561 * all records would have been reached. (think about it...). 562 * 563 * Lines in the rotation can have 3 attributes which are marked on the 564 * line so that curscr is consistent with the visual screen. 565 * 1. Not dirty -- lines inside the scrolled block, top region or 566 * bottom region. 567 * 2. Blank lines -- lines in the differential of the scrolling 568 * region adjacent to top and bot regions 569 * depending on scrolling direction. 570 * 3. Dirty line -- all other lines are marked dirty. 571 */ 572 sc_region = bot - top + 1; 573 i = top; 574 tmp1 = curscr->lines[top]; 575 cur_period = top; 576 for (j = top; j <= bot; j++) { 577 target = (i - top + n + sc_region) % sc_region + top; 578 tmp2 = curscr->lines[target]; 579 curscr->lines[target] = tmp1; 580 /* Mark block as clean and blank out scrolled lines. */ 581 clp = curscr->lines[target]; 582 #ifdef DEBUG 583 __CTRACE("quickch: n=%d startw=%d curw=%d i = %d target=%d ", 584 n, startw, curw, i, target); 585 #endif 586 if ((target >= startw && target < curw) || target < top 587 || target > bot) { 588 #ifdef DEBUG 589 __CTRACE("-- notdirty"); 590 #endif 591 win->lines[target]->flags &= ~__ISDIRTY; 592 } else if ((n > 0 && target >= top && target < top + n) || 593 (n < 0 && target <= bot && target > bot + n)) { 594 if (clp->hash != blank_hash || memcmp(clp->line, 595 buf, win->maxx * __LDATASIZE) !=0) { 596 (void)memcpy(clp->line, buf, 597 win->maxx * __LDATASIZE); 598 #ifdef DEBUG 599 __CTRACE("-- blanked out: dirty"); 600 #endif 601 clp->hash = blank_hash; 602 __touchline(win, target, 0, win->maxx - 1, 0); 603 } else { 604 __touchline(win, target, 0, win->maxx - 1, 0); 605 #ifdef DEBUG 606 __CTRACE(" -- blank line already: dirty"); 607 #endif 608 } 609 } else { 610 #ifdef DEBUG 611 __CTRACE(" -- dirty"); 612 #endif 613 __touchline(win, target, 0, win->maxx - 1, 0); 614 } 615 #ifdef DEBUG 616 __CTRACE("\n"); 617 #endif 618 if (target == cur_period) { 619 i = target + 1; 620 tmp1 = curscr->lines[i]; 621 cur_period = i; 622 } else { 623 tmp1 = tmp2; 624 i = target; 625 } 626 } 627 #ifdef DEBUG 628 __CTRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n"); 629 for (i = 0; i < curscr->maxy; i++) { 630 __CTRACE("C: %d:", i); 631 for (j = 0; j < curscr->maxx; j++) 632 __CTRACE("%c", 633 curscr->lines[i]->line[j].ch); 634 __CTRACE("\n"); 635 __CTRACE("W: %d:", i); 636 for (j = 0; j < win->maxx; j++) 637 __CTRACE("%c", win->lines[i]->line[j].ch); 638 __CTRACE("\n"); 639 } 640 #endif 641 if (n != 0) { 642 WINDOW *wp; 643 scrolln(win, starts, startw, curs, bot, top); 644 /* 645 * Need to repoint any subwindow lines to the rotated 646 * line structured. 647 */ 648 for (wp = win->nextp; wp != win; wp = wp->nextp) 649 __set_subwin(win, wp); 650 } 651 } 652 653 /* 654 * scrolln -- 655 * Scroll n lines, where n is starts - startw. 656 */ 657 static void 658 scrolln(win, starts, startw, curs, bot, top) 659 WINDOW *win; 660 int starts, startw, curs, bot, top; 661 { 662 int i, oy, ox, n; 663 664 oy = curscr->cury; 665 ox = curscr->curx; 666 n = starts - startw; 667 668 /* 669 * XXX 670 * The initial tests that set __noqch don't let us reach here unless 671 * we have either CS + HO + SF/sf/SR/sr, or AL + DL. SF/sf and SR/sr 672 * scrolling can only shift the entire scrolling region, not just a 673 * part of it, which means that the quickch() routine is going to be 674 * sadly disappointed in us if we don't have CS as well. 675 * 676 * If CS, HO and SF/sf are set, can use the scrolling region. Because 677 * the cursor position after CS is undefined, we need HO which gives us 678 * the ability to move to somewhere without knowledge of the current 679 * location of the cursor. Still call __mvcur() anyway, to update its 680 * idea of where the cursor is. 681 * 682 * When the scrolling region has been set, the cursor has to be at the 683 * last line of the region to make the scroll happen. 684 * 685 * Doing SF/SR or AL/DL appears faster on the screen than either sf/sr 686 * or al/dl, and, some terminals have AL/DL, sf/sr, and CS, but not 687 * SF/SR. So, if we're scrolling almost all of the screen, try and use 688 * AL/DL, otherwise use the scrolling region. The "almost all" is a 689 * shameless hack for vi. 690 */ 691 if (n > 0) { 692 if (CS != NULL && HO != NULL && (SF != NULL || 693 (AL == NULL || DL == NULL || 694 top > 3 || bot + 3 < win->maxy) && sf != NULL)) { 695 tputs(__tscroll(CS, top, bot + 1), 0, __cputchar); 696 __mvcur(oy, ox, 0, 0, 1); 697 tputs(HO, 0, __cputchar); 698 __mvcur(0, 0, bot, 0, 1); 699 if (SF != NULL) 700 tputs(__tscroll(SF, n, 0), 0, __cputchar); 701 else 702 for (i = 0; i < n; i++) 703 tputs(sf, 0, __cputchar); 704 tputs(__tscroll(CS, 0, win->maxy), 0, __cputchar); 705 __mvcur(bot, 0, 0, 0, 1); 706 tputs(HO, 0, __cputchar); 707 __mvcur(0, 0, oy, ox, 1); 708 return; 709 } 710 711 /* Scroll up the block. */ 712 __mvcur(oy, ox, top, 0, 1); 713 if (SF != NULL && top == 0) 714 tputs(__tscroll(SF, n, 0), 0, __cputchar); 715 else if (DL != NULL) 716 tputs(__tscroll(DL, n, 0), 0, __cputchar); 717 else if (dl != NULL) 718 for (i = 0; i < n; i++) 719 tputs(dl, 0, __cputchar); 720 else if (sf != NULL && top == 0) 721 for (i = 0; i < n; i++) 722 tputs(sf, 0, __cputchar); 723 else 724 abort(); 725 726 /* Push down the bottom region. */ 727 __mvcur(top, 0, bot - n + 1, 0, 1); 728 if (AL != NULL) 729 tputs(__tscroll(AL, n, 0), 0, __cputchar); 730 else if (al != NULL) 731 for (i = 0; i < n; i++) 732 tputs(al, 0, __cputchar); 733 else 734 abort(); 735 __mvcur(bot - n + 1, 0, oy, ox, 1); 736 } else { 737 /* 738 * !!! 739 * n < 0 740 * 741 * If CS, HO and SR/sr are set, can use the scrolling region. 742 * See the above comments for details. 743 */ 744 if (CS != NULL && HO != NULL && (SR != NULL || 745 (AL == NULL || DL == NULL || 746 top > 3 || bot + 3 < win->maxy) && sr != NULL)) { 747 tputs(__tscroll(CS, top, bot + 1), 0, __cputchar); 748 __mvcur(oy, ox, 0, 0, 1); 749 tputs(HO, 0, __cputchar); 750 __mvcur(0, 0, top, 0, 1); 751 752 if (SR != NULL) 753 tputs(__tscroll(SR, -n, 0), 0, __cputchar); 754 else 755 for (i = n; i < 0; i++) 756 tputs(sr, 0, __cputchar); 757 tputs(__tscroll(CS, 0, win->maxy), 0, __cputchar); 758 __mvcur(top, 0, 0, 0, 1); 759 tputs(HO, 0, __cputchar); 760 __mvcur(0, 0, oy, ox, 1); 761 return; 762 } 763 764 /* Preserve the bottom lines. */ 765 __mvcur(oy, ox, bot + n + 1, 0, 1); 766 if (SR != NULL && bot == win->maxy) 767 tputs(__tscroll(SR, -n, 0), 0, __cputchar); 768 else if (DL != NULL) 769 tputs(__tscroll(DL, -n, 0), 0, __cputchar); 770 else if (dl != NULL) 771 for (i = n; i < 0; i++) 772 tputs(dl, 0, __cputchar); 773 else if (sr != NULL && bot == win->maxy) 774 for (i = n; i < 0; i++) 775 tputs(sr, 0, __cputchar); 776 else 777 abort(); 778 779 /* Scroll the block down. */ 780 __mvcur(bot + n + 1, 0, top, 0, 1); 781 if (AL != NULL) 782 tputs(__tscroll(AL, -n, 0), 0, __cputchar); 783 else if (al != NULL) 784 for (i = n; i < 0; i++) 785 tputs(al, 0, __cputchar); 786 else 787 abort(); 788 __mvcur(top, 0, oy, ox, 1); 789 } 790 } 791