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