|
|
1.1 ! root 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.14 9/24/87"; ! 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: short len; /* should really be u_char */ ! 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: ! 809: /* ! 810: * Hacks to help with some Tek terminals ! 811: * rad@tek ! 812: */ ! 813: int tputs_len; ! 814: /*ARGSUSED*/ ! 815: countit(c) { tputs_len++; } ! 816: ! 817: initterm() ! 818: { ! 819: static char tcbuf[1024]; /* termcap buffer */ ! 820: register char *cp; ! 821: #ifdef USG ! 822: struct termio tio; ! 823: #else /* !USG */ ! 824: struct sgttyb ttyb; ! 825: #endif /* !USG */ ! 826: ! 827: if ((cp = getenv("TERM")) == NULL) ! 828: xerror("TERM not set in environment"); ! 829: ! 830: switch (tgetent(tcbuf, cp)) { ! 831: case 0: ! 832: xerror("Terminal not found in TERMCAP"); ! 833: case -1: ! 834: xerror("Can't open /etc/termcap"); ! 835: case 1: ! 836: break; ! 837: } ! 838: #ifdef TIOCGWINSZ ! 839: { ! 840: struct winsize ws; ! 841: int winch(); ! 842: ! 843: COLS = ROWS = -1; ! 844: if(ioctl(1, TIOCGWINSZ, &ws) == 0) { ! 845: ROWS = ws.ws_row; ! 846: COLS = ws.ws_col; ! 847: } ! 848: if(ROWS <= 0) ! 849: ROWS = tgetnum("li"); ! 850: if(COLS <= 0) ! 851: COLS = tgetnum("co"); ! 852: if ((ROWS <= 0) || (COLS <= 0)) ! 853: xerror("Can't get screen size"); ! 854: ! 855: signal(SIGWINCH, winch); /* allow for changing window size */ ! 856: } ! 857: #else /* !TIOCGWINSZ */ ! 858: if ((ROWS = tgetnum("li")) == -1 ! 859: || (COLS = tgetnum("co")) == -1) ! 860: xerror("Can't get screen size"); ! 861: #endif /* !TIOCGWINSZ */ ! 862: _zap(); ! 863: ! 864: if (CL == NULL) ! 865: xerror ("No clear screen defined"); ! 866: ! 867: if (HO == NULL && CM == NULL) ! 868: xerror("No home or cursor addressing"); ! 869: if (HO) ! 870: HOlen = strlen(HO); ! 871: else ! 872: HOlen = 999; ! 873: ! 874: PC = xPC ? xPC[0] : 0; ! 875: BC = xBC; ! 876: UP = xUP; ! 877: /* ! 878: * _vmove() may be called with a full-screen traverse, ! 879: * meaning it will put the UP (along with any padding) into ! 880: * the buffer as many as MAXPLEN times. This means that ! 881: * if the UP string would be more than 10 chars long (defined ! 882: * in _amove() ), the buffer might be overflowed (assuming ! 883: * CH is also large). ! 884: * This actually occurs with the Tek4023 termcap, where :up=1000UP: ! 885: * is used to fake vi into using :cm instead, due to the fact ! 886: * that a 4023 can't do upline relative motion at all. ! 887: * -rdoty@tek ! 888: */ ! 889: if (UP) { ! 890: tputs_len = 0; ! 891: tputs(UP, 1, countit); ! 892: if (tputs_len > 10 ) ! 893: UP = 0; ! 894: } ! 895: ! 896: if (tgetnum("ug") > 0) ! 897: US = UE = NULL; ! 898: ! 899: if (XT) /* Destructive tab code not included */ ! 900: PT = 0; /* to keep things simple */ ! 901: ! 902: #ifdef USG ! 903: if (ioctl(0, TCGETA, &tio) == 0) ! 904: GT = tio.c_oflag&TAB3; ! 905: #else /* !USG */ ! 906: if (ioctl(0, TIOCGETP, &ttyb) == 0) ! 907: GT = ttyb.sg_flags&XTABS; ! 908: #endif /* !USG */ ! 909: ! 910: { ! 911: char *thelines; ! 912: int i; ! 913: char *malloc(); ! 914: ! 915: thelines = malloc(2 * ROWS * COLS); ! 916: _virt = (struct line *)malloc(2 * ROWS * sizeof (struct line)); ! 917: _actual = _virt + ROWS; ! 918: for (i = 0; i < ROWS; i++) { ! 919: _virt[i].len = 0; ! 920: _virt[i].flags = 0; ! 921: _actual[i].len = 0; ! 922: _actual[i].flags = 0; ! 923: _virt[i].l = thelines; ! 924: thelines += COLS; ! 925: _actual[i].l = thelines; ! 926: thelines += COLS; ! 927: } ! 928: } ! 929: ! 930: /* Select article scrolling algorithm. We prefer scrolling region ! 931: over insert/delete line because it's faster on the HP */ ! 932: hasscroll = 0; ! 933: if (!NS) { ! 934: hasscroll = 1; ! 935: if (SR) ! 936: hasscroll = 3; ! 937: if (CS) ! 938: hasscroll++; ! 939: } ! 940: if (AL && DL && hasscroll != 4) ! 941: hasscroll = 5; ! 942: } ! 943: ! 944: rawterm() ! 945: { ! 946: if (TI != NULL) ! 947: tputs(TI, 0, vputc); ! 948: } ! 949: ! 950: cookedterm() ! 951: { ! 952: if (TE != NULL) { ! 953: tputs(TE, 0, vputc); ! 954: vflush(); ! 955: } ! 956: } ! 957: ! 958: /* get strings from termcap */ ! 959: _zap() ! 960: { ! 961: static char tstrbuf[1024]; ! 962: static char *tp; ! 963: register char *namp, **sp, *bp; ! 964: ! 965: tp = tstrbuf; ! 966: sp = _tstr; ! 967: for (namp = sname; *namp; namp += 2) { ! 968: *sp++ = tgetstr(namp, &tp); ! 969: } ! 970: bp = _tflg; ! 971: for (namp = bname; *namp; namp += 2) { ! 972: *bp++ = tgetflag(namp, &tp); ! 973: } ! 974: } ! 975: #ifdef TIOCGWINSZ ! 976: /* ! 977: * window changed size -- update ROWS and COLS ! 978: * and then redraw screen ! 979: */ ! 980: winch() ! 981: { ! 982: struct winsize ws; ! 983: int cols, rows; ! 984: ! 985: cols = rows = -1; ! 986: if(ioctl(1, TIOCGWINSZ, &ws) == 0) { ! 987: rows = ws.ws_row; ! 988: cols = ws.ws_col; ! 989: } ! 990: if (rows == ROWS && cols == COLS) { /* just redraw it if no change */ ! 991: _junked = 1; /* redraw */ ! 992: updscr(); ! 993: return; ! 994: } ! 995: ! 996: if(rows > 0) ! 997: ROWS = rows; ! 998: if(cols > 0) ! 999: COLS = cols; ! 1000: ! 1001: if (ROWS > MAXPLEN) ! 1002: ROWS = MAXPLEN; ! 1003: if (COLS > MAXLLEN) { ! 1004: COLS = MAXLLEN; ! 1005: AM = XN = 1; ! 1006: } ! 1007: ! 1008: winch_upd(); ! 1009: } ! 1010: #endif /* TIOCGWINSZ */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.