1: /* 2: * Virtual terminal handler 3: * Written by Kenneth Almquist, AGS Computers (HO 4C601, X7105). 4: * Modified by Stephen Hemminger, to use TERMCAP (without curses) 5: */ 6: 7: #ifdef SCCSID 8: static char *SccsId = "@(#)virtterm.c 1.10 1/17/86"; 9: #endif /* SCCSID */ 10: 11: /*LINTLIBRARY*/ 12: 13: #include <stdio.h> 14: #include <ctype.h> 15: #include <sys/types.h> 16: #include <sys/ioctl.h> 17: #include <signal.h> 18: #ifdef USG 19: #include <termio.h> 20: #else /* !USG */ 21: #include <sgtty.h> 22: #endif /* !USG */ 23: 24: /* 25: * These values for MAXPLEN and MAXLLEN are used to dimension arrays 26: * that hold strings of relative cursor motions. The actual arrays that 27: * are used to hold screen images are malloc'd. 28: */ 29: #define MAXPLEN 90 30: #define MAXLLEN 160 31: 32: #define BOTLINE (ROWS - 1) 33: #define DIRTY 01 34: 35: /* terminal escape sequences from termcap */ 36: #define HO _tstr[0] /* home */ 37: #define CL _tstr[1] /* clear screen */ 38: #define CD _tstr[2] /* clear to end of screen */ 39: #define CE _tstr[3] /* clear to end of line */ 40: #define xUP _tstr[4] /* up one line */ 41: #define DO _tstr[5] /* down one line */ 42: #define US _tstr[6] /* underline */ 43: #define UE _tstr[7] /* underline end */ 44: #define BT _tstr[8] /* backtab */ 45: #define xBC _tstr[9] /* backspace */ 46: #define AL _tstr[10] /* insert line */ 47: #define DL _tstr[11] /* delete line */ 48: #define CM _tstr[12] /* cursor move */ 49: #define CH _tstr[13] /* cursor horizontal move */ 50: #define CV _tstr[14] /* cursor vertical move */ 51: #define CS _tstr[15] /* scrolling region */ 52: #define SF _tstr[16] /* scroll forwards */ 53: #define SR _tstr[17] /* scroll backwards */ 54: #define TI _tstr[18] /* start cursor mode */ 55: #define TE _tstr[19] /* end cursor mode */ 56: #define TA _tstr[20] /* tab char (if not \t) */ 57: #define CR _tstr[21] /* carriage return (if not \r) */ 58: #define xPC _tstr[22] /* for reading pad character */ 59: char PC; /* pad character */ 60: char *BC, *UP; /* external variables for tgoto */ 61: 62: static char sname[] = "hoclcdceupdousuebtbcaldlcmchcvcssfsrtitetacrpc"; 63: char *_tstr[23]; 64: int HOlen; /* length of HO string */ 65: 66: 67: /* terminal flags */ 68: #define BS _tflg[0] /* can backspace */ 69: #define AM _tflg[1] /* has auto margins */ 70: #define XN _tflg[2] /* no newline after wrap */ 71: #define RET !_tflg[3] /* has carriage return */ 72: #define NS _tflg[4] /* has SF (scroll forward) */ 73: #define PT _tflg[5] /* has tabs */ 74: #define XT _tflg[6] /* tabs are destructive */ 75: int GT = 1; /* tab stops on terminal are set */ 76: 77: static char bname[] = "bsamxnncnsptxt"; 78: char _tflg[7]; 79: 80: 81: extern char *tgoto(), *tgetstr(); 82: extern char *getenv(), *strcpy(); 83: 84: #define ULINE 0200 85: 86: /* Constants accessable by user */ 87: int hasscroll; /* scrolling type, 0 == no scrolling */ 88: int ROWS; /* number of lines on screen */ 89: int COLS; /* width of screen */ 90: 91: struct line { 92: char len; 93: char flags; 94: char *l; /* pointer to actual line text, NO NULL @ end */ 95: }; 96: 97: int _row, _col; 98: int _srow, _scol; 99: struct line *_virt; /* what we want the screen to look like */ 100: struct line *_actual; /* What it actually looks like */ 101: int _uline = 0; 102: int _junked = 1; 103: int _curjunked; 104: int _dir = 1; 105: int _shifttop, _shiftbot; 106: int _shift; 107: int _scratched; 108: int vputc(); 109: 110: /* 111: * Tell refresh to shift lines in region upwards count lines. Count 112: * may be negative. The virtual image is not shifted; this may change 113: * later. The variable _scratched is set to supress all attempts to 114: * shift. 115: */ 116: 117: ushift(top, bot, count) 118: { 119: if (_scratched) 120: return; 121: if (_shift != 0 && (_shifttop != top || _shiftbot != bot)) { 122: _scratched++; 123: return; 124: } 125: _shifttop = top; 126: _shiftbot = bot; 127: _shift += count; 128: } 129: 130: /* 131: * generate a beep on the terminal 132: */ 133: beep() 134: { 135: vputc('\7'); 136: } 137: 138: /* 139: * Move to one line below the bottom of the screen. 140: */ 141: botscreen() 142: { 143: _amove(BOTLINE, 0); 144: vputc('\n'); 145: vflush(); 146: } 147: 148: move(row, col) 149: { 150: if (row < 0 || row >= ROWS || col < 0 || col >= COLS) 151: return; 152: _row = row; 153: _col = col; 154: } 155: 156: 157: 158: /* 159: * Output string at specified location. 160: */ 161: mvaddstr(row, col, str) 162: char *str; 163: { 164: move(row, col); 165: addstr(str); 166: } 167: 168: addstr(s) 169: char *s; 170: { 171: register char *p; 172: register struct line *lp; 173: register int col = _col; 174: 175: lp = &_virt[_row]; 176: if (lp->len < col) { 177: p = &lp->l[lp->len]; 178: while (lp->len < col) { 179: *p++ = ' '; 180: lp->len++; 181: } 182: } 183: for (p = s; *p != '\0'; p++) { 184: if (*p == '\n') { 185: lp->len = col; 186: lp->flags |= DIRTY; 187: col = 0; 188: if (++_row >= ROWS) 189: _row = 0; 190: lp = &_virt[_row]; 191: } 192: else { 193: lp->l[col] = *p; 194: lp->flags |= DIRTY; 195: if (++col >= COLS) { 196: lp->len = COLS; 197: col = 0; 198: if (++_row >= ROWS) 199: _row = 0; 200: lp = &_virt[_row]; 201: } 202: } 203: } 204: if (lp->len <= col) 205: lp->len = col; 206: _col = col; 207: } 208: 209: addch(c) 210: { 211: register struct line *lp; 212: register char *p; 213: 214: lp = &_virt[_row]; 215: if (lp->len < _col) { 216: p = &lp->l[lp->len]; 217: while (lp->len < _col) { 218: *p++ = ' '; 219: lp->len++; 220: } 221: } 222: lp->l[_col] = c; 223: if (lp->len == _col) 224: lp->len++; 225: if (++_col >= COLS) { 226: _col = 0; 227: if (++_row >= ROWS) 228: _row = 0; 229: } 230: lp->flags |= DIRTY; 231: } 232: 233: /* 234: * Clear an entire line. 235: */ 236: clrline(row) 237: { 238: register struct line *lp; 239: 240: lp = &_virt[row]; 241: if (lp->len > 0) { 242: lp->len = 0; 243: lp->flags |= DIRTY; 244: } 245: } 246: 247: erase() 248: { 249: register i; 250: 251: for (i = 0; i < ROWS; i++) { 252: _virt[i].len = 0; 253: _virt[i].flags |= DIRTY; 254: } 255: } 256: 257: refresh() 258: { 259: register i; 260: register char *p, *q; 261: register int j, len; 262: 263: if (checkin()) 264: return; 265: i = 1; 266: if (_junked) { 267: _sclear(); 268: _junked = 0; 269: } else if (! _scratched) { 270: if (_shift > 0) { 271: _ushift(_shifttop, _shiftbot, _shift); 272: } else if (_shift < 0) { 273: i = _dshift(_shifttop, _shiftbot, -_shift); 274: } else { 275: i = _dir; 276: } 277: } 278: _dir = i; 279: _shift = 0; 280: if (checkin()) 281: return; 282: _fixlines(); 283: for (i = _dir > 0 ? 0 : BOTLINE; i >= 0 && i < ROWS; i += _dir) { 284: if ((_virt[i].flags & DIRTY) == 0) 285: continue; 286: _ckclrlin(i); /* decide whether to do a clear line */ 287: /* probably should consider cd too */ 288: len = _virt[i].len; 289: if (_actual[i].len < len) 290: len = _actual[i].len; 291: p = _virt[i].l; 292: q = _actual[i].l; 293: for (j = 0; j < len; j++) { 294: if (*p != *q) { 295: /* Inline test for speed */ 296: if (i != _srow || j != _scol || _curjunked) 297: _amove(i, j); 298: _aputc(*p); 299: *q = *p; 300: } 301: p++; 302: q++; 303: } 304: len = _virt[i].len; 305: if (_actual[i].len > len) { 306: _clrtoeol(i, len); 307: } else { 308: for (; j < len; j++) { 309: if (*p != ' ') { 310: /* Inline test for speed */ 311: if (i != _srow || j != _scol || _curjunked) 312: _amove(i, j); 313: _aputc(*p); 314: } 315: *q++ = *p++; 316: } 317: _actual[i].len = len; 318: } 319: if (checkin()) 320: return; 321: } 322: _dir = 1; 323: _amove(_row, _col); 324: vflush(); /* flush output buffer */ 325: _scratched = 0; 326: } 327: 328: _dshift(top, bot, count) 329: { 330: register i; 331: 332: if (count >= bot - top || hasscroll < 4) { /* must have CS or AL/DL */ 333: _scratched++; 334: return 1; 335: } 336: for (i = bot - count; _actual[i].len == 0; i--) 337: if (i == top) 338: return 1; 339: for (i = top; i <= bot; i++) 340: _virt[i].flags |= DIRTY; 341: for (i = bot; i >= top + count; i--) { 342: /* FIXME, this should be done by recirculating the pointers */ 343: register j; 344: j = _actual[i].len = _actual[i - count].len; 345: _actual[i].flags = _actual[i - count].flags; 346: strncpy(_actual[i].l, _actual[i - count].l, j); 347: } 348: for (; i >= top; i--) 349: _actual[i].len = 0; 350: 351: if (hasscroll != 5) { /* can we define scrolling region, and scroll back */ 352: tputs(tgoto(CS, bot, top), 1, vputc);/* define scroll region */ 353: _curjunked = 1; 354: _amove(top, 0); 355: for (i = count; --i >= 0;) 356: tputs(SR, 1, vputc);/* scroll back */ 357: tputs(tgoto(CS, BOTLINE, 0), 1, vputc); 358: _curjunked = 1; 359: } else { 360: _amove(bot - count + 1, 0); 361: if (CD && bot == BOTLINE) 362: tputs(CD, 1, vputc); 363: else { 364: for (i = count; --i >= 0;) 365: tputs(DL, ROWS - _srow, vputc); 366: } 367: _amove(top, 0); 368: for (i = count; --i >= 0;) 369: tputs(AL, ROWS - _srow, vputc); 370: } 371: return -1; 372: } 373: 374: 375: _ushift(top, bot, count) 376: { 377: register i; 378: 379: if (count >= bot - top || hasscroll == 0) { 380: _scratched++; 381: return; 382: } 383: for (i = top + count; _actual[i].len == 0; i++) 384: if (i == bot) 385: return; 386: if (hasscroll == 1 || hasscroll == 3) { 387: /* we cheat and shift the entire screen */ 388: /* be sure we are shifting more lines into than out of position */ 389: if ((bot - top + 1) - count <= ROWS - (bot - top + 1)) 390: return; 391: top = 0, bot = BOTLINE; 392: } 393: for (i = top; i <= bot; i++) 394: _virt[i].flags |= DIRTY; 395: for (i = top; i <= bot - count; i++) { 396: /* FIXME, this should be done by recirculating the pointers */ 397: register int j; 398: j = _actual[i].len = _actual[i + count].len; 399: _actual[i].flags = _actual[i + count].flags; 400: strncpy(_actual[i].l, _actual[i + count].l, j); 401: } 402: for (; i <= bot; i++) 403: for (; i <= bot; i++) 404: _actual[i].len = 0; 405: 406: if (hasscroll != 5) { 407: if (top != 0 || bot != BOTLINE) { 408: tputs(tgoto(CS, bot, top), 0, vputc); 409: _curjunked = 1; 410: } 411: _amove(bot, 0); /* move to bottom */ 412: for (i = 0; i < count; i++) { 413: if (SF) /* scroll forward */ 414: tputs(SF, 1, vputc); 415: else 416: vputc('\n'); 417: } 418: if (top != 0 || bot != BOTLINE) { 419: tputs(tgoto(CS, BOTLINE, 0), 0, vputc); 420: _curjunked = 1; 421: } 422: } else { 423: _amove(top, 0); 424: for (i = count; --i >= 0;) 425: tputs(DL, ROWS - _srow, vputc); 426: if (bot < BOTLINE) { 427: _amove(bot - count + 1, 0); 428: for (i = count; --i >= 0;) 429: tputs(AL, ROWS - _srow, vputc); 430: } 431: } 432: } 433: 434: _sclear() 435: { 436: register struct line *lp; 437: 438: tputs(CL, 0, vputc); 439: _srow = _scol = 0; 440: for (lp = _actual; lp < &_actual[ROWS]; lp++) { 441: lp->len = 0; 442: } 443: for (lp = _virt; lp < &_virt[ROWS]; lp++) { 444: if (lp->len != 0) 445: lp->flags |= DIRTY; 446: } 447: } 448: 449: _clrtoeol(row, col) 450: { 451: register struct line *lp = &_actual[row]; 452: register i; 453: 454: if (CE && lp->len > col + 1) { 455: _amove(row, col); 456: tputs(CE, 1, vputc); 457: } else { 458: for (i = col ; i < lp->len ; i++) { 459: if (lp->l[i] != ' ') { 460: _amove(row, i); 461: _aputc(' '); 462: } 463: } 464: } 465: lp->len = col; 466: } 467: 468: _fixlines() 469: { 470: register struct line *lp; 471: register char *p; 472: register int i; 473: 474: for (i = 0; i < ROWS; i++) { 475: lp = &_virt[i]; 476: if (lp->flags & DIRTY) { 477: for (p = &lp->l[lp->len]; --p >= lp->l && *p == ' ';) 478: ; 479: lp->len = (int) (p - lp->l) + 1; 480: if (lp->len == _actual[i].len && strncmp(lp->l, _actual[i].l, lp->len) == 0) 481: lp->flags &= ~DIRTY; 482: } 483: } 484: } 485: 486: 487: /* 488: * Consider clearing the line before overwriting it. 489: * We always clear a line if it has underlined characters in it 490: * because these can cause problems. Otherwise decide whether 491: * that will decrease the number of characters to change. This 492: * routine could probably be simplified with no great loss. 493: */ 494: 495: _ckclrlin(i) 496: { 497: int eval; 498: int len; 499: int first; 500: register struct line *vp, *ap; 501: register int j; 502: 503: if (!CE) 504: return; 505: ap = &_actual[i]; 506: vp = &_virt[i]; 507: len = ap->len; 508: eval = -strlen(CE); 509: if (len > vp->len) { 510: len = vp->len; 511: eval = 0; 512: } 513: for (j = 0; j < len && vp->l[j] == ap->l[j]; j++) 514: ; 515: if (j == len) 516: return; 517: first = j; 518: while (j < len) { 519: if (vp->l[j] == ' ') { 520: if (ap->l[j] != ' ') { 521: while (++j < len && vp->l[j] == ' ' && ap->l[j] != ' ') { 522: eval++; 523: } 524: if (j == len) 525: eval++; 526: continue; 527: } 528: } 529: else { 530: if (vp->l[j] == ap->l[j]) { 531: while (++j < len && vp->l[j] == ap->l[j]) { 532: eval--; 533: } 534: continue; 535: } 536: } 537: j++; 538: } 539: if (US) { 540: for (j = 0 ; j < ap->len ; j++) { 541: if (ap->l[j] & ULINE) { 542: eval = 999; 543: if (first > j) 544: first = j; 545: break; 546: } 547: } 548: } 549: for (j = first; --j >= 0;) 550: if (vp->l[j] != ' ') 551: break; 552: if (j < 0) 553: first = 0; 554: if (eval > 0) { 555: _amove(i, first); 556: tputs(CE, 0, vputc); 557: _actual[i].len = first; 558: } 559: } 560: 561: 562: 563: /* 564: * Move routine 565: * first compute direct cursor address string and cost 566: * then relative motion string and cost, 567: * then home then relative and cost 568: * choose smallest and do it. 569: * 570: * The plod stuff is to build the strings (with padding) then decide 571: */ 572: static char *plodstr; /* current location in relmove string */ 573: 574: plodput(c) 575: { 576: *plodstr++ = c; 577: } 578: 579: /* FIXME: speedup 1-char horiz moves: print the char that's there. */ 580: /* FIXME: avoid funniness if cm works. */ 581: /* FIXME: Avoid setul(0) if cursor motion OK in standout (XM?) */ 582: _amove(row, col) 583: { 584: char direct[20]; 585: char rel[MAXPLEN*10 + MAXLLEN*10]; /* longest move is full screen */ 586: char ho[MAXPLEN*10 + MAXLLEN*10]; 587: int cost, newcost; 588: register char *movstr; 589: 590: if (row == _srow && col == _scol && _curjunked == 0) 591: return; 592: if (_uline) 593: _setul(0); /* Inline test for speed */ 594: 595: cost = 999; 596: if (CM) { 597: plodstr = direct; 598: tputs(tgoto(CM, col, row), 0, plodput); 599: cost = plodstr - direct; 600: movstr = direct; 601: } 602: if (_curjunked == 0) { 603: plodstr = rel; 604: if (_vmove(_srow, row) >= 0 605: && (plodstr - rel) < cost /* after vmove */ 606: && _hmove(_scol, col, row) >= 0 607: && (newcost = plodstr - rel) < cost) { /* after both */ 608: cost = newcost; 609: movstr = rel; 610: } 611: } 612: if (cost > HOlen) { /* is it worth calculating */ 613: plodstr = ho; 614: tputs(HO, 0, plodput); 615: if (_vmove(0, row) >= 0 616: && (plodstr - ho) < cost /* after ho, vmove */ 617: && _hmove(0, col, row) >= 0 618: && (newcost = plodstr - ho) < cost) { /* after all three */ 619: cost = newcost; 620: movstr = ho; 621: } 622: } 623: 624: if (cost < 999) 625: while (--cost >= 0) 626: vputc(*movstr++); 627: 628: _srow = row; 629: _scol = col; 630: _curjunked = 0; 631: } 632: 633: _vmove(orow, nrow) 634: { 635: char direct[128]; 636: char *saveplod = plodstr; 637: 638: if (CV) { 639: plodstr = direct; 640: tputs(tgoto(CV, nrow, nrow), 0, plodput); 641: *plodstr = '\0'; 642: plodstr = saveplod; 643: } 644: if (orow > nrow) { /* cursor up */ 645: if (! UP) 646: return -1; 647: while (orow > nrow) { 648: tputs(UP, 1, plodput); 649: orow--; 650: } 651: } 652: while (orow < nrow) { /* cursor down */ 653: if (DO) 654: tputs(DO, 1, plodput); 655: else 656: *plodstr++ = '\n'; 657: orow++; 658: } 659: if (CV && plodstr - saveplod >= strlen(direct)) { 660: register char *p; 661: plodstr = saveplod; 662: for (p = direct ; *plodstr = *p++ ; plodstr++) 663: ; 664: } 665: return 0; 666: } 667: 668: _hmove(ocol, ncol, row) 669: { 670: char direct[128]; 671: char ret[MAXLLEN*10]; 672: char *saveplod = plodstr; 673: char *movstr; 674: int cost, newcost; 675: 676: cost = 999; 677: if (CH) { 678: plodstr = direct; 679: tputs(tgoto(CH, ncol, ncol), 0, plodput); 680: cost = plodstr - direct; 681: movstr = direct; 682: plodstr = saveplod; 683: } 684: if (RET && ocol > ncol) { /* consider doing carriage return */ 685: plodstr = ret; 686: if (CR) 687: tputs(CR, 1, plodput); 688: else 689: *plodstr++ = '\r'; 690: if (_relhmove(0, ncol, row) >= 0 691: && (newcost = plodstr - ret) < cost) { 692: cost = newcost; 693: movstr = ret; 694: } 695: plodstr = saveplod; 696: } 697: if (_relhmove(ocol, ncol, row) < 0) { 698: if (cost == 999) 699: return -1; 700: goto copy; 701: } 702: if (plodstr - saveplod > cost) { 703: copy: plodstr = saveplod; 704: while (--cost >= 0) 705: *plodstr++ = *movstr++; 706: } 707: return 0; 708: } 709: 710: _relhmove(ocol, ncol, row) 711: { 712: int tab; 713: 714: if (ocol < ncol && PT && GT) { /* tab (nondestructive) */ 715: while ((tab = (ocol + 8) & ~07) <= ncol) { 716: if (TA) 717: tputs(TA, 1, plodput); 718: else 719: *plodstr++ = '\t'; 720: ocol = tab; 721: } 722: if (tab < COLS && tab - ncol < ncol - ocol) { 723: if (TA) 724: tputs(TA, 1, plodput); 725: else 726: *plodstr++ = '\t'; 727: ocol = tab; 728: } 729: } else if (BT && GT && ocol > ncol) { /* backwards tab */ 730: while ((tab = (ocol - 1) &~ 07) >= ncol) { 731: if (BS && tab == ocol - 1) { 732: if (BC) 733: tputs(BC, 1, plodput); 734: else 735: *plodstr++ = '\b'; 736: } else 737: tputs(BT, 1, plodput); 738: ocol = tab; 739: } 740: if (ncol - tab + 1 < ocol - ncol) { 741: tputs(BT, 1, plodput); 742: ocol = tab; 743: } 744: } 745: if (ocol > ncol) { /* cursor left */ 746: if (! BS) 747: return -1; 748: while (ocol > ncol) { 749: if (BC != NULL) 750: tputs(BC, 1, plodput); 751: else 752: *plodstr++ = '\b'; 753: ocol--; 754: } 755: } 756: if (ocol < ncol) { /* cursor right */ 757: register struct line *lp = &_actual[row]; 758: /* 759: * This code doesn't move over underlined characters properly, 760: * but in practice this doesn't seem to matter. 761: */ 762: while (ocol < ncol) { 763: if (ocol < lp->len) 764: *plodstr++ = lp->l[ocol]; 765: else 766: *plodstr++ = ' '; 767: ocol++; 768: } 769: } 770: return 0; 771: } 772: 773: _aputc(c) 774: { 775: if (_uline != (c & ULINE)) /* Inline for speed */ 776: _setul(c & ULINE); 777: if (++_scol >= COLS) { 778: if (_srow == ROWS - 1) { 779: /* Don't ever paint last char of last line */ 780: _scol--; 781: return; 782: } 783: _curjunked++; /* Don't assume AM is right */ 784: } 785: vputc(c & ~ULINE); 786: } 787: 788: 789: _setul(on) 790: { 791: if (on) { 792: if (_uline == 0 && US != NULL) { 793: tputs(US, 1, vputc); 794: _uline = ULINE; 795: } 796: } 797: else { 798: if (_uline != 0 && UE != NULL) { 799: tputs(UE, 1, vputc); 800: _uline = 0; 801: } 802: } 803: } 804: 805: /* 806: * Initialize termcap strings for later use. 807: */ 808: initterm() 809: { 810: static char tcbuf[1024]; /* termcap buffer */ 811: register char *cp; 812: #ifdef USG 813: struct termio tio; 814: #else /* !USG */ 815: struct sgttyb ttyb; 816: #endif /* !USG */ 817: 818: if ((cp = getenv("TERM")) == NULL) 819: xerror("TERM not set in environment"); 820: 821: switch (tgetent(tcbuf, cp)) { 822: case 0: 823: xerror("Terminal not found in TERMCAP"); 824: case -1: 825: xerror("Can't open /etc/termcap"); 826: case 1: 827: break; 828: } 829: #ifdef TIOCGWINSZ 830: { 831: struct winsize ws; 832: int winch(); 833: 834: COLS = ROWS = -1; 835: if(ioctl(1, TIOCGWINSZ, &ws) == 0) { 836: ROWS = ws.ws_row; 837: COLS = ws.ws_col; 838: } 839: if(ROWS <= 0) 840: ROWS = tgetnum("li"); 841: if(COLS <= 0) 842: COLS = tgetnum("co"); 843: if ((ROWS <= 0) || (COLS <= 0)) 844: xerror("Can't get screen size"); 845: 846: signal(SIGWINCH, winch); /* allow for changing window size */ 847: } 848: #else /* !TIOCGWINSZ */ 849: if ((ROWS = tgetnum("li")) == -1 850: || (COLS = tgetnum("co")) == -1) 851: xerror("Can't get screen size"); 852: #endif /* !TIOCGWINSZ */ 853: _zap(); 854: 855: if (CL == NULL) 856: xerror ("No clear screen defined"); 857: 858: if (HO == NULL && CM == NULL) 859: xerror("No home or cursor addressing"); 860: if (HO) 861: HOlen = strlen(HO); 862: else 863: HOlen = 999; 864: 865: PC = xPC ? xPC[0] : 0; 866: BC = xBC; 867: UP = xUP; 868: 869: if (tgetnum("ug") > 0) 870: US = UE = NULL; 871: 872: if (XT) /* Destructive tab code not included */ 873: PT = 0; /* to keep things simple */ 874: 875: #ifdef USG 876: if (ioctl(0, TCGETA, &tio) == 0) 877: GT = tio.c_oflag&TAB3; 878: #else /* !USG */ 879: if (ioctl(0, TIOCGETP, &ttyb) == 0) 880: GT = ttyb.sg_flags&XTABS; 881: #endif /* !USG */ 882: 883: { 884: char *thelines; 885: int i; 886: char *malloc(); 887: 888: thelines = malloc(2 * ROWS * COLS); 889: _virt = (struct line *)malloc(2 * ROWS * sizeof (struct line)); 890: _actual = _virt + ROWS; 891: for (i = 0; i < ROWS; i++) { 892: _virt[i].len = 0; 893: _virt[i].flags = 0; 894: _actual[i].len = 0; 895: _actual[i].flags = 0; 896: _virt[i].l = thelines; 897: thelines += COLS; 898: _actual[i].l = thelines; 899: thelines += COLS; 900: } 901: } 902: 903: /* Select article scrolling algorithm. We prefer scrolling region 904: over insert/delete line because it's faster on the HP */ 905: hasscroll = 0; 906: if (!NS) { 907: hasscroll = 1; 908: if (SR) 909: hasscroll = 3; 910: if (CS) 911: hasscroll++; 912: } 913: if (AL && DL && hasscroll != 4) 914: hasscroll = 5; 915: } 916: 917: rawterm() 918: { 919: if (TI != NULL) 920: tputs(TI, 0, vputc); 921: } 922: 923: cookedterm() 924: { 925: if (TE != NULL) { 926: tputs(TE, 0, vputc); 927: vflush(); 928: } 929: } 930: 931: /* get strings from termcap */ 932: _zap() 933: { 934: static char tstrbuf[1024]; 935: static char *tp; 936: register char *namp, **sp, *bp; 937: 938: tp = tstrbuf; 939: sp = _tstr; 940: for (namp = sname; *namp; namp += 2) { 941: *sp++ = tgetstr(namp, &tp); 942: } 943: bp = _tflg; 944: for (namp = bname; *namp; namp += 2) { 945: *bp++ = tgetflag(namp, &tp); 946: } 947: } 948: #ifdef TIOCGWINSZ 949: /* 950: * window changed size -- update ROWS and COLS 951: * and then redraw screen 952: */ 953: winch() 954: { 955: struct winsize ws; 956: int cols, rows; 957: 958: cols = rows = -1; 959: if(ioctl(1, TIOCGWINSZ, &ws) == 0) { 960: rows = ws.ws_row; 961: cols = ws.ws_col; 962: } 963: if (rows == ROWS && cols == COLS) { /* just redraw it if no change */ 964: _junked = 1; /* redraw */ 965: updscr(); 966: return; 967: } 968: 969: if(rows > 0) 970: ROWS = rows; 971: if(cols > 0) 972: COLS = cols; 973: 974: if (ROWS > MAXPLEN) 975: ROWS = MAXPLEN; 976: if (COLS > MAXLLEN) { 977: COLS = MAXLLEN; 978: AM = XN = 1; 979: } 980: 981: winch_upd(); 982: } 983: #endif TIOCGWINSZ