1 /* $NetBSD: refresh.c,v 1.52 2003/01/27 21:11:12 jdc Exp $ */ 2 3 /* 4 * Copyright (c) 1981, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)refresh.c 8.7 (Berkeley) 8/13/94"; 40 #else 41 __RCSID("$NetBSD: refresh.c,v 1.52 2003/01/27 21:11:12 jdc Exp $"); 42 #endif 43 #endif /* not lint */ 44 45 #include <stdlib.h> 46 #include <string.h> 47 48 #include "curses.h" 49 #include "curses_private.h" 50 51 static void domvcur __P((int, int, int, int)); 52 static int makech __P((int)); 53 static void quickch __P((void)); 54 static void scrolln __P((int, int, int, int, int)); 55 56 #ifndef _CURSES_USE_MACROS 57 58 /* 59 * refresh -- 60 * Make the current screen look like "stdscr" over the area covered by 61 * stdscr. 62 */ 63 int 64 refresh(void) 65 { 66 return wrefresh(stdscr); 67 } 68 69 #endif 70 71 /* 72 * wnoutrefresh -- 73 * Add the contents of "win" to the virtual window. 74 */ 75 int 76 wnoutrefresh(WINDOW *win) 77 { 78 #ifdef DEBUG 79 __CTRACE("wnoutrefresh: win %0.2o\n", win); 80 #endif 81 82 return _cursesi_wnoutrefresh(_cursesi_screen, win, 0, 0, win->begy, 83 win->begx, win->maxy, win->maxx); 84 } 85 86 /* 87 * pnoutrefresh -- 88 * Add the contents of "pad" to the virtual window. 89 */ 90 int 91 pnoutrefresh(WINDOW *pad, int pbegy, int pbegx, int sbegy, int sbegx, 92 int smaxy, int smaxx) 93 { 94 int pmaxy, pmaxx; 95 96 #ifdef DEBUG 97 __CTRACE("pnoutrefresh: pad %0.2o, flags 0x%08x\n", pad, pad->flags); 98 __CTRACE("pnoutrefresh: (%d, %d), (%d, %d), (%d, %d)\n", pbegy, pbegx, 99 sbegy, sbegx, smaxy, smaxx); 100 #endif 101 102 /* SUS says if these are negative, they should be treated as zero */ 103 if (pbegy < 0) 104 pbegy = 0; 105 if (pbegx < 0) 106 pbegx = 0; 107 if (sbegy < 0) 108 sbegy = 0; 109 if (sbegx < 0) 110 sbegx = 0; 111 112 /* Calculate rectangle on pad - used bu _cursesi_wnoutrefresh */ 113 pmaxy = pbegy + smaxy - sbegy + 1; 114 pmaxx = pbegx + smaxx - sbegx + 1; 115 116 /* Check rectangle fits in pad */ 117 if (pmaxy > pad->maxy - pad->begy) 118 pmaxy = pad->maxy - pad->begy; 119 if (pmaxx > pad->maxx - pad->begx) 120 pmaxx = pad->maxx - pad->begx; 121 122 if (smaxy - sbegy < 0 || smaxx - sbegx < 0 ) 123 return ERR; 124 125 return _cursesi_wnoutrefresh(_cursesi_screen, pad, 126 pad->begy + pbegy, pad->begx + pbegx, pad->begy + sbegy, 127 pad->begx + sbegx, pmaxy, pmaxx); 128 } 129 130 /* 131 * _cursesi_wnoutrefresh -- 132 * Does the grunt work for wnoutrefresh to the given screen. 133 * Copies the part of the window given by the rectangle 134 * (begy, begx) to (maxy, maxx) at screen position (wbegy, wbegx). 135 */ 136 int 137 _cursesi_wnoutrefresh(SCREEN *screen, WINDOW *win, int begy, int begx, 138 int wbegy, int wbegx, int maxy, int maxx) 139 { 140 141 short wy, wx, y_off, x_off; 142 __LINE *wlp, *vlp; 143 144 #ifdef DEBUG 145 __CTRACE("wnoutrefresh: win %0.2o, flags 0x%08x\n", win, win->flags); 146 __CTRACE("wnoutrefresh: (%d, %d), (%d, %d), (%d, %d)\n", begy, begx, 147 wbegy, wbegx, maxy, maxx); 148 #endif 149 150 if (screen->curwin) 151 return(OK); 152 153 /* Check that cursor position on "win" is valid for "__virtscr" */ 154 if (win->cury + wbegy - begy < screen->__virtscr->maxy && 155 win->cury + wbegy - begy >= 0 && win->cury < maxy - begy) 156 screen->__virtscr->cury = win->cury + wbegy - begy; 157 if (win->curx + wbegx - begx < screen->__virtscr->maxx && 158 win->curx + wbegx - begx >= 0 && win->curx < maxx - begx) 159 screen->__virtscr->curx = win->curx + wbegx - begx; 160 161 /* Copy the window flags from "win" to "__virtscr" */ 162 if (win->flags & __CLEAROK) { 163 if (win->flags & __FULLWIN) 164 screen->__virtscr->flags |= __CLEAROK; 165 win->flags &= ~__CLEAROK; 166 } 167 screen->__virtscr->flags &= ~__LEAVEOK; 168 screen->__virtscr->flags |= win->flags; 169 170 for (wy = begy, y_off = wbegy; wy < maxy && 171 y_off < screen->__virtscr->maxy; wy++, y_off++) { 172 wlp = win->lines[wy]; 173 #ifdef DEBUG 174 __CTRACE("wnoutrefresh: wy %d\tf: %d\tl:%d\tflags %x\n", wy, 175 *wlp->firstchp, *wlp->lastchp, wlp->flags); 176 #endif 177 if ((wlp->flags & __ISDIRTY) == 0) 178 continue; 179 vlp = screen->__virtscr->lines[y_off]; 180 181 if (*wlp->firstchp < maxx + win->ch_off && 182 *wlp->lastchp >= win->ch_off) { 183 /* Copy line from "win" to "__virtscr". */ 184 for (wx = begx + *wlp->firstchp - win->ch_off, 185 x_off = wbegx + *wlp->firstchp - win->ch_off; 186 wx <= *wlp->lastchp && wx < maxx && 187 x_off < screen->__virtscr->maxx; wx++, x_off++) { 188 vlp->line[x_off].attr = wlp->line[wx].attr; 189 /* Copy attributes */ 190 if (wlp->line[wx].attr & __COLOR) 191 vlp->line[x_off].attr |= 192 wlp->line[wx].battr & ~__COLOR; 193 else 194 vlp->line[x_off].attr |= 195 wlp->line[wx].battr; 196 /* Check for nca conflict with colour */ 197 if ((vlp->line[x_off].attr & __COLOR) && 198 (vlp->line[x_off].attr & 199 _cursesi_screen->nca)) 200 vlp->line[x_off].attr &= ~__COLOR; 201 /* Copy character */ 202 if (wlp->line[wx].ch == ' ' && 203 wlp->line[wx].bch != ' ') 204 vlp->line[x_off].ch 205 = wlp->line[wx].bch; 206 else 207 vlp->line[x_off].ch 208 = wlp->line[wx].ch; 209 } 210 211 /* Set flags on "__virtscr" and unset on "win". */ 212 if (wlp->flags & __ISPASTEOL) 213 vlp->flags |= __ISPASTEOL; 214 else 215 vlp->flags &= ~__ISPASTEOL; 216 if (wlp->flags & __ISDIRTY) 217 vlp->flags |= __ISDIRTY; 218 219 #ifdef DEBUG 220 __CTRACE("win: firstch = %d, lastch = %d\n", 221 *wlp->firstchp, *wlp->lastchp); 222 #endif 223 /* Set change pointers on "__virtscr". */ 224 if (*vlp->firstchp > 225 *wlp->firstchp + wbegx - win->ch_off) 226 *vlp->firstchp = 227 *wlp->firstchp + wbegx - win->ch_off; 228 if (*vlp->lastchp < 229 *wlp->lastchp + wbegx - win->ch_off) 230 *vlp->lastchp = 231 *wlp->lastchp + wbegx - win->ch_off; 232 #ifdef DEBUG 233 __CTRACE("__virtscr: firstch = %d, lastch = %d\n", 234 *vlp->firstchp, *vlp->lastchp); 235 #endif 236 /* 237 * Unset change pointers only if a window, as a pad 238 * can be displayed again without any of the contents 239 * changing. 240 */ 241 if (!(win->flags & __ISPAD)) { 242 /* Set change pointers on "win". */ 243 if (*wlp->firstchp >= win->ch_off) 244 *wlp->firstchp = maxx + win->ch_off; 245 if (*wlp->lastchp < maxx + win->ch_off) 246 *wlp->lastchp = win->ch_off; 247 if (*wlp->lastchp < *wlp->firstchp) { 248 #ifdef DEBUG 249 __CTRACE("wnoutrefresh: line %d notdirty\n", wy); 250 #endif 251 wlp->flags &= ~__ISDIRTY; 252 } 253 } 254 } 255 } 256 257 return (OK); 258 } 259 260 /* 261 * wrefresh -- 262 * Make the current screen look like "win" over the area covered by 263 * win. 264 */ 265 int 266 wrefresh(WINDOW *win) 267 { 268 int retval; 269 270 #ifdef DEBUG 271 __CTRACE("wrefresh: win %0.2o\n", win); 272 #endif 273 274 _cursesi_screen->curwin = (win == _cursesi_screen->curscr); 275 if (!_cursesi_screen->curwin) 276 retval = _cursesi_wnoutrefresh(_cursesi_screen, win, 0, 0, 277 win->begy, win->begx, win->maxy, win->maxx); 278 else 279 retval = OK; 280 if (retval == OK) { 281 retval = doupdate(); 282 if (!win->flags & __LEAVEOK) { 283 win->cury = max(0, curscr->cury - win->begy); 284 win->curx = max(0, curscr->curx - win->begx); 285 } 286 } 287 _cursesi_screen->curwin = 0; 288 return(retval); 289 } 290 291 /* 292 * prefresh -- 293 * Make the current screen look like "pad" over the area coverd by 294 * the specified area of pad. 295 */ 296 int 297 prefresh(WINDOW *pad, int pbegy, int pbegx, int sbegy, int sbegx, 298 int smaxy, int smaxx) 299 { 300 int retval; 301 302 #ifdef DEBUG 303 __CTRACE("prefresh: pad %0.2o, flags 0x%08x\n", pad, pad->flags); 304 #endif 305 306 /* Use pnoutrefresh() to avoid duplicating code here */ 307 retval = pnoutrefresh(pad, pbegy, pbegx, sbegy, sbegx, smaxy, smaxx); 308 if (retval == OK) { 309 retval = doupdate(); 310 if (!pad->flags & __LEAVEOK) { 311 pad->cury = max(0, curscr->cury - pad->begy); 312 pad->curx = max(0, curscr->curx - pad->begx); 313 } 314 } 315 return(retval); 316 } 317 318 /* 319 * doupdate -- 320 * Make the current screen look like the virtual window "__virtscr". 321 */ 322 int 323 doupdate(void) 324 { 325 WINDOW *win; 326 __LINE *wlp; 327 short wy; 328 int dnum; 329 330 /* Check if we need to restart ... */ 331 if (_cursesi_screen->endwin) 332 __restartwin(); 333 334 if (_cursesi_screen->curwin) 335 win = curscr; 336 else 337 win = _cursesi_screen->__virtscr; 338 339 /* Initialize loop parameters. */ 340 _cursesi_screen->ly = curscr->cury; 341 _cursesi_screen->lx = curscr->curx; 342 wy = 0; 343 344 if (!_cursesi_screen->curwin) 345 for (wy = 0; wy < win->maxy; wy++) { 346 wlp = win->lines[wy]; 347 if (wlp->flags & __ISDIRTY) 348 wlp->hash = __hash((char *)(void *)wlp->line, 349 (size_t) (win->maxx * __LDATASIZE)); 350 } 351 352 if ((win->flags & __CLEAROK) || (curscr->flags & __CLEAROK) || 353 _cursesi_screen->curwin) { 354 if (curscr->wattr & __COLOR) 355 __unsetattr(0); 356 tputs(__tc_cl, 0, __cputchar); 357 _cursesi_screen->ly = 0; 358 _cursesi_screen->lx = 0; 359 if (!_cursesi_screen->curwin) { 360 curscr->flags &= ~__CLEAROK; 361 curscr->cury = 0; 362 curscr->curx = 0; 363 werase(curscr); 364 } 365 __touchwin(win); 366 win->flags &= ~__CLEAROK; 367 } 368 if (!__CA) { 369 if (win->curx != 0) 370 __cputchar('\n'); 371 if (!_cursesi_screen->curwin) 372 werase(curscr); 373 } 374 #ifdef DEBUG 375 __CTRACE("doupdate: (%0.2o): curwin = %d\n", win, 376 _cursesi_screen->curwin); 377 __CTRACE("doupdate: \tfirstch\tlastch\n"); 378 #endif 379 380 if (!_cursesi_screen->curwin) { 381 /* 382 * Invoke quickch() only if more than a quarter of the lines 383 * in the window are dirty. 384 */ 385 for (wy = 0, dnum = 0; wy < win->maxy; wy++) 386 if (win->lines[wy]->flags & __ISDIRTY) 387 dnum++; 388 if (!__noqch && dnum > (int) win->maxy / 4) 389 quickch(); 390 } 391 392 #ifdef DEBUG 393 { 394 int i, j; 395 396 __CTRACE("#####################################\n"); 397 for (i = 0; i < curscr->maxy; i++) { 398 __CTRACE("C: %d:", i); 399 __CTRACE(" 0x%x \n", curscr->lines[i]->hash); 400 for (j = 0; j < curscr->maxx; j++) 401 __CTRACE("%c", curscr->lines[i]->line[j].ch); 402 __CTRACE("\n"); 403 __CTRACE(" attr:"); 404 for (j = 0; j < curscr->maxx; j++) 405 __CTRACE(" %x", 406 curscr->lines[i]->line[j].attr); 407 __CTRACE("\n"); 408 __CTRACE("W: %d:", i); 409 __CTRACE(" 0x%x \n", win->lines[i]->hash); 410 __CTRACE(" 0x%x ", win->lines[i]->flags); 411 for (j = 0; j < win->maxx; j++) 412 __CTRACE("%c", win->lines[i]->line[j].ch); 413 __CTRACE("\n"); 414 __CTRACE(" attr:"); 415 for (j = 0; j < win->maxx; j++) 416 __CTRACE(" %x", 417 win->lines[i]->line[j].attr); 418 __CTRACE("\n"); 419 } 420 } 421 #endif /* DEBUG */ 422 423 for (wy = 0; wy < win->maxy; wy++) { 424 wlp = win->lines[wy]; 425 /* XXX: remove this debug */ 426 #ifdef DEBUG 427 __CTRACE("doupdate: wy %d\tf: %d\tl:%d\tflags %x\n", wy, 428 *wlp->firstchp, *wlp->lastchp, wlp->flags); 429 #endif 430 if (!_cursesi_screen->curwin) 431 curscr->lines[wy]->hash = wlp->hash; 432 if (wlp->flags & __ISDIRTY) { 433 if (makech(wy) == ERR) 434 return (ERR); 435 else { 436 if (*wlp->firstchp >= 0) 437 *wlp->firstchp = win->maxx; 438 if (*wlp->lastchp < win->maxx) 439 *wlp->lastchp = 0; 440 if (*wlp->lastchp < *wlp->firstchp) { 441 #ifdef DEBUG 442 __CTRACE("doupdate: line %d notdirty\n", wy); 443 #endif 444 wlp->flags &= ~__ISDIRTY; 445 } 446 } 447 448 } 449 #ifdef DEBUG 450 __CTRACE("\t%d\t%d\n", *wlp->firstchp, *wlp->lastchp); 451 #endif 452 } 453 454 #ifdef DEBUG 455 __CTRACE("doupdate: ly=%d, lx=%d\n", _cursesi_screen->ly, 456 _cursesi_screen->lx); 457 #endif 458 459 if (_cursesi_screen->curwin) 460 domvcur(_cursesi_screen->ly, _cursesi_screen->lx, 461 (int) win->cury, (int) win->curx); 462 else { 463 if (win->flags & __LEAVEOK) { 464 curscr->cury = _cursesi_screen->ly; 465 curscr->curx = _cursesi_screen->lx; 466 } else { 467 domvcur(_cursesi_screen->ly, _cursesi_screen->lx, 468 win->cury, win->curx); 469 curscr->cury = win->cury; 470 curscr->curx = win->curx; 471 } 472 } 473 474 /* Don't leave the screen with attributes set. */ 475 __unsetattr(0); 476 (void) fflush(_cursesi_screen->outfd); 477 return (OK); 478 } 479 480 /* 481 * makech -- 482 * Make a change on the screen. 483 */ 484 static int 485 makech(wy) 486 int wy; 487 { 488 WINDOW *win; 489 static __LDATA blank = {' ', 0, ' ', 0}; 490 __LDATA *nsp, *csp, *cp, *cep; 491 int clsp, nlsp; /* Last space in lines. */ 492 int lch, wx; 493 char *ce; 494 attr_t lspc; /* Last space colour */ 495 attr_t off, on; 496 497 #ifdef __GNUC__ 498 nlsp = lspc = 0; /* XXX gcc -Wuninitialized */ 499 #endif 500 if (_cursesi_screen->curwin) 501 win = curscr; 502 else 503 win = __virtscr; 504 /* Is the cursor still on the end of the last line? */ 505 if (wy > 0 && curscr->lines[wy - 1]->flags & __ISPASTEOL) { 506 domvcur(_cursesi_screen->ly, _cursesi_screen->lx, 507 _cursesi_screen->ly + 1, 0); 508 _cursesi_screen->ly++; 509 _cursesi_screen->lx = 0; 510 } 511 wx = *win->lines[wy]->firstchp; 512 if (wx < 0) 513 wx = 0; 514 else 515 if (wx >= win->maxx) 516 return (OK); 517 lch = *win->lines[wy]->lastchp; 518 if (lch < 0) 519 return (OK); 520 else 521 if (lch >= (int) win->maxx) 522 lch = win->maxx - 1; 523 524 if (_cursesi_screen->curwin) 525 csp = ␣ 526 else 527 csp = &curscr->lines[wy]->line[wx]; 528 529 nsp = &win->lines[wy]->line[wx]; 530 if (__tc_ce && !_cursesi_screen->curwin) { 531 cp = &win->lines[wy]->line[win->maxx - 1]; 532 lspc = cp->attr & __COLOR; 533 while (cp->ch == ' ' && cp->attr == lspc) 534 if (cp-- <= win->lines[wy]->line) 535 break; 536 nlsp = cp - win->lines[wy]->line; 537 if (nlsp < 0) 538 nlsp = 0; 539 } 540 if (!_cursesi_screen->curwin) 541 ce = __tc_ce; 542 else 543 ce = NULL; 544 545 while (wx <= lch) { 546 if (memcmp(nsp, csp, sizeof(__LDATA)) == 0) { 547 if (wx <= lch) { 548 while (wx <= lch && 549 memcmp(nsp, csp, sizeof(__LDATA)) == 0) { 550 nsp++; 551 if (!_cursesi_screen->curwin) 552 ++csp; 553 ++wx; 554 } 555 continue; 556 } 557 break; 558 } 559 domvcur(_cursesi_screen->ly, _cursesi_screen->lx, wy, wx); 560 561 #ifdef DEBUG 562 __CTRACE("makech: 1: wx = %d, ly= %d, lx = %d, newy = %d, newx = %d\n", 563 wx, _cursesi_screen->ly, _cursesi_screen->lx, wy, wx); 564 #endif 565 _cursesi_screen->ly = wy; 566 _cursesi_screen->lx = wx; 567 while (memcmp(nsp, csp, sizeof(__LDATA)) != 0 && wx <= lch) { 568 if (ce != NULL && 569 wx >= nlsp && nsp->ch == ' ' && nsp->attr == lspc) { 570 /* Check for clear to end-of-line. */ 571 cep = &curscr->lines[wy]->line[win->maxx - 1]; 572 while (cep->ch == ' ' && cep->attr == lspc) 573 if (cep-- <= csp) 574 break; 575 clsp = cep - curscr->lines[wy]->line - 576 win->begx * __LDATASIZE; 577 #ifdef DEBUG 578 __CTRACE("makech: clsp = %d, nlsp = %d\n", 579 clsp, nlsp); 580 #endif 581 if (((clsp - nlsp >= strlen(__tc_ce) && 582 clsp < win->maxx * __LDATASIZE) || 583 wy == win->maxy - 1) && 584 (!(lspc & __COLOR) || 585 ((lspc & __COLOR) && __tc_ut))) { 586 __unsetattr(0); 587 if (__using_color && 588 ((lspc & __COLOR) != 589 (curscr->wattr & __COLOR))) 590 __set_color(curscr, lspc & 591 __COLOR); 592 tputs(__tc_ce, 0, __cputchar); 593 _cursesi_screen->lx = wx + win->begx; 594 while (wx++ <= clsp) { 595 csp->ch = ' '; 596 csp->attr = lspc; 597 csp++; 598 } 599 return (OK); 600 } 601 ce = NULL; 602 } 603 604 #ifdef DEBUG 605 __CTRACE("makech: have attributes %08x, need attributes %08x\n", curscr->wattr, nsp->attr); 606 #endif 607 608 off = ~nsp->attr & curscr->wattr; 609 610 /* 611 * Unset attributes as appropriate. Unset first 612 * so that the relevant attributes can be reset 613 * (because 'me' unsets 'mb', 'md', 'mh', 'mk', 614 * 'mp' and 'mr'). Check to see if we also turn off 615 * standout, attributes and colour. 616 */ 617 if (off & __TERMATTR && __tc_me != NULL) { 618 tputs(__tc_me, 0, __cputchar); 619 curscr->wattr &= __mask_me; 620 off &= __mask_me; 621 } 622 623 /* 624 * Exit underscore mode if appropriate. 625 * Check to see if we also turn off standout, 626 * attributes and colour. 627 */ 628 if (off & __UNDERSCORE && __tc_ue != NULL) { 629 tputs(__tc_ue, 0, __cputchar); 630 curscr->wattr &= __mask_ue; 631 off &= __mask_ue; 632 } 633 634 /* 635 * Exit standout mode as appropriate. 636 * Check to see if we also turn off underscore, 637 * attributes and colour. 638 * XXX 639 * Should use uc if so/se not available. 640 */ 641 if (off & __STANDOUT && __tc_se != NULL) { 642 tputs(__tc_se, 0, __cputchar); 643 curscr->wattr &= __mask_se; 644 off &= __mask_se; 645 } 646 647 if (off & __ALTCHARSET && __tc_ae != NULL) { 648 tputs(__tc_ae, 0, __cputchar); 649 curscr->wattr &= ~__ALTCHARSET; 650 } 651 652 /* Set/change colour as appropriate. */ 653 if (__using_color) 654 __set_color(curscr, nsp->attr & __COLOR); 655 656 on = nsp->attr & ~curscr->wattr; 657 658 /* 659 * Enter standout mode if appropriate. 660 */ 661 if (on & __STANDOUT && __tc_so != NULL && __tc_se 662 != NULL) { 663 tputs(__tc_so, 0, __cputchar); 664 curscr->wattr |= __STANDOUT; 665 } 666 667 /* 668 * Enter underscore mode if appropriate. 669 * XXX 670 * Should use uc if us/ue not available. 671 */ 672 if (on & __UNDERSCORE && __tc_us != NULL && 673 __tc_ue != NULL) { 674 tputs(__tc_us, 0, __cputchar); 675 curscr->wattr |= __UNDERSCORE; 676 } 677 678 /* 679 * Set other attributes as appropriate. 680 */ 681 if (__tc_me != NULL) { 682 if (on & __BLINK && __tc_mb != NULL) { 683 tputs(__tc_mb, 0, __cputchar); 684 curscr->wattr |= __BLINK; 685 } 686 if (on & __BOLD && __tc_md != NULL) { 687 tputs(__tc_md, 0, __cputchar); 688 curscr->wattr |= __BOLD; 689 } 690 if (on & __DIM && __tc_mh != NULL) { 691 tputs(__tc_mh, 0, __cputchar); 692 curscr->wattr |= __DIM; 693 } 694 if (on & __BLANK && __tc_mk != NULL) { 695 tputs(__tc_mk, 0, __cputchar); 696 curscr->wattr |= __BLANK; 697 } 698 if (on & __PROTECT && __tc_mp != NULL) { 699 tputs(__tc_mp, 0, __cputchar); 700 curscr->wattr |= __PROTECT; 701 } 702 if (on & __REVERSE && __tc_mr != NULL) { 703 tputs(__tc_mr, 0, __cputchar); 704 curscr->wattr |= __REVERSE; 705 } 706 } 707 708 /* Enter/exit altcharset mode as appropriate. */ 709 if (on & __ALTCHARSET && __tc_as != NULL && 710 __tc_ae != NULL) { 711 tputs(__tc_as, 0, __cputchar); 712 curscr->wattr |= __ALTCHARSET; 713 } 714 715 wx++; 716 if (wx >= win->maxx && 717 wy == win->maxy - 1 && !_cursesi_screen->curwin) 718 if (win->flags & __SCROLLOK) { 719 if (win->flags & __ENDLINE) 720 __unsetattr(1); 721 if (!(win->flags & __SCROLLWIN)) { 722 if (!_cursesi_screen->curwin) { 723 csp->attr = nsp->attr; 724 __cputchar((int) 725 (csp->ch = 726 nsp->ch)); 727 } else 728 __cputchar((int) nsp->ch); 729 } 730 if (wx < curscr->maxx) { 731 domvcur(_cursesi_screen->ly, wx, 732 (int) (win->maxy - 1), 733 (int) (win->maxx - 1)); 734 } 735 _cursesi_screen->ly = win->maxy - 1; 736 _cursesi_screen->lx = win->maxx - 1; 737 return (OK); 738 } 739 if (wx < win->maxx || wy < win->maxy - 1 || 740 !(win->flags & __SCROLLWIN)) { 741 if (!_cursesi_screen->curwin) { 742 csp->attr = nsp->attr; 743 __cputchar((int) (csp->ch = nsp->ch)); 744 csp++; 745 } else 746 __cputchar((int) nsp->ch); 747 } 748 #ifdef DEBUG 749 __CTRACE("makech: putchar(%c)\n", nsp->ch & 0177); 750 #endif 751 if (__tc_uc && ((nsp->attr & __STANDOUT) || 752 (nsp->attr & __UNDERSCORE))) { 753 __cputchar('\b'); 754 tputs(__tc_uc, 0, __cputchar); 755 } 756 nsp++; 757 #ifdef DEBUG 758 __CTRACE("makech: 2: wx = %d, lx = %d\n", wx, _cursesi_screen->lx); 759 #endif 760 } 761 if (_cursesi_screen->lx == wx) /* If no change. */ 762 break; 763 _cursesi_screen->lx = wx; 764 if (_cursesi_screen->lx >= COLS && __tc_am) 765 _cursesi_screen->lx = COLS - 1; 766 else 767 if (wx >= win->maxx) { 768 domvcur(_cursesi_screen->ly, 769 _cursesi_screen->lx, 770 _cursesi_screen->ly, 771 (int) (win->maxx - 1)); 772 _cursesi_screen->lx = win->maxx - 1; 773 } 774 #ifdef DEBUG 775 __CTRACE("makech: 3: wx = %d, lx = %d\n", wx, 776 _cursesi_screen->lx); 777 #endif 778 } 779 780 return (OK); 781 } 782 783 /* 784 * domvcur -- 785 * Do a mvcur, leaving attributes if necessary. 786 */ 787 static void 788 domvcur(oy, ox, ny, nx) 789 int oy, ox, ny, nx; 790 { 791 __unsetattr(1); 792 __mvcur(oy, ox, ny, nx, 1); 793 } 794 795 /* 796 * Quickch() attempts to detect a pattern in the change of the window 797 * in order to optimize the change, e.g., scroll n lines as opposed to 798 * repainting the screen line by line. 799 */ 800 801 static __LDATA buf[128]; 802 static u_int last_hash; 803 static size_t last_hash_len; 804 #define BLANKSIZE (sizeof(buf) / sizeof(buf[0])) 805 806 static void 807 quickch(void) 808 { 809 #define THRESH (int) __virtscr->maxy / 4 810 811 __LINE *clp, *tmp1, *tmp2; 812 int bsize, curs, curw, starts, startw, i, j; 813 int n, target, cur_period, bot, top, sc_region; 814 u_int blank_hash; 815 attr_t bcolor; 816 817 #ifdef __GNUC__ 818 curs = curw = starts = startw = 0; /* XXX gcc -Wuninitialized */ 819 #endif 820 /* 821 * Find how many lines from the top of the screen are unchanged. 822 */ 823 for (top = 0; top < __virtscr->maxy; top++) 824 if (__virtscr->lines[top]->flags & __ISDIRTY && 825 (__virtscr->lines[top]->hash != curscr->lines[top]->hash || 826 memcmp(__virtscr->lines[top]->line, 827 curscr->lines[top]->line, 828 (size_t) __virtscr->maxx * __LDATASIZE) != 0)) 829 break; 830 else 831 __virtscr->lines[top]->flags &= ~__ISDIRTY; 832 /* 833 * Find how many lines from bottom of screen are unchanged. 834 */ 835 for (bot = __virtscr->maxy - 1; bot >= 0; bot--) 836 if (__virtscr->lines[bot]->flags & __ISDIRTY && 837 (__virtscr->lines[bot]->hash != curscr->lines[bot]->hash || 838 memcmp(__virtscr->lines[bot]->line, 839 curscr->lines[bot]->line, 840 (size_t) __virtscr->maxx * __LDATASIZE) != 0)) 841 break; 842 else 843 __virtscr->lines[bot]->flags &= ~__ISDIRTY; 844 845 /* 846 * Work round an xterm bug where inserting lines causes all the 847 * inserted lines to be covered with the background colour we 848 * set on the first line (even if we unset it for subsequent 849 * lines). 850 */ 851 bcolor = __virtscr->lines[min(top, 852 __virtscr->maxy - 1)]->line[0].attr & __COLOR; 853 for (i = top + 1, j = 0; i < bot; i++) { 854 if ((__virtscr->lines[i]->line[0].attr & __COLOR) != bcolor) { 855 bcolor = __virtscr->lines[i]->line[__virtscr->maxx]. 856 attr & __COLOR; 857 j = i - top; 858 } else 859 break; 860 } 861 top += j; 862 863 #ifdef NO_JERKINESS 864 /* 865 * If we have a bottom unchanged region return. Scrolling the 866 * bottom region up and then back down causes a screen jitter. 867 * This will increase the number of characters sent to the screen 868 * but it looks better. 869 */ 870 if (bot < __virtscr->maxy - 1) 871 return; 872 #endif /* NO_JERKINESS */ 873 874 /* 875 * Search for the largest block of text not changed. 876 * Invariants of the loop: 877 * - Startw is the index of the beginning of the examined block in 878 * __virtscr. 879 * - Starts is the index of the beginning of the examined block in 880 * curscr. 881 * - Curw is the index of one past the end of the exmined block in 882 * __virtscr. 883 * - Curs is the index of one past the end of the exmined block in 884 * curscr. 885 * - bsize is the current size of the examined block. 886 */ 887 888 for (bsize = bot - top; bsize >= THRESH; bsize--) { 889 for (startw = top; startw <= bot - bsize; startw++) 890 for (starts = top; starts <= bot - bsize; 891 starts++) { 892 for (curw = startw, curs = starts; 893 curs < starts + bsize; curw++, curs++) 894 if (__virtscr->lines[curw]->hash != 895 curscr->lines[curs]->hash) 896 break; 897 if (curs != starts + bsize) 898 continue; 899 for (curw = startw, curs = starts; 900 curs < starts + bsize; curw++, curs++) 901 if (memcmp(__virtscr->lines[curw]->line, 902 curscr->lines[curs]->line, 903 (size_t) __virtscr->maxx * 904 __LDATASIZE) != 0) 905 break; 906 if (curs == starts + bsize) 907 goto done; 908 } 909 } 910 done: 911 912 /* Did not find anything */ 913 if (bsize < THRESH) 914 return; 915 916 #ifdef DEBUG 917 __CTRACE("quickch:bsize=%d,starts=%d,startw=%d,curw=%d,curs=%d,top=%d,bot=%d\n", 918 bsize, starts, startw, curw, curs, top, bot); 919 #endif 920 921 /* 922 * Make sure that there is no overlap between the bottom and top 923 * regions and the middle scrolled block. 924 */ 925 if (bot < curs) 926 bot = curs - 1; 927 if (top > starts) 928 top = starts; 929 930 n = startw - starts; 931 932 #ifdef DEBUG 933 __CTRACE("#####################################\n"); 934 for (i = 0; i < curscr->maxy; i++) { 935 __CTRACE("C: %d:", i); 936 __CTRACE(" 0x%x \n", curscr->lines[i]->hash); 937 for (j = 0; j < curscr->maxx; j++) 938 __CTRACE("%c", curscr->lines[i]->line[j].ch); 939 __CTRACE("\n"); 940 __CTRACE(" attr:"); 941 for (j = 0; j < curscr->maxx; j++) 942 __CTRACE(" %x", curscr->lines[i]->line[j].attr); 943 __CTRACE("\n"); 944 __CTRACE("W: %d:", i); 945 __CTRACE(" 0x%x \n", __virtscr->lines[i]->hash); 946 __CTRACE(" 0x%x ", __virtscr->lines[i]->flags); 947 for (j = 0; j < __virtscr->maxx; j++) 948 __CTRACE("%c", __virtscr->lines[i]->line[j].ch); 949 __CTRACE("\n"); 950 __CTRACE(" attr:"); 951 for (j = 0; j < __virtscr->maxx; j++) 952 __CTRACE(" %x", __virtscr->lines[i]->line[j].attr); 953 __CTRACE("\n"); 954 } 955 #endif 956 957 if (buf[0].ch != ' ') { 958 for (i = 0; i < BLANKSIZE; i++) { 959 buf[i].ch = ' '; 960 buf[i].bch = ' '; 961 buf[i].attr = 0; 962 buf[i].battr = 0; 963 } 964 } 965 966 if (__virtscr->maxx != last_hash_len) { 967 blank_hash = 0; 968 for (i = __virtscr->maxx; i > BLANKSIZE; i -= BLANKSIZE) { 969 blank_hash = __hash_more((char *)(void *)buf, sizeof(buf), 970 blank_hash); 971 } 972 blank_hash = __hash_more((char *)(void *)buf, 973 i * sizeof(buf[0]), blank_hash); 974 /* cache result in static data - screen width doesn't change often */ 975 last_hash_len = __virtscr->maxx; 976 last_hash = blank_hash; 977 } else 978 blank_hash = last_hash; 979 980 /* 981 * Perform the rotation to maintain the consistency of curscr. 982 * This is hairy since we are doing an *in place* rotation. 983 * Invariants of the loop: 984 * - I is the index of the current line. 985 * - Target is the index of the target of line i. 986 * - Tmp1 points to current line (i). 987 * - Tmp2 and points to target line (target); 988 * - Cur_period is the index of the end of the current period. 989 * (see below). 990 * 991 * There are 2 major issues here that make this rotation non-trivial: 992 * 1. Scrolling in a scrolling region bounded by the top 993 * and bottom regions determined (whose size is sc_region). 994 * 2. As a result of the use of the mod function, there may be a 995 * period introduced, i.e., 2 maps to 4, 4 to 6, n-2 to 0, and 996 * 0 to 2, which then causes all odd lines not to be rotated. 997 * To remedy this, an index of the end ( = beginning) of the 998 * current 'period' is kept, cur_period, and when it is reached, 999 * the next period is started from cur_period + 1 which is 1000 * guaranteed not to have been reached since that would mean that 1001 * all records would have been reached. (think about it...). 1002 * 1003 * Lines in the rotation can have 3 attributes which are marked on the 1004 * line so that curscr is consistent with the visual screen. 1005 * 1. Not dirty -- lines inside the scrolled block, top region or 1006 * bottom region. 1007 * 2. Blank lines -- lines in the differential of the scrolling 1008 * region adjacent to top and bot regions 1009 * depending on scrolling direction. 1010 * 3. Dirty line -- all other lines are marked dirty. 1011 */ 1012 sc_region = bot - top + 1; 1013 i = top; 1014 tmp1 = curscr->lines[top]; 1015 cur_period = top; 1016 for (j = top; j <= bot; j++) { 1017 target = (i - top + n + sc_region) % sc_region + top; 1018 tmp2 = curscr->lines[target]; 1019 curscr->lines[target] = tmp1; 1020 /* Mark block as clean and blank out scrolled lines. */ 1021 clp = curscr->lines[target]; 1022 #ifdef DEBUG 1023 __CTRACE("quickch: n=%d startw=%d curw=%d i = %d target=%d ", 1024 n, startw, curw, i, target); 1025 #endif 1026 if ((target >= startw && target < curw) || target < top 1027 || target > bot) { 1028 #ifdef DEBUG 1029 __CTRACE("-- notdirty\n"); 1030 #endif 1031 __virtscr->lines[target]->flags &= ~__ISDIRTY; 1032 } else 1033 if ((n > 0 && target >= top && target < top + n) || 1034 (n < 0 && target <= bot && target > bot + n)) { 1035 if (clp->hash != blank_hash || memcmp(clp->line, 1036 clp->line + 1, (__virtscr->maxx - 1) * 1037 __LDATASIZE) || memcmp(clp->line, buf, 1038 __LDATASIZE)) { 1039 for (i = __virtscr->maxx; i > BLANKSIZE; 1040 i -= BLANKSIZE) { 1041 (void)memcpy(clp->line + i - 1042 BLANKSIZE, buf, sizeof(buf)); 1043 } 1044 (void)memcpy(clp->line , buf, i * 1045 sizeof(buf[0])); 1046 #ifdef DEBUG 1047 __CTRACE("-- blanked out: dirty\n"); 1048 #endif 1049 clp->hash = blank_hash; 1050 __touchline(__virtscr, target, 0, (int) __virtscr->maxx - 1); 1051 } else { 1052 #ifdef DEBUG 1053 __CTRACE(" -- blank line already: dirty\n"); 1054 #endif 1055 __touchline(__virtscr, target, 0, (int) __virtscr->maxx - 1); 1056 } 1057 } else { 1058 #ifdef DEBUG 1059 __CTRACE(" -- dirty\n"); 1060 #endif 1061 __touchline(__virtscr, target, 0, (int) __virtscr->maxx - 1); 1062 } 1063 if (target == cur_period) { 1064 i = target + 1; 1065 tmp1 = curscr->lines[i]; 1066 cur_period = i; 1067 } else { 1068 tmp1 = tmp2; 1069 i = target; 1070 } 1071 } 1072 #ifdef DEBUG 1073 __CTRACE("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n"); 1074 for (i = 0; i < curscr->maxy; i++) { 1075 __CTRACE("C: %d:", i); 1076 for (j = 0; j < curscr->maxx; j++) 1077 __CTRACE("%c", curscr->lines[i]->line[j].ch); 1078 __CTRACE("\n"); 1079 __CTRACE("W: %d:", i); 1080 for (j = 0; j < __virtscr->maxx; j++) 1081 __CTRACE("%c", __virtscr->lines[i]->line[j].ch); 1082 __CTRACE("\n"); 1083 } 1084 #endif 1085 if (n != 0) 1086 scrolln(starts, startw, curs, bot, top); 1087 } 1088 1089 /* 1090 * scrolln -- 1091 * Scroll n lines, where n is starts - startw. 1092 */ 1093 static void /* ARGSUSED */ 1094 scrolln(starts, startw, curs, bot, top) 1095 int starts, startw, curs, bot, top; 1096 { 1097 int i, oy, ox, n; 1098 1099 oy = curscr->cury; 1100 ox = curscr->curx; 1101 n = starts - startw; 1102 1103 /* 1104 * XXX 1105 * The initial tests that set __noqch don't let us reach here unless 1106 * we have either cs + ho + SF/sf/SR/sr, or AL + DL. SF/sf and SR/sr 1107 * scrolling can only shift the entire scrolling region, not just a 1108 * part of it, which means that the quickch() routine is going to be 1109 * sadly disappointed in us if we don't have cs as well. 1110 * 1111 * If cs, ho and SF/sf are set, can use the scrolling region. Because 1112 * the cursor position after cs is undefined, we need ho which gives us 1113 * the ability to move to somewhere without knowledge of the current 1114 * location of the cursor. Still call __mvcur() anyway, to update its 1115 * idea of where the cursor is. 1116 * 1117 * When the scrolling region has been set, the cursor has to be at the 1118 * last line of the region to make the scroll happen. 1119 * 1120 * Doing SF/SR or AL/DL appears faster on the screen than either sf/sr 1121 * or AL/DL, and, some terminals have AL/DL, sf/sr, and cs, but not 1122 * SF/SR. So, if we're scrolling almost all of the screen, try and use 1123 * AL/DL, otherwise use the scrolling region. The "almost all" is a 1124 * shameless hack for vi. 1125 */ 1126 if (n > 0) { 1127 if (__tc_cs != NULL && __tc_ho != NULL && (__tc_SF != NULL || 1128 ((__tc_AL == NULL || __tc_DL == NULL || 1129 top > 3 || bot + 3 < __virtscr->maxy) && 1130 __tc_sf != NULL))) { 1131 tputs(__tscroll(__tc_cs, top, bot + 1), 0, __cputchar); 1132 __mvcur(oy, ox, 0, 0, 1); 1133 tputs(__tc_ho, 0, __cputchar); 1134 __mvcur(0, 0, bot, 0, 1); 1135 if (__tc_SF != NULL) 1136 tputs(__tscroll(__tc_SF, n, 0), 0, __cputchar); 1137 else 1138 for (i = 0; i < n; i++) 1139 tputs(__tc_sf, 0, __cputchar); 1140 tputs(__tscroll(__tc_cs, 0, (int) __virtscr->maxy), 0, 1141 __cputchar); 1142 __mvcur(bot, 0, 0, 0, 1); 1143 tputs(__tc_ho, 0, __cputchar); 1144 __mvcur(0, 0, oy, ox, 1); 1145 return; 1146 } 1147 1148 /* Scroll up the block. */ 1149 if (__tc_SF != NULL && top == 0) { 1150 __mvcur(oy, ox, bot, 0, 1); 1151 tputs(__tscroll(__tc_SF, n, 0), 0, __cputchar); 1152 } else 1153 if (__tc_DL != NULL) { 1154 __mvcur(oy, ox, top, 0, 1); 1155 tputs(__tscroll(__tc_DL, n, 0), 0, __cputchar); 1156 } else 1157 if (__tc_dl != NULL) { 1158 __mvcur(oy, ox, top, 0, 1); 1159 for (i = 0; i < n; i++) 1160 tputs(__tc_dl, 0, __cputchar); 1161 } else 1162 if (__tc_sf != NULL && top == 0) { 1163 __mvcur(oy, ox, bot, 0, 1); 1164 for (i = 0; i < n; i++) 1165 tputs(__tc_sf, 0, 1166 __cputchar); 1167 } else 1168 abort(); 1169 1170 /* Push down the bottom region. */ 1171 __mvcur(top, 0, bot - n + 1, 0, 1); 1172 if (__tc_AL != NULL) 1173 tputs(__tscroll(__tc_AL, n, 0), 0, __cputchar); 1174 else 1175 if (__tc_al != NULL) 1176 for (i = 0; i < n; i++) 1177 tputs(__tc_al, 0, __cputchar); 1178 else 1179 abort(); 1180 __mvcur(bot - n + 1, 0, oy, ox, 1); 1181 } else { 1182 /* 1183 * !!! 1184 * n < 0 1185 * 1186 * If cs, ho and SR/sr are set, can use the scrolling region. 1187 * See the above comments for details. 1188 */ 1189 if (__tc_cs != NULL && __tc_ho != NULL && (__tc_SR != NULL || 1190 ((__tc_AL == NULL || __tc_DL == NULL || top > 3 || 1191 bot + 3 < __virtscr->maxy) && __tc_sr != NULL))) { 1192 tputs(__tscroll(__tc_cs, top, bot + 1), 0, __cputchar); 1193 __mvcur(oy, ox, 0, 0, 1); 1194 tputs(__tc_ho, 0, __cputchar); 1195 __mvcur(0, 0, top, 0, 1); 1196 1197 if (__tc_SR != NULL) 1198 tputs(__tscroll(__tc_SR, -n, 0), 0, __cputchar); 1199 else 1200 for (i = n; i < 0; i++) 1201 tputs(__tc_sr, 0, __cputchar); 1202 tputs(__tscroll(__tc_cs, 0, (int) __virtscr->maxy), 0, 1203 __cputchar); 1204 __mvcur(top, 0, 0, 0, 1); 1205 tputs(__tc_ho, 0, __cputchar); 1206 __mvcur(0, 0, oy, ox, 1); 1207 return; 1208 } 1209 1210 /* Preserve the bottom lines. */ 1211 __mvcur(oy, ox, bot + n + 1, 0, 1); 1212 if (__tc_SR != NULL && bot == __virtscr->maxy) 1213 tputs(__tscroll(__tc_SR, -n, 0), 0, __cputchar); 1214 else 1215 if (__tc_DL != NULL) 1216 tputs(__tscroll(__tc_DL, -n, 0), 0, __cputchar); 1217 else 1218 if (__tc_dl != NULL) 1219 for (i = n; i < 0; i++) 1220 tputs(__tc_dl, 0, __cputchar); 1221 else 1222 if (__tc_sr != NULL && 1223 bot == __virtscr->maxy) 1224 for (i = n; i < 0; i++) 1225 tputs(__tc_sr, 0, 1226 __cputchar); 1227 else 1228 abort(); 1229 1230 /* Scroll the block down. */ 1231 __mvcur(bot + n + 1, 0, top, 0, 1); 1232 if (__tc_AL != NULL) 1233 tputs(__tscroll(__tc_AL, -n, 0), 0, __cputchar); 1234 else 1235 if (__tc_al != NULL) 1236 for (i = n; i < 0; i++) 1237 tputs(__tc_al, 0, __cputchar); 1238 else 1239 abort(); 1240 __mvcur(top, 0, oy, ox, 1); 1241 } 1242 } 1243 1244 /* 1245 * __unsetattr -- 1246 * Unset attributes on curscr. Leave standout, attribute and colour 1247 * modes if necessary (!ms). Always leave altcharset (xterm at least 1248 * ignores a cursor move if we don't). 1249 */ 1250 void /* ARGSUSED */ 1251 __unsetattr(int checkms) 1252 { 1253 int isms; 1254 1255 if (checkms) 1256 if (!__tc_ms) { 1257 isms = 1; 1258 } else { 1259 isms = 0; 1260 } 1261 else 1262 isms = 1; 1263 #ifdef DEBUG 1264 __CTRACE("__unsetattr: checkms = %d, ms = %s, wattr = %08x\n", 1265 checkms, __tc_ms ? "TRUE" : "FALSE", curscr->wattr); 1266 #endif 1267 1268 /* 1269 * Don't leave the screen in standout mode (check against ms). Check 1270 * to see if we also turn off underscore, attributes and colour. 1271 */ 1272 if (curscr->wattr & __STANDOUT && isms) { 1273 tputs(__tc_se, 0, __cputchar); 1274 curscr->wattr &= __mask_se; 1275 } 1276 /* 1277 * Don't leave the screen in underscore mode (check against ms). 1278 * Check to see if we also turn off attributes. Assume that we 1279 * also turn off colour. 1280 */ 1281 if (curscr->wattr & __UNDERSCORE && isms) { 1282 tputs(__tc_ue, 0, __cputchar); 1283 curscr->wattr &= __mask_ue; 1284 } 1285 /* 1286 * Don't leave the screen with attributes set (check against ms). 1287 * Assume that also turn off colour. 1288 */ 1289 if (curscr->wattr & __TERMATTR && isms) { 1290 tputs(__tc_me, 0, __cputchar); 1291 curscr->wattr &= __mask_me; 1292 } 1293 /* Don't leave the screen with altcharset set (don't check ms). */ 1294 if (curscr->wattr & __ALTCHARSET) { 1295 tputs(__tc_ae, 0, __cputchar); 1296 curscr->wattr &= ~__ALTCHARSET; 1297 } 1298 /* Don't leave the screen with colour set (check against ms). */ 1299 if (__using_color && isms) 1300 __unset_color(curscr); 1301 } 1302