|
|
1.1 ! root 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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.