1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
   2: static char rcsid[] = "$Header: vtrm.c,v 1.3 85/08/30 10:11:04 timo Exp $";
   3: 
   4: /* History:
   5:  *	21-aug-85 GvR	added support for AL and DL (parametrized al and dl).
   6:  *	The Epoch tk	created and modified.
   7:  */
   8: 
   9: /*
  10:  * Virtual TeRMinal package.
  11:  *
  12:  * This package uses termcap to determine the terminal capabilities.
  13:  *
  14:  * The lines and columns of our virtual terminal are numbered
  15:  *	y = {0...lines-1} from top to bottom, and
  16:  *	x = {0...cols-1} from left to right,
  17:  * respectively.
  18:  *
  19:  * The Visible Procedures in this package are:
  20:  *
  21:  * trmstart(&lines, &cols, &flags)
  22:  * 	Obligatory initialization call (sets tty modes etc.),
  23:  * 	Returns the height and width of the screen to the integers
  24:  * 	whose addresses are passed as parameters, and a flag that
  25:  *	describes some capabilities.
  26:  *	Function return value: Yes if all went well, No if the terminal
  27:  *	is not supported.  An error message has already been displayed.
  28:  *
  29:  * trmundefined()
  30:  *	Sets internal representation of screen and attributes to undefined.
  31:  *	This is necessary for a hard redraw, which would get optimised to
  32:  *	oblivion,
  33:  *
  34:  * trmsense(&y, &x)
  35:  *	Returns the cursor position through its parameters
  36:  *	after a possible manual change by the user.
  37:  *
  38:  * trmputdata(yfirst, ylast, indent, data)
  39:  * 	Fill lines {yfirst..ylast} with data, after skipping the initial
  40:  *	'indent' positions. It is assumed that these positions do not contain
  41:  *	anything dangerous (like standout cookies or null characters).
  42:  *
  43:  * trmscrollup(yfirst, ylast, by)
  44:  * 	Shift lines {yfirst..ylast} up by lines (down |by| if by < 0).
  45:  *
  46:  * trmsync(y, x)
  47:  * 	Call to output data to the terminal and set cursor position.
  48:  *
  49:  * trmbell()
  50:  *	Send a (possibly visible) bell, immediately (flushing stdout).
  51:  *
  52:  * trmend()
  53:  * 	Obligatory termination call (resets tty modes etc.).
  54:  *
  55:  * You may call these as one or more cycles of:
  56:  * 	+ trmstart
  57:  * 	+    zero or more times any of the other routines
  58:  * 	+ trmend
  59:  * To catch interrupts and the like, you may call trmend even in the middle
  60:  * of trmstart.
  61:  */
  62: 
  63: 
  64: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
  65: /* Includes and data definitions.                                           */
  66: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
  67: 
  68: #include <stdio.h>
  69: #include <setjmp.h>
  70: #ifndef TERMIO
  71: #include <sgtty.h>
  72: #else
  73: #include <termio.h>
  74: #endif TERMIO
  75: #include <signal.h>
  76: #include <ctype.h>      /* for isprint() */
  77: 
  78: #include "vtrm.h"
  79: 
  80: #ifdef lint
  81: #define VOID (void)
  82: #else
  83: #define VOID
  84: #endif
  85: 
  86: #define Forward
  87: #define Visible
  88: #define Hidden static
  89: #define Procedure
  90: 
  91: typedef short intlet;
  92: typedef char *string;
  93: typedef char bool;
  94: #define Yes ((bool) 1)
  95: #define No  ((bool) 0)
  96: 
  97: #define Min(a,b) ((a) <= (b) ? (a) : (b))
  98: 
  99: /* tty modes */
 100: #ifndef TERMIO
 101: /* v7/BSD tty control */
 102: Hidden struct sgttyb oldtty, newtty;
 103: /* to enable type ahead for abled persons on systems that provide this: */
 104: #ifdef TIOCSETN
 105: #define stty(fd,bp) VOID ioctl(fd, TIOCSETN, bp)
 106: #endif
 107: #else
 108: /* AT&T tty control */
 109: Hidden struct termio oldtty, newtty;
 110: #define gtty(fd,bp) ioctl(fd, TCGETA, bp)
 111: #define stty(fd,bp) VOID ioctl(fd, TCSETAW, bp)
 112: #endif TERMIO
 113: Hidden bool know_ttys = No;
 114: 
 115: /* visible data for termcap */
 116: char PC;
 117: char *BC;
 118: char *UP;
 119: short ospeed;
 120: 
 121: Forward int outchar();      /* procedure for termcap's tputs */
 122: #define Putstr(str) tputs((str), 1, outchar)
 123: extern char *tgoto();
 124: 
 125: /* termcap terminal capabilities */
 126: 
 127: Hidden int lines;
 128: Hidden int cols;
 129: 
 130: Hidden bool has_am;         /* has automatic margins */
 131: Hidden bool has_da;         /* display may be retained above screen */
 132: Hidden bool has_db;         /* display may be retained below screen */
 133: Hidden bool has_in;         /* not save to have null chars on the screen */
 134: Hidden bool has_mi;         /* move safely in insert (and delete?) mode */
 135: Hidden bool has_ms;         /* move safely in standout mode */
 136: Hidden bool has_xs;     /* standout not erased by overwriting */
 137: 
 138: Hidden char *al_str;        /* add new blank line */
 139: Hidden char *par_al_str;    /* parametrized al (AL) */
 140: Hidden char *cd_str;        /* clear to end of display */
 141: Hidden char *ce_str;        /* clear to end of line */
 142: Hidden char *cl_str;        /* cursor home and clear screen */
 143: Hidden char *cm_str;        /* cursor motion */
 144: Hidden char *cr_str;        /* carriage return */
 145: Hidden char *cs_str;        /* change scrolling region */
 146: Hidden char *dc_str;        /* delete character */
 147: Hidden char *dl_str;        /* delete line */
 148: Hidden char *par_dl_str;    /* parametrized dl (DL) */
 149: Hidden char *do_str;        /* cursor down one line */
 150: Hidden char *dm_str;        /* enter delete mode */
 151: Hidden char *ed_str;        /* end delete mode */
 152: Hidden char *ei_str;        /* end insert mode */
 153: Hidden char *ho_str;        /* cursor home */
 154: Hidden char *ic_str;        /* insert character (iff necessary, maybe pad) */
 155: Hidden char *im_str;        /* enter insert mode */
 156: Hidden char *le_str;        /* cursor left */
 157: Hidden char *nd_str;        /* cursor right (non-destructive space) */
 158: Hidden char *se_str;        /* end standout mode */
 159: Hidden char *sf_str;        /* scroll text up (from bottom of region) */
 160: Hidden char *so_str;        /* begin standout mode */
 161: Hidden char *sr_str;        /* scroll text down (from top of region) */
 162: Hidden char *te_str;        /* end termcap */
 163: Hidden char *ti_str;        /* start termcap */
 164: Hidden char *up_str;        /* cursor up */
 165: Hidden char *vb_str;        /* visible bell */
 166: Hidden char *ve_str;        /* make cursor visible again */
 167: Hidden char *vi_str;        /* make cursor invisible */
 168: 
 169: /* sense cursor position, addition to termcap */
 170: Hidden char *cp_str;        /* format of returned Cursor Position string */
 171: Hidden char *sp_str;        /* Sense cursor Position from terminal */
 172: 
 173: /* terminal status */
 174: 
 175: /* calling order of Visible Procs */
 176: Hidden bool started = No;
 177: 
 178: /* to exports the capabilities mentioned in vtrm.h: */
 179: Hidden int flags = 0;
 180: 
 181: /* cost for impossible operations */
 182: #define Infinity 9999
 183:     /* Allow for adding Infinity+Infinity within range */
 184:     /* (Range is assumed at least 2**15 - 1) */
 185: 
 186: /* The following for all sorts of undefined things (except for UNKNOWN char) */
 187: #define Undefined (-1)
 188: 
 189: /* current mode of putting char's */
 190: #define Normal  0
 191: #define Insert  1
 192: #define Delete  2
 193: Hidden short mode = Normal;
 194: 
 195: /* current standout mode */
 196: #define Off 0
 197: #define On  0200
 198: Hidden short so_mode = Off;
 199: 
 200: /* masks for char's and intlet's */
 201: #define NULCHAR '\000'
 202: #define CHAR    0177
 203: #define SOBIT   On
 204: #define SOCHAR  0377
 205: /* if (has_xs) record cookies placed on screen in extra bit */
 206: /* type of cookie is determined by the SO bit */
 207: #define XSBIT   0400
 208: #define SOCOOK  0600
 209: #define COOKBITS SOCOOK
 210: #define UNKNOWN 1
 211: #define NOCOOK  UNKNOWN
 212: 
 213: /* current cursor position */
 214: Hidden intlet cur_y = Undefined, cur_x = Undefined;
 215: 
 216: /* "line[y][x]" holds the char on the terminal, with the SOBIT and XSBIT.
 217:  * the SOBIT tells whether the character is standing out, the XSBIT whether
 218:  * there is a cookie on the screen at this position.
 219:  * In particular a standend-cookie may be recorded AFTER the line
 220:  * (just in case some trmputdata will write after that position).
 221:  * "lenline[y]" holds the length of the line.
 222:  * Unknown chars will be 1, so the optimising compare in putline will fail.
 223:  * (Partially) empty lines are distinghuished by "lenline[y] < cols".
 224:  */
 225: Hidden intlet **line = 0, *lenline = 0;
 226: 
 227: /* Clear the screen initially iff only memory cursor addressing available */
 228: Hidden bool mustclear = No;
 229: 
 230: /* Make the cursor invisible when trmsync() tries to move outside the screen */
 231: Hidden bool no_cursor = No;
 232: 
 233: /* Optimise cursor motion */
 234: Hidden int abs_cost;        /* cost of absolute cursor motion */
 235: Hidden int cr_cost;         /* cost of carriage return */
 236: Hidden int do_cost;         /* cost of down */
 237: Hidden int le_cost;         /* cost of left */
 238: Hidden int nd_cost;         /* cost of right */
 239: Hidden int up_cost;         /* cost of up */
 240: 
 241: /* Optimise trailing match in put_line, iff the terminal can insert and delete
 242:  * characters; the cost per n characters will be:
 243:  * 	n * MultiplyFactor + OverHead
 244:  */
 245: Hidden int ins_mf, ins_oh, del_mf, del_oh;
 246: Hidden int ed_cost, ei_cost;        /* used in move() */
 247: 
 248: /* The type of scrolling possible determines which routines get used;
 249:  * these may be:
 250:  * (1) with addline and deleteline (termcap: al_str & dl_str);
 251:  * (2) with a settable scrolling region, like VT100 (cs_str, sr_str, sf_str);
 252:  * (3) no scrolling available. (NOT YET IMPLEMENTED)
 253:  */
 254: Hidden Procedure (*scr_up)();
 255: Hidden Procedure (*scr_down)();
 256: Forward Procedure scr1up();
 257: Forward Procedure scr1down();
 258: Forward Procedure scr2up();
 259: Forward Procedure scr2down();
 260: /*Forward Procedure scr3up(); */
 261: /*Forward Procedure scr3down(); */
 262: 
 263: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
 264: /* Starting, Ending and (fatal) Error.                                      */
 265: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
 266: 
 267: /*
 268:  * Initialization call.
 269:  * Determine terminal capabilities from termcap.
 270:  * Set up tty modes.
 271:  * Start up terminal and internal administration.
 272:  * Return Yes if succeeded, No if trouble (e.g., bad terminal type).
 273:  */
 274: Visible int
 275: trmstart(plines, pcols, pflags)
 276: int *plines;
 277: int *pcols;
 278: int *pflags;
 279: {
 280: #ifdef TRACE
 281: fprintf(stderr, "\ttrmstart(&li, &co, &fl);\n");
 282: #endif
 283:     if (started)
 284:         trmerr("trmstart called twice in succession");
 285:     if (!gettermcaps())
 286:         return No;
 287:     if (!setttymode())
 288:         return No;
 289:     start_trm();
 290: 
 291:     *plines = lines;
 292:     *pcols = cols;
 293:     *pflags = flags;
 294: 
 295:     started = Yes;
 296:     return Yes;
 297: }
 298: 
 299: /*
 300:  * Termination call.
 301:  * Reset tty modes, etc.
 302:  * Beware that it might be called by a catched interrupt even in the middle
 303:  * of trmstart()!
 304:  */
 305: Visible Procedure
 306: trmend()
 307: {
 308: #ifdef TRACE
 309: fprintf(stderr, "\ttrmend();\n");
 310: #endif
 311:     set_mode(Normal);
 312:     if (so_mode != Off)
 313:         standend();
 314:     Putstr(te_str);
 315:     VOID fflush(stdout);
 316:     resetttymode();
 317: 
 318:     started = No;
 319: }
 320: 
 321: /*
 322:  * Set all internal statuses to undefined, especially the contents of
 323:  * the screen, so a hard redraw will not be optimised to heaven.
 324:  */
 325: Visible Procedure
 326: trmundefined()
 327: {
 328:     register int y, x;
 329: #ifdef TRACE
 330: fprintf(stderr, "\ttrmundefined();\n");
 331: #endif
 332: 
 333:     cur_y = cur_x = Undefined;
 334:     mode = so_mode = Undefined;
 335: 
 336:     for (y = 0; y < lines; y++) {
 337:         for (x = 0; x <= cols; x++)
 338:             line[y][x] = 1; /* impossible char, no so bits */
 339:         lenline[y] = cols;
 340:     }
 341: }
 342: 
 343: /*
 344:  * Give an error message, and abort.
 345:  * The abort can be catched by the calling process.
 346:  */
 347: Hidden Procedure
 348: trmerr(mess)
 349: string mess;
 350: {
 351:     trmreset();
 352:     fprintf(stderr,
 353:         "*** System error in screen output module:\n*** %s\n", mess);
 354:     VOID fflush(stderr);
 355:     abort();
 356: }
 357: 
 358: /*
 359:  * Give an error message and reset the tty modes (but don't abort).
 360:  */
 361: Hidden Procedure trmmess(mess)
 362: string mess;
 363: {
 364:     trmreset();
 365:     fprintf(stderr, "*** Fatal error: %s\n", mess);
 366:     VOID fflush(stderr);
 367: }
 368: 
 369: /*
 370:  * Complain about a missing terminal feature.  Otherwise like trmmess.
 371:  */
 372: Hidden Procedure
 373: trmsorry(mess)
 374: string mess;
 375: {
 376:     trmreset();
 377:     fprintf(stderr, (
 378: #ifdef BED
 379:       "*** Sorry, this terminal isn't powerful enough to run the B editor.\n"
 380: #else
 381:       "*** Sorry, this terminal isn't powerful emough.\n"
 382: #endif
 383:     ));
 384:     fprintf(stderr, "*** The problem is: %s.\n", mess);
 385: #ifdef BED
 386:     fprintf(stderr,
 387:       "*** (You might try 'b -e' to use a standard editor instead.)\n");
 388: #endif
 389:     VOID fflush(stderr);
 390: }
 391: 
 392: /*
 393:  * Prepare for giving a (more or less fatal) error message.
 394:  */
 395: Hidden Procedure
 396: trmreset()
 397: {
 398:     if (started) {
 399:         move(lines-1, 0);
 400:         clear_lines(lines-1, lines-1);
 401:     }
 402:     VOID fflush(stdout);
 403:     resetttymode();
 404: }
 405: 
 406: Hidden Procedure
 407: check_started(m)
 408: char *m;
 409: {
 410:     char s[80];
 411: 
 412:     if (!started) {
 413:         VOID sprintf(s, "%s called outside trmstart/trmend", m);
 414:         trmerr(s);
 415:     }
 416: }
 417: 
 418: int ccc;
 419: 
 420: /*ARGSUSED*/
 421: Hidden Procedure
 422: countchar(ch)
 423: char ch;
 424: {
 425:     ccc++;
 426: }
 427: 
 428: Hidden int
 429: strcost(str)
 430: char *str;
 431: {
 432:     if (str == NULL)
 433:         return Infinity;
 434:     return str0cost(str);
 435: }
 436: 
 437: Hidden int
 438: str0cost(str)
 439: char *str;
 440: {
 441:     ccc = 0;
 442:     tputs(str, 1, countchar);
 443:     return ccc;
 444: }
 445: 
 446: Hidden int
 447: gettermcaps()           /* get terminal capabilities from termcap
 448: 				 * and related static properties
 449: 				 */
 450: {
 451:     string trmname;
 452:     char tc_buf[1024];
 453:     static char strbuf[1024];
 454:     char *area = strbuf;
 455:     char *xPC;
 456:     char *getenv();
 457:     int tgetent();
 458:     int tgetnum();
 459:     int tgetflag();
 460:     char *tgetstr();
 461:     int sg;
 462:     static bool tc_initialized = No;
 463: #ifdef TIOCGWINSZ
 464:     struct winsize win;
 465: #endif
 466: 
 467:     if (tc_initialized)
 468:         return Yes;
 469: 
 470:     if ((trmname=getenv("TERM")) == NULL) {
 471:         trmmess("terminal type not exported in $TERM variable");
 472:         return No;
 473:     }
 474:     if (tgetent(tc_buf, trmname) != 1) {
 475:         trmmess("unknown terminal type in $TERM envariable");
 476:         return No;
 477:     }
 478: 
 479:     if (tgetflag("hc")) {
 480:         trmsorry("can't use a hardcopy terminal");
 481:         return No;
 482:     }
 483: 
 484:     BC = tgetstr("le", &area);
 485:     if (BC == NULL)
 486:         BC = tgetstr("bc", &area);
 487:     if (BC == NULL)
 488:         if (tgetflag("bs"))
 489:             BC="\b";
 490:         else {
 491:             trmsorry("no LEFT cursor motion");
 492:             return No;
 493:         }
 494:     UP = tgetstr("up", &area);
 495:     if (UP == NULL) {
 496:         trmsorry("no UP cursor motion");
 497:         return No;
 498:     }
 499:     xPC = tgetstr("pc", &area);
 500:     PC = (xPC != NULL? xPC[0] : NULCHAR);
 501: 
 502:     ho_str = tgetstr("ho", &area);
 503:     do_str = tgetstr("do", &area);
 504:     nd_str = tgetstr("nd", &area);
 505:     cm_str = tgetstr("cm", &area);
 506:     if (cm_str == NULL) {
 507:         cm_str = tgetstr("CM", &area);
 508:         if (cm_str == NULL) {
 509:             if (ho_str == NULL || do_str == NULL || nd_str == NULL) {
 510:                 trmsorry("no absolute cursor motion");
 511:                 return No;
 512:             }
 513:         }
 514:         else
 515:             mustclear = Yes;
 516:     }
 517: 
 518:     al_str = tgetstr("al", &area);
 519:     dl_str = tgetstr("dl", &area);
 520:     par_al_str = tgetstr("AL", &area);
 521:     par_dl_str = tgetstr("DL", &area);
 522:     if (al_str && dl_str) {
 523:         scr_up = scr1up;
 524:         scr_down = scr1down;
 525:         flags |= CAN_SCROLL;
 526:     }
 527:     else {
 528:         cs_str = tgetstr("cs", &area);
 529:         sf_str = tgetstr("sf", &area);
 530:         if (sf_str == NULL)
 531:             sf_str = "\n";
 532:         sr_str = tgetstr("sr", &area);
 533:         if (cs_str && sr_str) {
 534:             scr_up = scr2up;
 535:             scr_down = scr2down;
 536:             flags |= CAN_SCROLL;
 537:         }
 538:         else {
 539:             trmsorry("can't scroll");
 540:             return No;
 541:         }
 542:     }
 543: 
 544:     lines = tgetnum("li");
 545:     cols = tgetnum("co");
 546: #ifdef TIOCGWINSZ
 547:     if (ioctl (0, TIOCGWINSZ, &win) == 0) {
 548:         if (win.ws_col)
 549:             cols = win.ws_col;
 550:         if (win.ws_row)
 551:             lines = win.ws_row;
 552:     }
 553: #endif
 554:     if (lines == -1) lines = 24;
 555:     if (cols == -1) cols = 80;
 556: 
 557:     has_am = tgetflag("am");
 558:     has_db = tgetflag("db");
 559:     has_in = tgetflag("in");
 560:     has_mi = tgetflag("mi");
 561:     has_ms = tgetflag("ms");
 562:     has_xs = tgetflag("xs");
 563:     if ((sg=tgetnum("sg")) == 0)
 564:         has_xs = Yes;
 565:     else if (sg > 0) {
 566:         trmsorry("video attributes take up space on the screen");
 567:         return No;
 568:     }
 569: 
 570:     cd_str = tgetstr("cd", &area);
 571:     ce_str = tgetstr("ce", &area);
 572:     if (!ce_str) {
 573:         trmsorry("can't clear to end of line");
 574:         return No;
 575:     }
 576:     cl_str = tgetstr("cl", &area);
 577:     cr_str = tgetstr("cr", &area);
 578:     if (cr_str == NULL) cr_str = "\r";
 579:     dc_str = tgetstr("dc", &area);
 580:     dm_str = tgetstr("dm", &area);
 581:     if (do_str == NULL) do_str = tgetstr("nl", &area);
 582:     if (do_str == NULL) do_str = "\n";
 583:     ed_str = tgetstr("ed", &area);
 584:     ei_str = tgetstr("ei", &area);
 585:     ic_str = tgetstr("ic", &area);
 586:     im_str = tgetstr("im", &area);
 587:     le_str = BC;
 588:     se_str = tgetstr("se", &area);
 589:     so_str = tgetstr("so", &area);
 590:     te_str = tgetstr("te", &area);
 591:     ti_str = tgetstr("ti", &area);
 592:     up_str = UP;
 593:     vb_str = tgetstr("vb", &area);
 594:     if (vb_str == NULL)     /* then we will do with the audible bell */
 595:         vb_str = "\007";
 596:     ve_str = tgetstr("ve", &area);
 597:     vi_str = tgetstr("vi", &area);
 598: 
 599:     /* cursor sensing (non standard) */
 600:     cp_str = tgetstr("cp", &area);
 601:     sp_str = tgetstr("sp", &area);
 602:     if (cp_str != NULL && sp_str != NULL)
 603:         flags |= CAN_SENSE;
 604: 
 605:     if (so_str != NULL && se_str != NULL)
 606:         flags |= HAS_STANDOUT;
 607: 
 608:     /* calculate costs of local and absolute cursor motions */
 609:     if (cm_str == NULL)
 610:         abs_cost = Infinity;
 611:     else
 612:         abs_cost = strcost(tgoto(cm_str, 0, 0));
 613:     cr_cost = strcost(cr_str);
 614:     do_cost = strcost(do_str);
 615:     le_cost = strcost(le_str);
 616:     nd_cost = strcost(nd_str);
 617:     up_cost = strcost(up_str);
 618: 
 619:     /* cost of leaving insert or delete mode, used in move() */
 620:     ei_cost = str0cost(ei_str);
 621:     ed_cost = str0cost(ed_str);
 622: 
 623:     /* calculate insert and delete cost multiply_factor and overhead */
 624:     if (((im_str && ei_str) || ic_str) && dc_str) {
 625:         flags |= CAN_OPTIMISE;
 626:         ins_mf = 1 + str0cost(ic_str);
 627:         ins_oh = str0cost(im_str) + ei_cost;
 628:         del_mf = str0cost(dc_str);
 629:         del_oh = str0cost(dm_str) + ed_cost;
 630:     }
 631: 
 632:     tc_initialized = Yes;
 633:     return Yes;
 634: }
 635: 
 636: Hidden int
 637: setttymode()
 638: {
 639:     if (!know_ttys) {
 640:         if (gtty(1, &oldtty) != 0 || gtty(1, &newtty) != 0) {
 641:             trmmess("can't get tty modes (output not a terminal)");
 642:             return No;
 643:         }
 644: #ifndef TERMIO
 645:         ospeed = oldtty.sg_ospeed;
 646: #ifdef PWB
 647:         newtty.sg_flags = (newtty.sg_flags & ~ECHO & ~CRMOD & ~XTABS)
 648:                   | RAW;
 649: #else PWB
 650:         newtty.sg_flags = (newtty.sg_flags & ~ECHO & ~CRMOD & ~XTABS)
 651:                   | CBREAK;
 652: #endif PWB
 653: #else TERMIO
 654:         ospeed= oldtty.c_lflag & CBAUD;
 655:         newtty.c_iflag &= ~ICRNL; /* No CR->NL mapping on input */
 656:         newtty.c_oflag &= ~ONLCR; /* NL doesn't output CR */
 657:         newtty.c_lflag &= ~(ICANON|ECHO); /* No line editing, no echo */
 658:         newtty.c_cc[VMIN]= 3; /* wait for 3 characters */
 659:         newtty.c_cc[VTIME]= 1; /* or 0.1 sec. */
 660: #endif TERMIO
 661:         know_ttys = Yes;
 662:     }
 663:     stty(1, &newtty);
 664:     return Yes;
 665: }
 666: 
 667: Hidden Procedure
 668: resetttymode()
 669: {
 670:     if (know_ttys)
 671:         stty(1, &oldtty);
 672: }
 673: 
 674: Hidden char*
 675: lalloc(size)
 676: unsigned size;
 677: {
 678:     char *l;
 679:     char *malloc();
 680: 
 681:     l = malloc(size);
 682:     if (l == NULL)
 683:         trmerr("not enough memory for screen buffer");
 684:     return l;
 685: }
 686: 
 687: Hidden Procedure
 688: start_trm()
 689: {
 690:     register int y;
 691: 
 692:     if (line == 0) {
 693:         line = (intlet**) lalloc((unsigned) lines * sizeof(intlet*));
 694:         for (y = 0; y < lines; y++)
 695:             line[y] = (intlet*) lalloc((unsigned) ((cols+1)*sizeof(intlet)));
 696:     }
 697:     if (lenline == 0)
 698:         lenline = (intlet*) lalloc((unsigned) lines * sizeof(intlet));
 699: 
 700: 
 701:     trmundefined();
 702: 
 703:     Putstr(ti_str);
 704:     if (cs_str)
 705:         Putstr(tgoto(cs_str, lines-1, 0));
 706:     if (mustclear)
 707:         clear_lines(0, lines-1);
 708: }
 709: 
 710: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
 711: /* Sensing and moving the cursor.                                           */
 712: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
 713: 
 714: /*
 715:  * Sense the current (y, x) cursor position, after a possible manual
 716:  * change by the user with local cursor motions.
 717:  * If the terminal cannot be asked for the current cursor position,
 718:  * or if the string returned by the terminal is garbled,
 719:  * the position is made Undefined.
 720:  */
 721: Visible Procedure
 722: trmsense(py, px)
 723:     int *py;
 724:     int *px;
 725: {
 726:     bool getpos();
 727: 
 728: #ifdef TRACE
 729: fprintf(stderr, "\ttrmsense(&yy, &xx);\n");
 730: #endif
 731:     check_started("trmsense");
 732: 
 733:     *py = *px = Undefined;
 734:     set_mode(Normal);
 735:     if (so_mode != Off)
 736:         standend();
 737: 
 738:     if (flags&CAN_SENSE && getpos(py, px)) {
 739:         if (*py < 0 || lines <= *py || *px < 0 || cols <= *px)
 740:             *py = *px = Undefined;
 741:     }
 742:     cur_y = *py;
 743:     cur_x = *px;
 744: }
 745: 
 746: Hidden bool
 747: getpos(py, px)
 748: int *py, *px;
 749: {
 750:     char *format = cp_str;
 751:     int fc;         /* current format character */
 752:     int ic;         /* current input character */
 753:     int num;
 754:     int on_y = 1;
 755:     bool incr_orig = No;
 756:     int i, ni;
 757: 
 758:     Putstr(sp_str);
 759:     VOID fflush(stdout);
 760: 
 761:     while (fc = *format++) {
 762:         if (fc != '%') {
 763:             if (getchar() != fc)
 764:                 return No;
 765:         }
 766:         else {
 767:             switch (fc = *format++) {
 768:             case '%':
 769:                 if (getchar() != '%')
 770:                     return No;
 771:                 continue;
 772:             case 'r':
 773:                 on_y = 1 - on_y;
 774:                 continue;
 775:             case 'i':
 776:                 incr_orig = Yes;
 777:                 continue;
 778:             case 'd':
 779:                 ic = getchar();
 780:                 if (!isdigit(ic))
 781:                     return No;
 782:                 num = ic - '0';
 783:                 while (isdigit(ic=getchar()))
 784:                     num = 10*num + ic - '0';
 785:                 VOID ungetc(ic, stdin);
 786:                 break;
 787:             case '2':
 788:             case '3':
 789:                 ni = fc - '0';
 790:                     num = 0;
 791:                 for (i=0; i<ni; i++) {
 792:                     ic = getchar();
 793:                     if (isdigit(ic))
 794:                         num = 10*num + ic - '0';
 795:                     else
 796:                         return No;
 797:                 }
 798:                 break;
 799:             case '+':
 800:                 num = getchar() - *format++;
 801:                 break;
 802:             case '-':
 803:                 num = getchar() + *format++;
 804:                 break;
 805:             default:
 806:                 return No;
 807:             }
 808:             /* assign num to parameter */
 809:             if (incr_orig)
 810:                 num--;
 811:             if (on_y)
 812:                 *py = num;
 813:             else
 814:                 *px = num;
 815:             on_y = 1 - on_y;
 816:         }
 817:     }
 818: 
 819:     return Yes;
 820: }
 821: 
 822: /*
 823:  * To move over characters by rewriting them, we have to check:
 824:  * (1) that the screen has been initialised on these positions;
 825:  * (2) we do not screw up characters
 826:  * when rewriting line[y] from x_from upto x_to
 827:  */
 828: Hidden bool
 829: rewrite_ok(y, xfrom, xto)
 830: int y, xfrom, xto;
 831: {
 832:     register intlet *plnyx, *plnyto;
 833: 
 834:     if (xto > lenline[y])
 835:         return No;
 836: 
 837:     plnyto = &line[y][xto];
 838:     for (plnyx = &line[y][xfrom]; plnyx <= plnyto; plnyx++)
 839:         if (*plnyx == UNKNOWN
 840:             ||
 841:             (!has_xs && (*plnyx & SOBIT) != so_mode)
 842:            )
 843:             return No;
 844:     return Yes;
 845: }
 846: 
 847: /*
 848:  * Move to position y,x on the screen
 849:  */
 850: /* possible move types for y and x respectively: */
 851: #define None    0
 852: #define Down    1
 853: #define Up  2
 854: #define Right   1
 855: #define ReWrite 2
 856: #define Left    3
 857: #define CrWrite 4
 858: 
 859: Hidden Procedure
 860: move(y, x)
 861: int y, x;
 862: {
 863:     int dy, dx;
 864:     int y_cost, x_cost, y_move, x_move;
 865:     int mode_cost;
 866:     int xi;
 867: 
 868:     if (cur_y == y && cur_x == x)
 869:         return;
 870: 
 871:     if (!has_mi || mode == Undefined)
 872:         set_mode(Normal);
 873:     if (!has_xs && ((!has_ms && so_mode != Off) || so_mode == Undefined))
 874:         standend();
 875: 
 876:     if (cur_y == Undefined || cur_x == Undefined)
 877:         goto absmove;
 878: 
 879:     dy = y - cur_y;
 880:     dx = x - cur_x;
 881: 
 882:     if (dy > 0) {
 883:         y_move = Down;
 884:         y_cost = dy * do_cost;
 885:     }
 886:     else if (dy < 0) {
 887:         y_move = Up;
 888:         y_cost = -dy * up_cost;
 889:     }
 890:     else {
 891:         y_move = None;
 892:         y_cost = 0;
 893:     }
 894:     if (y_cost < abs_cost) {
 895:         switch (mode) {
 896:         case Normal:
 897:             mode_cost = 0;
 898:             break;
 899:         case Insert:
 900:             mode_cost = ei_cost;
 901:             break;
 902:         case Delete:
 903:             mode_cost = ed_cost;
 904:             break;
 905:         }
 906:         if (dx > 0) {
 907:             x_cost = dx + mode_cost;
 908:             if (dx*nd_cost < x_cost || !rewrite_ok(y, cur_x, x)) {
 909:                 x_cost = dx * nd_cost;
 910:                 x_move = Right;
 911:             }
 912:             else
 913:                 x_move = ReWrite;
 914:         }
 915:         else if (dx < 0) {
 916:             x_cost = -dx * le_cost;
 917:             x_move = Left;
 918:         }
 919:         else {
 920:             x_cost = 0;
 921:             x_move = None;
 922:         }
 923:         if (cr_cost + x + mode_cost < x_cost && rewrite_ok(y, 0, x)) {
 924:             x_move = CrWrite;
 925:             x_cost = cr_cost + x + mode_cost;
 926:         }
 927:     }
 928:     else
 929:         x_cost = abs_cost;
 930: 
 931:     if (y_cost + x_cost < abs_cost) {
 932:         switch (y_move) {
 933:         case Down:
 934:             while (dy-- > 0) Putstr(do_str);
 935:             break;
 936:         case Up:
 937:             while (dy++ < 0) Putstr(up_str);
 938:             break;
 939:         }
 940:         switch (x_move) {
 941:         case Right:
 942:             while (dx-- > 0) Putstr(nd_str);
 943:             break;
 944:         case Left:
 945:             while (dx++ < 0) Putstr(le_str);
 946:             break;
 947:         case CrWrite:
 948:             Putstr(cr_str);
 949:             cur_x = 0;
 950:             /* FALL THROUGH */
 951:         case ReWrite:
 952:             set_mode(Normal);
 953:             for (xi = cur_x; xi < x; xi++)
 954:                 putchar(line[y][xi]);
 955:             break;
 956:         }
 957:     }
 958:     else
 959:     {
 960:     absmove:
 961:         if (cm_str == NULL) {
 962:             Putstr(ho_str);
 963:             for (cur_y = 0; cur_y < y; ++cur_y)
 964:                 Putstr(do_str);
 965:             /* Should try to use tabs here: */
 966:             for (cur_x = 0; cur_x < x; ++cur_x)
 967:                 Putstr(nd_str);
 968:         }
 969:         else
 970:             Putstr(tgoto(cm_str, x, y));
 971:     }
 972: 
 973:     cur_y = y;
 974:     cur_x = x;
 975: }
 976: 
 977: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
 978: /* Putting data on the screen.                                              */
 979: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
 980: 
 981: /*
 982:  * Fill screen area with given data.
 983:  * Characters with the SO-bit (0200) set are put in standout mode.
 984:  */
 985: Visible Procedure
 986: trmputdata(yfirst, ylast, indent, data)
 987: int yfirst;
 988: int ylast;
 989: register int indent;
 990: register string data;
 991: {
 992:     register int y;
 993:     int x, len, lendata, space;
 994: 
 995: #ifdef TRACE
 996: fprintf(stderr, "\ttrmputdata(%d, %d, %d, \"%s\");\n", yfirst, ylast, indent, data);
 997: #endif
 998:     check_started("trmputdata");
 999: 
1000:     if (yfirst < 0)
1001:         yfirst = 0;
1002:     if (ylast >= lines)
1003:         ylast = lines-1;
1004:     space = cols*(ylast-yfirst+1) - indent;
1005:     if (space <= 0)
1006:         return;
1007:     yfirst += indent/cols;
1008:     indent %= cols;
1009:     if (data) {
1010:         x = indent;
1011:         lendata = strlen(data);
1012:         if (ylast == lines-1 && lendata >= space)
1013:             lendata = space - 1;
1014:         len = Min(lendata, cols-x);
1015:         for (y = yfirst; y <= ylast; ) {
1016:             put_line(y, x, data, len);
1017:             y++;
1018:             lendata -= len;
1019:             if (lendata > 0) {
1020:                 x = 0;
1021:                 data += len;
1022:                 len = Min(lendata, cols);
1023:             }
1024:             else
1025:                 break;
1026:         }
1027:     }
1028:     if (y <= ylast)
1029:         clear_lines(y, ylast);
1030: }
1031: 
1032: /*
1033:  * We will first try to get the picture:
1034:  *
1035:  *                  op>>>>>>>>>>>op          oq<<<<<<<<<<<<<<<<<<<<<<<<oq
1036:  *                  ^            ^           ^                         ^
1037:  *           <xskip><-----m1----><----od-----><-----------m2----------->
1038:  *   OLD:   "You're in a maze of twisty little pieces of code, all alike"
1039:  *   NEW:          "in a maze of little twisting pieces of code, all alike"
1040:  *                  <-----m1----><-----nd------><-----------m2----------->
1041:  *                  ^            ^             ^                         ^
1042:  *                  np>>>>>>>>>>>np            nq<<<<<<<<<<<<<<<<<<<<<<<<nq
1043:  * where
1044:  *	op, oq, np, nq are pointers to start and end of Old and New data,
1045:  * and
1046:  *	xskip = length of indent to be skipped,
1047:  *	m1 = length of Matching part at start,
1048:  *	od = length of Differing mid on screen,
1049:  *	nd = length of Differing mid in data to be put,
1050:  *	m2 = length of Matching trail.
1051:  *
1052:  * Then we will try to find a long blank-or-cleared piece in <nd+m2>:
1053:  *
1054:  *    <---m1---><---d1---><---nb---><---d2---><---m2--->
1055:  *              ^         ^         ^        ^         ^
1056:  *              np        bp        bq1      nq        nend
1057:  * where
1058:  *	bp, bq are pointers to start and AFTER end of blank piece,
1059:  * and
1060:  *	d1 = length of differing part before blank piece,
1061:  *	nb = length of blank piece to be skipped,
1062:  *	d2 = length of differing part after blank piece.
1063:  * Remarks:
1064:  *	d1 + nb + d2 == nd,
1065:  * and
1066:  *	d2 maybe less than 0.
1067:  */
1068: Hidden int
1069: put_line(y, xskip, data, len)
1070: int y, xskip;
1071: string data;
1072: int len;
1073: {
1074:     register intlet *op, *oq;
1075:     register char *np, *nq, *nend;
1076:     char *bp, *bq1, *p, *q;
1077:     int m1, m2, od, nd, delta, dd, d1, nb, d2;
1078:     bool skipping;
1079:     int cost, o_cost;   /* normal and optimising cost */
1080: 
1081:     /* calculate the magic parameters */
1082:     op = &line[y][xskip];
1083:     oq = &line[y][lenline[y]-1];
1084:     np = data;
1085:     nq = nend = data + len - 1;
1086:     m1 = m2 = 0;
1087:     while ((*op&SOCHAR) == (((intlet)*np)&SOCHAR) && op <= oq && np <= nq)
1088:         op++, np++, m1++;
1089:     if (flags & CAN_OPTIMISE)
1090:         while ((*oq&SOCHAR) == (((intlet)*nq)&SOCHAR) && op <= oq && np <= nq)
1091:             oq--, nq--, m2++;
1092:     od = oq - op + 1;
1093:     nd = nq - np + 1;
1094:     /* now we have the first picture above */
1095: 
1096:     if (od==0 && nd==0)
1097:         return;
1098:     delta = nd - od;
1099: 
1100:     /* find the blank piece */
1101:     p = q = bp = bq1 = np;
1102:     oq += m2;       /* back to current eol */
1103:     if (!has_in) {
1104:         while (p <= nend) {
1105:             while (q<=nend && *q==' ' && (op>oq || *op==' '))
1106:                 q++, op++;
1107:             if (q - p > bq1 - bp)
1108:                 bp = p, bq1 = q;
1109:             p = ++q;
1110:             op++;
1111:         }
1112:     }
1113:     d1 = bp - np;
1114:     nb = bq1 - bp;
1115:     d2 = nq - bq1 + 1;
1116: 
1117:     /* what is cheapest:
1118: 	 *	normal: put nd+m2;                         (dd = nd+m2)
1119: 	 *	skipping: put d1, skip nb, put d2+m2;      (dd = d2+m2)
1120: 	 *	optimise: put dd, insert or delete delta.  (dd = min(od,nd))
1121: 	 */
1122:     cost = nd + m2;     /* normal cost */
1123:     if (nb > abs_cost || (d1 == 0 && nb > 0)) {
1124:         skipping = Yes;
1125:         cost -= nb - (d1>0 ? abs_cost : 0); /* skipping cost */
1126:         dd = d2;
1127:     }
1128:     else {
1129:         skipping = No;
1130:         dd = nd;
1131:     }
1132: 
1133:     if (m2 != 0) {
1134:         /* try optimising */
1135:         o_cost = Min(od, nd);
1136:         if (delta > 0)
1137:             o_cost += delta * ins_mf + ins_oh;
1138:         else if (delta < 0)
1139:             o_cost += -delta * del_mf + del_oh;
1140:         if (o_cost >= cost) {
1141:             /* discard m2, no optimise */
1142:             dd += m2;
1143:             m2 = 0;
1144:         }
1145:         else {
1146:             dd = Min(od, nd);
1147:             skipping = No;
1148:         }
1149:     }
1150: 
1151:     /* and now for the real work */
1152:     if (!skipping || d1 > 0)
1153:         move(y, xskip + m1);
1154: 
1155:     if (has_xs)
1156:         get_so_mode();
1157: 
1158:     if (skipping) {
1159:         if (d1 > 0) {
1160:             set_mode(Normal);
1161:             put_str(np, d1, No);
1162:         }
1163:         if (has_xs && so_mode != Off)
1164:             standend();
1165:         set_blanks(y, xskip+m1+d1, xskip+m1+d1+nb);
1166:         if (dd != 0 || delta < 0) {
1167:             move(y, xskip+m1+d1+nb);
1168:             np = bq1;
1169:         }
1170:     }
1171: 
1172:     if (dd > 0) {
1173:         set_mode(Normal);
1174:         put_str(np, dd, No);
1175:     }
1176: 
1177:     if (m2 > 0) {
1178:         if (delta > 0) {
1179:             set_mode(Insert);
1180:             ins_str(np+dd, delta);
1181:         }
1182:         else if (delta < 0) {
1183:             set_mode(Delete);
1184:             del_str(-delta);
1185:         }
1186:     }
1187:     else {
1188:         if (delta < 0) {
1189:             clr_to_eol();
1190:             return;
1191:         }
1192:     }
1193: 
1194:     lenline[y] = xskip + len;
1195:     if (cur_x == cols) {
1196:         if (!has_mi)
1197:             set_mode(Normal);
1198:         if (!has_ms)
1199:             so_mode = Undefined;
1200:         if (has_am)
1201:             cur_y++;
1202:         else
1203:             Putstr(cr_str);
1204:         cur_x = 0;
1205:     }
1206:     else if (has_xs) {
1207:         if (m2 == 0) {
1208:             if (so_mode == On)
1209:                 standend();
1210:         }
1211:         else {
1212:             if (!(line[cur_y][cur_x] & XSBIT)) {
1213:                 if (so_mode != (line[cur_y][cur_x] & SOBIT))
1214:                     (so_mode ? standend() : standout());
1215:             }
1216:         }
1217:     }
1218: }
1219: 
1220: Hidden Procedure
1221: set_mode(m)
1222: int m;
1223: {
1224:     if (m == mode)
1225:         return;
1226:     switch (mode) {
1227:     case Insert:
1228:         Putstr(ei_str);
1229:         break;
1230:     case Delete:
1231:         Putstr(ed_str);
1232:         break;
1233:     case Undefined:
1234:         Putstr(ei_str);
1235:         Putstr(ed_str);
1236:         break;
1237:     }
1238:     switch (m) {
1239:     case Insert:
1240:         Putstr(im_str);
1241:         break;
1242:     case Delete:
1243:         Putstr(dm_str);
1244:         break;
1245:     }
1246:     mode = m;
1247: }
1248: 
1249: Hidden Procedure
1250: get_so_mode()
1251: {
1252:     if (cur_x >= lenline[cur_y] || line[cur_y][cur_x] == UNKNOWN)
1253:         so_mode = Off;
1254:     else
1255:         so_mode = line[cur_y][cur_x] & SOBIT;
1256: }
1257: 
1258: Hidden Procedure
1259: standout()
1260: {
1261:     Putstr(so_str);
1262:     so_mode = On;
1263:     if (has_xs)
1264:         line[cur_y][cur_x] |= SOCOOK;
1265: }
1266: 
1267: Hidden Procedure
1268: standend()
1269: {
1270:     Putstr(se_str);
1271:     so_mode = Off;
1272:     if (has_xs)
1273:         line[cur_y][cur_x] = (line[cur_y][cur_x] & ~SOBIT) | XSBIT;
1274: }
1275: 
1276: Hidden Procedure
1277: put_str(data, n, inserting)
1278: char *data;
1279: int n;
1280: bool inserting;
1281: {
1282:     register intlet c, so;
1283:     intlet *ln_y_x, *ln_y_end;
1284: 
1285:     so = so_mode;
1286:     if (has_xs) {
1287:         ln_y_x = &line[cur_y][cur_x];
1288:         ln_y_end = &line[cur_y][lenline[cur_y]];
1289:     }
1290:     while (n-- > 0) {
1291:         if (has_xs && ln_y_x <= ln_y_end && ((*ln_y_x)&XSBIT))
1292:             so = so_mode = (*ln_y_x)&SOBIT;
1293:             /* this also checks for the standend cookie AFTER */
1294:             /* the line because off the equals sign in <= */
1295:         c = ((intlet)(*data++))&SOCHAR;
1296:         if ((c&SOBIT) != so) {
1297:             so = c&SOBIT;
1298:             so ? standout() : standend();
1299:         }
1300:         if (inserting)
1301:             Putstr(ic_str);
1302:         put_c(c);
1303:         if (has_xs)
1304:             ln_y_x++;
1305:     }
1306: }
1307: 
1308: Hidden Procedure
1309: ins_str(data, n)
1310: char *data;
1311: int n;
1312: {
1313:     int x;
1314: 
1315:     /* x will start AFTER the line, because there might be a cookie */
1316:     for (x = lenline[cur_y]; x >= cur_x; x--)
1317:         line[cur_y][x+n] = line[cur_y][x];
1318:     put_str(data, n, Yes);
1319: }
1320: 
1321: Hidden Procedure
1322: del_str(n)
1323: int n;
1324: {
1325:     int x, xto;
1326: 
1327:     xto = lenline[cur_y] - n; /* again one too far because of cookie */
1328:     if (has_xs) {
1329:         for (x = cur_x + n; x >= cur_x; x--) {
1330:             if (line[cur_y][x] & XSBIT)
1331:                 break;
1332:         }
1333:         if (x >= cur_x)
1334:             line[cur_y][cur_x+n] =
1335:                 (line[cur_y][cur_x+n] & CHAR)
1336:                 |
1337:                 (line[cur_y][x] & COOKBITS);
1338:     }
1339:     for (x = cur_x; x <= xto; x++)
1340:         line[cur_y][x] = line[cur_y][x+n];
1341:     while (n-- > 0)
1342:         Putstr(dc_str);
1343: }
1344: 
1345: Hidden Procedure
1346: put_c(c)
1347: intlet c;
1348: {
1349:     char ch;
1350:     intlet xs_flag;
1351: 
1352:     ch = c&CHAR;
1353:     if (!isprint(ch) && ch != ' ') { /* V7 isprint doesn't include blank */
1354:         ch = '?';
1355:         c = (c&SOBIT)|'?';
1356:     }
1357:     putchar(ch);
1358:     if (has_xs)
1359:         xs_flag = line[cur_y][cur_x]&XSBIT;
1360:     else
1361:         xs_flag = 0;
1362:     line[cur_y][cur_x] = (c&SOCHAR)|xs_flag;
1363:     cur_x++;
1364: }
1365: 
1366: Hidden Procedure
1367: clear_lines(yfirst, ylast)
1368: int yfirst, ylast ;
1369: {
1370:     register int y;
1371: 
1372:     if (!has_xs && so_mode != Off)
1373:         standend();
1374:     if (cl_str && yfirst == 0 && ylast == lines-1) {
1375:         Putstr(cl_str);
1376:         cur_y = cur_x = 0;
1377:         return;
1378:     }
1379:     for (y = yfirst; y <= ylast; y++) {
1380:         if (lenline[y] > 0) {
1381:             move(y, 0);
1382:             if (ylast == lines-1 && cd_str) {
1383:                 Putstr(cd_str);
1384:                 while (y <= ylast) {
1385:                     if (has_xs) line[y][0] = NOCOOK;
1386:                     lenline[y++] = 0;
1387:                 }
1388:                 break;
1389:             }
1390:             else {
1391:                 clr_to_eol();
1392:             }
1393:         }
1394:     }
1395: }
1396: 
1397: Hidden Procedure
1398: clr_to_eol()
1399: {
1400:     lenline[cur_y] = cur_x;
1401:     if (!has_xs && so_mode != Off)
1402:         standend();
1403:     Putstr(ce_str);
1404:     if (has_xs) {
1405:         if (cur_x == 0)
1406:             line[cur_y][0] = NOCOOK;
1407:         else if (line[cur_y][cur_x-1]&SOBIT)
1408:             standend();
1409:     }
1410: }
1411: 
1412: Hidden Procedure
1413: set_blanks
1414: (y, xfrom, xto)
1415: int y, xfrom, xto;
1416: {
1417:     register int x;
1418: 
1419:     for (x = xfrom; x < xto; x++) {
1420:         line[y][x] = (line[y][x]&XSBIT) | ' ';
1421:     }
1422: }
1423: 
1424: /*
1425:  * outchar() is used by termcap's tputs;
1426:  * we can't use putchar because that's probably a macro
1427:  */
1428: Hidden int
1429: outchar(ch)
1430: char ch;
1431: {
1432:     putchar(ch);
1433: }
1434: 
1435: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
1436: /* Scrolling (part of) the screen up (or down, dy<0).                       */
1437: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
1438: 
1439: Visible Procedure
1440: trmscrollup(yfirst, ylast, by)
1441: register int yfirst;
1442: register int ylast;
1443: register int by;
1444: {
1445: #ifdef TRACE
1446: fprintf(stderr, "\ttrmscrollup(%d, %d, %d);\n", yfirst, ylast, by);
1447: #endif
1448:     check_started("trmscrollup");
1449: 
1450:     if (yfirst < 0)
1451:         yfirst = 0;
1452:     if (ylast >= lines)
1453:         ylast = lines-1;
1454: 
1455:     if (yfirst > ylast)
1456:         return;
1457: 
1458:     if (!has_xs && so_mode != Off)
1459:         standend();
1460: 
1461:     if (by > 0 && yfirst + by > ylast
1462:         ||
1463:         by < 0 && yfirst - by > ylast)
1464:     {
1465:         clear_lines(yfirst, ylast);
1466:         return;
1467:     }
1468: 
1469:     if (by > 0) {
1470:         (*scr_up)(yfirst, ylast, by);
1471:         scr_lines(yfirst, ylast, by, 1);
1472:     }
1473:     else if (by < 0) {
1474:         (*scr_down)(yfirst, ylast, -by);
1475:         scr_lines(ylast, yfirst, -by, -1);
1476:     }
1477: }
1478: 
1479: Hidden Procedure
1480: scr_lines(yfrom, yto, n, dy)
1481: int yfrom, yto, n, dy;
1482: {
1483:     register int y;
1484:     intlet *saveln;
1485: 
1486:     while (n-- > 0) {
1487:         saveln = line[yfrom];
1488:         for (y = yfrom; y != yto; y += dy) {
1489:             line[y] = line[y+dy];
1490:             lenline[y] = lenline[y+dy];
1491:         }
1492:         line[yto] = saveln;
1493:         lenline[yto] = 0;
1494:         if (has_xs) line[yto][0] = NOCOOK;
1495:     }
1496: }
1497: 
1498: Hidden Procedure
1499: scr1up(yfirst, ylast, n)
1500:     int yfirst;
1501:     int ylast;
1502:     int n;
1503: {
1504:     move(yfirst, 0);
1505:     dellines(n);
1506:     if (ylast < lines-1) {
1507:         move(ylast-n+1, 0);
1508:         addlines(n);
1509:     }
1510: }
1511: 
1512: Hidden Procedure
1513: scr1down(yfirst, ylast, n)
1514:     int yfirst;
1515:     int ylast;
1516:     int n;
1517: {
1518:     if (ylast == lines-1) {
1519:         clear_lines(ylast-n+1, ylast);
1520:     }
1521:     else {
1522:         move(ylast-n+1, 0);
1523:         dellines(n);
1524:     }
1525:     move(yfirst, 0);
1526:     addlines(n);
1527: }
1528: 
1529: Hidden Procedure
1530: addlines(n)
1531: register int n;
1532: {
1533:     if (par_al_str && n > 1)
1534:             Putstr(tgoto(par_al_str, n, n));
1535:     else {
1536:         while (n-- > 0)
1537:             Putstr(al_str);
1538:     }
1539: }
1540: 
1541: Hidden Procedure
1542: dellines(n)
1543: register int n;
1544: {
1545:     if (par_dl_str && n > 1)
1546:         Putstr(tgoto(par_dl_str, n, n));
1547:     else {
1548:         while (n-- > 0)
1549:             Putstr(dl_str);
1550:     }
1551: }
1552: 
1553: Hidden Procedure
1554: scr2up(yfirst, ylast, n)
1555: int yfirst, ylast, n;
1556: {
1557:     Putstr(tgoto(cs_str, ylast, yfirst));
1558:     cur_y = cur_x = Undefined;
1559:     move(ylast, 0);
1560:     while (n-- > 0) {
1561:         Putstr(sf_str);
1562:         if (has_db && ylast == lines-1)
1563:             clr_to_eol();
1564:     }
1565:     Putstr(tgoto(cs_str, lines-1, 0));
1566:     cur_y = cur_x = Undefined;
1567: }
1568: 
1569: Hidden Procedure
1570: scr2down(yfirst, ylast, n)
1571: int yfirst, ylast, n;
1572: {
1573:     Putstr(tgoto(cs_str, ylast, yfirst));
1574:     cur_y = cur_x = Undefined;
1575:     move(yfirst, 0);
1576:     while (n-- > 0) {
1577:         Putstr(sr_str);
1578:         if (has_da && yfirst == 0)
1579:             clr_to_eol();
1580:     }
1581:     Putstr(tgoto(cs_str, lines-1, 0));
1582:     cur_y = cur_x = Undefined;
1583: }
1584: 
1585: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
1586: /* Synchronization, move cursor to given position (or previous if < 0).     */
1587: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
1588: 
1589: Visible Procedure
1590: trmsync(y, x)
1591:     int y;
1592:     int x;
1593: {
1594: #ifdef TRACE
1595: fprintf(stderr, "\ttrmsync(%d, %d);\n", y, x);
1596: #endif
1597:     check_started("trmsync");
1598: 
1599:     if (0 <= y && y < lines && 0 <= x && x < cols) {
1600:         move(y, x);
1601:         if (no_cursor) {
1602:             Putstr(ve_str);
1603:             no_cursor = No;
1604:         }
1605:     }
1606:     else if (no_cursor == No) {
1607:         Putstr(vi_str);
1608:         no_cursor = Yes;
1609:     }
1610:     VOID fflush(stdout);
1611: }
1612: 
1613: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
1614: /* Send a bell, visible if possible.                                        */
1615: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
1616: 
1617: Visible Procedure
1618: trmbell()
1619: {
1620: #ifdef TRACE
1621: fprintf(stderr, "\ttrmbell();\n");
1622: #endif
1623:     check_started("trmbell");
1624: 
1625:     Putstr(vb_str);
1626:     VOID fflush(stdout);
1627: }
1628: 
1629: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
1630: /* Show the current internal statuses of the screen on stderr.              */
1631: /* For debugging only.                                                      */
1632: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
1633: 
1634: #ifdef SHOW
1635: Visible Procedure
1636: trmshow(s)
1637: char *s;
1638: {
1639:     int y, x;
1640: 
1641:     fprintf(stderr, "<<< %s >>>\n", s);
1642:     for (y = 0; y < lines; y++) {
1643:         for (x = 0; x <= lenline[y] /*** && x < cols-1 ***/ ; x++) {
1644:             fputc(line[y][x]&CHAR, stderr);
1645:         }
1646:         fputc('\n', stderr);
1647:         for (x = 0; x <= lenline[y] && x < cols-1; x++) {
1648:             if (line[y][x]&SOBIT)
1649:                 fputc('-', stderr);
1650:             else
1651:                 fputc(' ', stderr);
1652:         }
1653:         fputc('\n', stderr);
1654:         for (x = 0; x <= lenline[y] && x < cols-1; x++) {
1655:             if (line[y][x]&XSBIT)
1656:                 fputc('+', stderr);
1657:             else
1658:                 fputc(' ', stderr);
1659:         }
1660:         fputc('\n', stderr);
1661:     }
1662:     fprintf(stderr, "CUR_Y = %d, CUR_X = %d.\n", cur_y, cur_x);
1663:     VOID fflush(stderr);
1664: }
1665: #endif

Defined functions

addlines defined in line 1529; used 2 times
check_started defined in line 406; used 5 times
clear_lines defined in line 1366; used 5 times
clr_to_eol defined in line 1397; used 4 times
countchar defined in line 421; used 1 times
del_str defined in line 1321; used 1 times
dellines defined in line 1541; used 2 times
get_so_mode defined in line 1249; used 1 times
getpos defined in line 746; used 3 times
gettermcaps defined in line 446; used 1 times
ins_str defined in line 1308; used 1 times
lalloc defined in line 674; used 3 times
move defined in line 859; used 11 times
outchar defined in line 1428; used 2 times
put_c defined in line 1345; used 1 times
put_line defined in line 1068; used 1 times
put_str defined in line 1276; used 3 times
resetttymode defined in line 667; used 2 times
rewrite_ok defined in line 828; used 2 times
scr1down defined in line 1512; used 2 times
scr1up defined in line 1498; used 2 times
scr2down defined in line 1569; used 2 times
scr2up defined in line 1553; used 2 times
scr_lines defined in line 1479; used 2 times
set_blanks defined in line 1412; used 1 times
set_mode defined in line 1220; used 9 times
setttymode defined in line 636; used 1 times
standend defined in line 1267; used 11 times
standout defined in line 1258; used 2 times
start_trm defined in line 687; used 1 times
str0cost defined in line 437; used 7 times
strcost defined in line 428; used 6 times
trmbell defined in line 1617; used 2 times
trmend defined in line 305; used 1 times
trmerr defined in line 347; used 3 times
trmmess defined in line 361; used 3 times
trmreset defined in line 395; used 3 times
trmscrollup defined in line 1439; used 8 times
trmsense defined in line 721; used 1 times
trmshow defined in line 1635; never used
trmsorry defined in line 372; used 7 times
trmstart defined in line 274; used 1 times
trmsync defined in line 1589; used 5 times
trmundefined defined in line 325; used 3 times

Defined variables

BC defined in line 117; used 6 times
Hidden defined in line 674; never used
PC defined in line 116; used 1 times
Procedure defined in line 667; never used
UP defined in line 118; used 3 times
abs_cost defined in line 234; used 7 times
al_str defined in line 138; used 3 times
ccc defined in line 418; used 3 times
cd_str defined in line 140; used 3 times
ce_str defined in line 141; used 3 times
cl_str defined in line 142; used 3 times
cm_str defined in line 143; used 8 times
cols defined in line 128; used 18 times
cp_str defined in line 170; used 3 times
cr_cost defined in line 235; used 3 times
cr_str defined in line 144; used 6 times
cs_str defined in line 145; used 8 times
cur_y defined in line 214; used 42 times
dc_str defined in line 146; used 4 times
del_mf defined in line 245; used 2 times
del_oh defined in line 245; used 2 times
dl_str defined in line 147; used 3 times
dm_str defined in line 150; used 3 times
do_cost defined in line 236; used 2 times
do_str defined in line 149; used 9 times
ed_cost defined in line 246; used 3 times
ed_str defined in line 151; used 4 times
ei_cost defined in line 246; used 3 times
ei_str defined in line 152; used 5 times
flags defined in line 179; used 8 times
has_am defined in line 130; used 2 times
has_da defined in line 131; used 1 times
has_db defined in line 132; used 2 times
has_in defined in line 133; used 2 times
has_mi defined in line 134; used 3 times
has_ms defined in line 135; used 3 times
has_xs defined in line 136; used 20 times
ho_str defined in line 153; used 3 times
ic_str defined in line 154; used 4 times
im_str defined in line 155; used 4 times
ins_mf defined in line 245; used 2 times
ins_oh defined in line 245; used 2 times
know_ttys defined in line 113; used 3 times
le_cost defined in line 237; used 2 times
le_str defined in line 156; used 3 times
line defined in line 225; used 41 times
lines defined in line 127; used 29 times
mode defined in line 193; used 6 times
mustclear defined in line 228; used 2 times
nd_cost defined in line 238; used 3 times
nd_str defined in line 157; used 5 times
newtty defined in line 109; used 11 times
no_cursor defined in line 231; used 4 times
oldtty defined in line 109; used 4 times
ospeed defined in line 119; used 2 times
par_al_str defined in line 139; used 3 times
par_dl_str defined in line 148; used 3 times
rcsid defined in line 2; never used
se_str defined in line 158; used 3 times
sf_str defined in line 159; used 4 times
so_mode defined in line 198; used 20 times
so_str defined in line 160; used 3 times
sp_str defined in line 171; used 3 times
sr_str defined in line 161; used 3 times
started defined in line 176; used 5 times
te_str defined in line 162; used 2 times
ti_str defined in line 163; used 2 times
up_cost defined in line 239; used 2 times
up_str defined in line 164; used 3 times
vb_str defined in line 165; used 4 times
ve_str defined in line 166; used 2 times
vi_str defined in line 167; used 2 times

Defined typedef's

bool defined in line 93; used 20 times
intlet defined in line 91; used 18 times
string defined in line 92; used 6 times

Defined macros

CHAR defined in line 202; used 3 times
COOKBITS defined in line 209; used 1 times
CrWrite defined in line 857; used 1 times
Delete defined in line 192; used 1 times
Down defined in line 852; used 1 times
Forward defined in line 86; used 5 times
Hidden defined in line 88; used 95 times
Infinity defined in line 182; used 2 times
Insert defined in line 191; used 1 times
Left defined in line 856; used 1 times
Min defined in line 97; used 4 times
NOCOOK defined in line 211; used 3 times
NULCHAR defined in line 201; used 1 times
No defined in line 95; used 32 times
None defined in line 851; used 2 times
Normal defined in line 190; used 8 times
Off defined in line 196; used 10 times
On defined in line 197; used 3 times
Procedure defined in line 89; used 38 times
Putstr defined in line 122; used 40 times
ReWrite defined in line 855; used 1 times
Right defined in line 854; used 1 times
SOBIT defined in line 203; used 10 times
SOCHAR defined in line 204; used 6 times
SOCOOK defined in line 208; used 2 times
UNKNOWN defined in line 210; used 3 times
Undefined defined in line 187; used 15 times
Up defined in line 853; used 1 times
VOID defined in line 83; used 13 times
Visible defined in line 87; used 9 times
XSBIT defined in line 207; used 7 times
Yes defined in line 94; used 15 times
gtty defined in line 110; used 2 times
  • in line 640(2)
stty defined in line 111; used 2 times
Last modified: 1985-11-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4934
Valid CSS Valid XHTML 1.0 Strict