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

Defined functions

_amove defined in line 582; used 15 times
_aputc defined in line 773; used 3 times
_ckclrlin defined in line 495; used 1 times
_clrtoeol defined in line 449; used 1 times
_dshift defined in line 328; used 1 times
_fixlines defined in line 468; used 1 times
_hmove defined in line 668; used 2 times
_relhmove defined in line 710; used 2 times
_sclear defined in line 434; used 1 times
_setul defined in line 789; used 2 times
_ushift defined in line 375; used 1 times
_vmove defined in line 633; used 2 times
_zap defined in line 932; used 1 times
addch defined in line 209; used 4 times
addstr defined in line 168; used 4 times
beep defined in line 133; used 1 times
botscreen defined in line 141; used 3 times
clrline defined in line 236; used 3 times
cookedterm defined in line 923; used 2 times
erase defined in line 247; never used
initterm defined in line 808; used 2 times
move defined in line 148; used 5 times
mvaddstr defined in line 161; used 7 times
plodput defined in line 574; used 13 times
rawterm defined in line 917; used 2 times
refresh defined in line 257; used 1 times
ushift defined in line 117; used 1 times
winch defined in line 953; used 3 times

Defined variables

BC defined in line 60; used 5 times
COLS defined in line 89; used 28 times
GT defined in line 75; used 4 times
HOlen defined in line 64; used 3 times
PC defined in line 59; used 1 times
ROWS defined in line 88; used 34 times
SccsId defined in line 8; never used
UP defined in line 60; used 3 times
_actual defined in line 100; used 33 times
_col defined in line 97; used 10 times
_curjunked defined in line 103; used 10 times
_dir defined in line 104; used 5 times
_junked defined in line 102; used 4 times
_row defined in line 97; used 12 times
_scol defined in line 98; used 8 times
_scratched defined in line 107; used 6 times
_shift defined in line 106; used 7 times
_shiftbot defined in line 105; used 4 times
_shifttop defined in line 105; used 4 times
_srow defined in line 98; used 11 times
_tflg defined in line 78; used 8 times
_tstr defined in line 63; used 24 times
_uline defined in line 101; used 6 times
_virt defined in line 99; used 22 times
bname defined in line 77; used 1 times
hasscroll defined in line 87; used 14 times
plodstr defined in line 572; used 35 times
sname defined in line 62; used 1 times

Defined struct's

line defined in line 91; used 24 times

Defined macros

AL defined in line 46; used 3 times
AM defined in line 69; used 1 times
BOTLINE defined in line 32; used 9 times
BS defined in line 68; used 2 times
BT defined in line 44; used 3 times
CD defined in line 38; used 2 times
CE defined in line 39; used 5 times
CH defined in line 49; used 2 times
CL defined in line 37; used 2 times
CM defined in line 48; used 3 times
CR defined in line 57; used 2 times
CS defined in line 51; used 5 times
CV defined in line 50; used 3 times
DIRTY defined in line 33; used 11 times
DL defined in line 47; used 3 times
DO defined in line 41; used 2 times
HO defined in line 36; used 4 times
MAXLLEN defined in line 30; used 5 times
MAXPLEN defined in line 29; used 4 times
NS defined in line 72; used 1 times
PT defined in line 73; used 2 times
RET defined in line 71; used 1 times
SF defined in line 52; used 2 times
SR defined in line 53; used 2 times
TA defined in line 56; used 4 times
TE defined in line 55; used 2 times
TI defined in line 54; used 2 times
UE defined in line 43; used 3 times
ULINE defined in line 84; used 5 times
US defined in line 42; used 4 times
XN defined in line 70; used 1 times
XT defined in line 74; used 1 times
xBC defined in line 45; used 1 times
xPC defined in line 58; used 2 times
  • in line 865(2)
xUP defined in line 40; used 1 times
Last modified: 1986-01-20
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4780
Valid CSS Valid XHTML 1.0 Strict