1: /*************************************************************************** 2: * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne. JOVE * 3: * is provided to you without charge, and with no warranty. You may give * 4: * away copies of JOVE, including sources, provided that this notice is * 5: * included in all the files. * 6: ***************************************************************************/ 7: 8: #include "jove.h" 9: #include "io.h" 10: #include "ctype.h" 11: #include "termcap.h" 12: 13: #ifdef IBMPC 14: 15: /* here come the actual emulation routines */ 16: 17: #include <dos.h> 18: #include <conio.h> 19: 20: #define BYTE unsigned char 21: #define WORD unsigned int 22: 23: #ifdef MAC 24: # undef private 25: # define private 26: #endif 27: 28: #ifdef LINT_ARGS 29: private BYTE near get_mode(void); 30: 31: private WORD 32: near cur_page(void), 33: near get_cur(void); 34: 35: private void 36: near ch_out(BYTE, BYTE), 37: near clr_eop(void), 38: near cur_advance(void), 39: near cur_down(void), 40: near cur_left(void), 41: near cur_right(void), 42: near cur_up(void), 43: near line_feed(void), 44: near normfun(char), 45: near scr_win(int, BYTE, BYTE, BYTE, BYTE), 46: near set_cur(WORD), 47: near set_mode(BYTE), 48: near wherexy(BYTE *, BYTE *); 49: #else 50: private BYTE near get_mode(); 51: 52: private WORD 53: near cur_page(), 54: near get_cur(); 55: 56: private void 57: near ch_out(), 58: near clr_eop(), 59: near cur_advance(), 60: near cur_down(), 61: near cur_left(), 62: near cur_right(), 63: near cur_up(), 64: near line_feed(), 65: near normfun(), 66: near scr_win(), 67: near set_cur(), 68: near set_mode(), 69: near wherexy(); 70: #endif /* LINT_ARGS */ 71: 72: #ifdef MAC 73: # undef private 74: # define private static 75: #endif 76: 77: #define VIDEO 0x10 78: 79: #define intr(n, r) int86(n, r, r); 80: 81: BYTE CHPL=80, 82: LPP=25, 83: CUR_PAGE=0, 84: C_ATTR = 0x07, 85: C_X=0, 86: C_Y=0; 87: 88: int Fgcolor = 7, 89: Bgcolor = 0, 90: Mdcolor = 0; 91: 92: void setcolor(fg, bg) 93: BYTE fg, bg; 94: { 95: C_ATTR = ((bg&0xf)<<4)|(fg&0xf); 96: } 97: 98: private 99: WORD near cur_page() 100: { 101: union REGS vr; 102: 103: vr.h.ah = 0x0f; 104: intr(VIDEO, &vr); 105: return(vr.h.bh); 106: } 107: 108: private 109: void near set_cur(xy) 110: WORD xy; 111: { 112: union REGS vr; 113: 114: vr.h.bh = CUR_PAGE; 115: vr.h.ah = 0x02; 116: vr.x.dx = xy; 117: intr(VIDEO, &vr); 118: } 119: 120: private 121: WORD near get_cur() 122: { 123: union REGS vr; 124: 125: vr.h.bh = CUR_PAGE; 126: vr.h.ah = 0x03; 127: intr(VIDEO, &vr); 128: return (vr.x.dx); 129: } 130: 131: private 132: BYTE near get_mode() 133: { 134: union REGS vr; 135: 136: vr.h.ah = 0x0f; 137: intr(VIDEO, &vr); 138: return(vr.h.al); 139: } 140: 141: BYTE lpp() 142: { 143: int far *regen = (int far *) 0x44C; 144: int what; 145: BYTE chpl(); 146: 147: what = (*regen&0xff00)/2/chpl(); 148: return (what > 43 ? 25 : what); 149: } 150: 151: private 152: void near set_mode(n) 153: BYTE n; 154: { 155: union REGS vr; 156: 157: vr.h.ah = 0x00; 158: vr.h.al = n; 159: intr(VIDEO, &vr); 160: } 161: 162: #define gotoxy(x,y) set_cur((x)<<8|((y)&0xff)) 163: #define cur_mov(x,y) set_cur((C_X=x)<<8|((C_Y=y)&0xff)) 164: 165: private 166: void near wherexy( x, y) 167: BYTE *x, *y; 168: { 169: register WORD xy; 170: 171: xy = get_cur(); 172: *x = xy>>8; 173: *y = xy&0xff; 174: } 175: 176: #define wherex() C_X 177: #define wherey() C_Y 178: 179: private 180: void near scr_win(no, ulr, ulc, lrr, lrc) 181: int no; 182: BYTE ulr, ulc, lrr, lrc; 183: { 184: union REGS vr; 185: 186: if (no >= 0) 187: vr.h.ah = 0x06; 188: else { 189: vr.h.ah = 0x07; 190: no = - no; 191: } 192: vr.h.al = no; 193: vr.x.cx = ulr<<8 | ulc; 194: vr.x.dx = lrr<<8 | lrc; 195: vr.h.bh = C_ATTR; 196: intr(VIDEO, &vr); 197: } 198: 199: BYTE chpl() 200: { 201: union REGS vr; 202: 203: vr.h.ah = 0x0f; 204: intr(VIDEO, &vr); 205: return(vr.h.ah); 206: } 207: 208: #define clr_page() scr_win(0, 0, 0, LPP-1, CHPL-1), \ 209: gotoxy(C_X = 0, C_Y = 0) 210: 211: private 212: void near cur_right() 213: { 214: if (C_Y < CHPL-1) 215: C_Y++; 216: gotoxy(C_X, C_Y); 217: } 218: 219: private 220: void near cur_up() 221: { 222: if (C_X) 223: C_X--; 224: gotoxy(C_X, C_Y); 225: } 226: 227: private 228: void near cur_left() 229: { 230: if (C_Y) 231: C_Y--; 232: gotoxy(C_X, C_Y); 233: } 234: 235: private 236: void near cur_down() 237: { 238: if (C_X < LPP-1) 239: C_X++; 240: gotoxy(C_X, C_Y); 241: } 242: 243: private 244: void near ch_out(c, n) 245: BYTE c, n; 246: { 247: union REGS vr; 248: 249: vr.h.ah = 0x09; 250: vr.h.al = c; 251: vr.h.bl = C_ATTR; 252: vr.h.bh = CUR_PAGE; 253: vr.x.cx = n; 254: intr(VIDEO, &vr); 255: } 256: 257: #define wrch(c) ch_out((c), 1), cur_advance() 258: 259: #define home_cur() gotoxy(C_X = 0, C_Y = 0) 260: 261: #define clr_eoln() ch_out(' ', CHPL-wherey()) 262: 263: private 264: void near clr_eop() 265: { 266: clr_eoln(); 267: scr_win(LPP-1-wherex(), wherex()+1, 0, LPP-1, CHPL-1); 268: } 269: 270: void init_43() 271: { 272: BYTE far *info = (BYTE far *) 0x487; 273: WORD far *CRTC = (WORD far *) 0x463; 274: union REGS vr; 275: WORD cur; 276: 277: CUR_PAGE = cur_page(); 278: CHPL = chpl(); 279: LPP = lpp(); 280: 281: if (get_mode()!=3) 282: set_mode(3); 283: cur = get_cur(); 284: 285: vr.x.ax = 0x1112; 286: vr.h.bl = 0; 287: intr(VIDEO, &vr); 288: 289: *info |= 1; 290: vr.x.ax = 0x0100; 291: vr.h.bh = 0; 292: vr.x.cx = 0x0600; 293: intr(VIDEO, &vr); 294: 295: outp(*CRTC, 0x14); 296: outp(*CRTC+1, 0x07); 297: 298: vr.x.ax = 0x1200; 299: vr.h.bl = 0x20; 300: intr(VIDEO, &vr); 301: 302: LPP = lpp(); 303: 304: set_cur(cur); 305: wherexy(&C_X, &C_Y); 306: } 307: 308: void reset_43() 309: { 310: BYTE far *info = (BYTE far *) 0x487; 311: WORD far *CRTC = (WORD far *) 0x463; 312: union REGS vr; 313: 314: set_mode(3); 315: 316: *info &= 128; 317: vr.x.ax = 0x0100; 318: vr.h.bh = 0x0607; 319: vr.x.cx = 0x0607; 320: intr(VIDEO, &vr); 321: 322: outp(*CRTC, 0x14); 323: outp(*CRTC+1, 13); 324: 325: } 326: 327: #define scr_up() scr_win(1, 0, 0, LPP-1, CHPL-1) 328: #define back_space() cur_left() 329: 330: private 331: void near line_feed() 332: { 333: if (++C_X > LPP-1) { 334: C_X = LPP-1; 335: scr_up(); 336: } 337: gotoxy(C_X, C_Y); 338: } 339: 340: #define BELL_P 0x61 /* speaker */ 341: #define BELL_D 0x2dc /* 550 hz */ 342: #define TIME_P 0x40 /* timer */ 343: #define TINI 182 /* 10110110b timer initialization */ 344: 345: void dobell(x) 346: { 347: unsigned int n = 0x8888; 348: int orgval; 349: 350: outp(TIME_P+3, TINI); 351: outp(TIME_P+2, BELL_D&0xff); 352: outp(TIME_P+2, BELL_D>>8); 353: orgval = inp(BELL_P); 354: outp(BELL_P, orgval|3); /* turn speaker on */ 355: while (--n > 0) 356: ; 357: outp(BELL_P, orgval); 358: } 359: 360: #define carriage_return() gotoxy(wherex(), C_Y = 0) 361: 362: private 363: void near cur_advance() 364: { 365: if (++C_Y > CHPL-1) { 366: C_Y = 0; 367: if (++C_X > LPP-1) { 368: scr_up(); 369: C_X = LPP-1; 370: } 371: } 372: gotoxy(C_X, C_Y); 373: } 374: 375: void init_term() 376: { 377: if (lpp() == 43) 378: reset_43(); 379: CUR_PAGE = cur_page(); 380: CHPL = chpl(); 381: LPP = lpp(); 382: wherexy(&C_X, &C_Y); 383: } 384: 385: private 386: void near normfun(); 387: 388: void write_em(s) 389: char *s; 390: { 391: while (*s) 392: normfun(*s++); 393: } 394: 395: void write_emif(s) 396: char *s; 397: { 398: if (s) 399: write_em(s); 400: } 401: 402: void write_emc(s, n) 403: char *s; 404: int n; 405: { 406: while (n--) 407: normfun(*s++); 408: } 409: 410: private 411: void near normfun(c) 412: char c; 413: { 414: switch (c) { 415: case 10: line_feed(); break; 416: case 13: carriage_return(); break; 417: case 8: back_space(); break; 418: case 7: dobell(0); break; 419: case 0: break; 420: default: wrch(c); 421: } 422: } 423: 424: #endif /* IBMPC */ 425: 426: 427: extern int BufSize; 428: 429: int AbortCnt, 430: tabstop = 8; 431: 432: #if !(defined(IBMPC) || defined(MAC)) 433: int (*TTins_line)(), 434: (*TTdel_line)(); 435: #endif /* (defined(IBMPC) || defined(MAC)) */ 436: 437: struct scrimage 438: *DesiredScreen = 0, 439: *PhysScreen = 0; 440: 441: struct screenline *Screen = 0, /* the screen (a bunch of screenline) */ 442: *Savelines = 0, /* another bunch (LI of them) */ 443: *Curline = 0; /* current line */ 444: char *cursor, /* offset into current Line */ 445: *cursend; 446: 447: int CapCol, 448: CapLine, 449: 450: i_line, 451: i_col; 452: 453: void 454: make_scr() 455: { 456: register int i; 457: register struct screenline *ns; 458: register char *nsp; 459: 460: #ifdef RESHAPING 461: /* In case we are RESHAPING the window! */ 462: if (DesiredScreen) 463: free((char *) DesiredScreen); 464: if (PhysScreen) 465: free((char *) PhysScreen); 466: if (Savelines) 467: free((char *) Savelines); 468: if (Screen) { 469: free(Screen->s_line); /* free all the screen data */ 470: free((char *) Screen); 471: } 472: #endif /* RESHAPING */ 473: 474: DesiredScreen = (struct scrimage *) malloc((unsigned) LI * sizeof (struct scrimage)); 475: PhysScreen = (struct scrimage *) malloc((unsigned) LI * sizeof (struct scrimage)); 476: 477: Savelines = (struct screenline *) 478: malloc((unsigned) LI * sizeof(struct screenline)); 479: ns = Screen = (struct screenline *) 480: malloc((unsigned) LI * sizeof(struct screenline)); 481: 482: nsp = (char *) malloc((unsigned)CO * LI); 483: if (nsp == 0) { 484: printf("\n\rCannot malloc screen!\n"); 485: finish(1); 486: } 487: 488: for (i = 0; i < LI; i++) { 489: ns->s_line = nsp; 490: nsp += CO; 491: ns->s_length = nsp - 1; /* End of Line */ 492: ns += 1; 493: } 494: cl_scr(0); 495: } 496: 497: void 498: clrline(cp1, cp2) 499: register char *cp1, 500: *cp2; 501: { 502: while (cp1 <= cp2) 503: *cp1++ = ' '; 504: } 505: 506: #if !(defined(IBMPC) || defined(MAC)) 507: # define sputc(c) ((*cursor != (char) (c)) ? dosputc(c) : (cursor++, i_col++)) 508: #endif /* (defined(IBMPC) || defined(MAC)) */ 509: 510: #ifdef IBMPC 511: int force = 0; 512: # define sputc(c) dosputc(c) 513: #endif /* IBMPC */ 514: 515: #ifdef MAC 516: # define sputc(c) bufputc(c) /* line buffered for mac display */ 517: #endif /* MAC */ 518: 519: #define soutputc(c) if (--n <= 0) break; else sputc(c) 520: 521: void 522: cl_eol() 523: { 524: if (cursor > cursend) 525: return; 526: 527: if (cursor < Curline->s_length) { 528: #if !(defined(IBMPC) || defined(MAC)) 529: if (CE) { 530: #endif /* (defined(IBMPC) || defined(MAC)) */ 531: Placur(i_line, i_col); 532: #ifdef TERMCAP 533: putpad(CE, 1); 534: #else 535: clr_eoln(); 536: #endif /* TERMCAP */ 537: clrline(cursor, Curline->s_length); 538: #if !(defined(IBMPC) || defined(MAC)) 539: } else { 540: /* Ugh. The slow way for dumb terminals. */ 541: register char *savecp = cursor; 542: 543: while (cursor <= Curline->s_length) 544: sputc(' '); 545: cursor = savecp; 546: } 547: #endif /* (defined(IBMPC) || defined(MAC)) */ 548: Curline->s_length = cursor; 549: } 550: } 551: 552: void 553: cl_scr(doit) 554: { 555: register int i; 556: register struct screenline *sp = Screen; 557: 558: for (i = 0; i < LI; i++, sp++) { 559: clrline(sp->s_line, sp->s_length); 560: sp->s_length = sp->s_line; 561: PhysScreen[i].s_id = 0; 562: } 563: if (doit) { 564: #ifdef TERMCAP 565: putpad(CL, LI); 566: #else 567: clr_page(); 568: #endif /* TERMCAP */ 569: CapCol = CapLine = 0; 570: UpdMesg = YES; 571: } 572: } 573: 574: #ifdef ID_CHAR 575: extern int IN_INSmode; 576: #endif 577: 578: /* Output one character (if necessary) at the current position */ 579: 580: #ifndef MAC 581: int /* only for lints sake */ 582: dosputc(c) 583: register char c; 584: { 585: #ifndef IBMPC 586: if (*cursor != c) { 587: # ifdef ID_CHAR 588: if (IN_INSmode) 589: INSmode(0); 590: # endif 591: #else /* IBMPC */ 592: if ((force) || (*cursor != c)) { 593: #endif /* IBMPC */ 594: if (i_line != CapLine || i_col != CapCol) 595: Placur(i_line, i_col); 596: #ifndef IBMPC 597: if (UL && (c & CHARMASK) == '_' && (*cursor & CHARMASK) != ' ') 598: putstr(" \b"); /* Erase so '_' looks right. */ 599: #endif /* IBMPC */ 600: *cursor++ = c; 601: #ifndef IBMPC 602: putchar(c & CHARMASK); 603: #else /* IBMPC */ 604: normfun(c); 605: #endif /* IBMPC */ 606: AbortCnt -= 1; 607: CapCol += 1; 608: i_col += 1; 609: } else { 610: cursor += 1; 611: i_col += 1; 612: } 613: } 614: #else /* MAC */ 615: 616: /* Character output to bit-mapped screen is very expensive. It makes 617: much more sense to write the entire line at once. So, we print all 618: the characters, whether already there or not, once the line is 619: complete. */ 620: 621: #define BUFFLUSH (char) 0 622: #define BUFSTART (char) 1 623: 624: bufputc(c) 625: register char c; 626: { 627: static char buf[256]; 628: static int len = 0; 629: 630: if(c == BUFSTART) { 631: /* if (i_line != CapLine || i_col != CapCol)*/ 632: NPlacur(i_line, i_col); 633: len = 0; 634: return; 635: } 636: if(c == BUFFLUSH) { 637: buf[0] = (unsigned char) len; 638: writechr(buf); 639: len = 0; 640: } 641: else { 642: if(len > 255) return; 643: *cursor++ = c; 644: if(c == '0') buf[++len] = 0xAF; /* slashed zero */ 645: else buf[++len] = c; 646: CapCol++; 647: i_col++; 648: } 649: return; 650: } 651: #endif /* MAC */ 652: 653: /* Write `line' at the current position of `cursor'. Stop when we 654: reach the end of the screen. Aborts if there is a character 655: waiting. */ 656: 657: #ifdef MAC /* This was getting too complicated with ifdefs ... */ 658: int 659: swrite(line, inversep, abortable) 660: register char *line; 661: register int abortable; 662: { 663: register int c; 664: int col = i_col, 665: aborted = 0; 666: register int n = cursend - cursor; 667: 668: if (n <= 0) 669: return 1; 670: sputc(BUFSTART); /* Okay, because no interruption possible */ 671: 672: while (c = *line++) { 673: if (c == '\t') { 674: int nchars; 675: 676: nchars = (tabstop - (col % tabstop)); 677: col += nchars; 678: 679: while (nchars--) 680: soutputc(' '); 681: if (n <= 0) 682: break; 683: } else if (isctrl(c)) { 684: soutputc('^'); 685: c = ((c == '\177') ? '?' : c + '@'); 686: soutputc(c); 687: col += 2; 688: } else { 689: soutputc(c); 690: col += 1; 691: } 692: } 693: if (n <= 0) { 694: if ((*line == '\0') && (c != '\t') && !isctrl(c)) 695: sputc(c); 696: sputc('!'); 697: } 698: if (cursor > Curline->s_length) 699: Curline->s_length = cursor; 700: sputc(BUFFLUSH); 701: return !aborted; 702: } 703: #else /* MAC */ 704: 705: int 706: swrite(line, inversep, abortable) 707: register char *line; 708: register int abortable; 709: { 710: register int c; 711: int col = i_col, 712: aborted = 0; 713: register int n = cursend - cursor; 714: #ifndef IBMPC 715: int or_byte = inversep ? 0200 : 0, 716: thebyte; 717: #else 718: int thebyte; 719: #endif /* IBMPC */ 720: 721: #ifdef IBMPC 722: force = inversep? 1: 0; /* to force a redraw of the modeline */ 723: #endif /* IBMPC */ 724: 725: if (n <= 0) 726: return 1; 727: while (c = *line++) { 728: #if !(defined(IBMPC) || defined(MAC)) /* don't check after every character */ 729: if (abortable && AbortCnt < 0) { 730: AbortCnt = BufSize; 731: if (InputPending = charp()) { 732: aborted = 1; 733: break; 734: } 735: } 736: #endif /* (defined(IBMPC) || defined(MAC)) */ 737: if (c == '\t') { 738: int nchars; 739: 740: nchars = (tabstop - (col % tabstop)); 741: col += nchars; 742: 743: #ifndef IBMPC 744: thebyte = (' ' | or_byte); 745: #endif /* IBMPC */ 746: while (nchars--) 747: #ifndef IBMPC 748: soutputc(thebyte); 749: #else /* IBMPC */ 750: soutputc(' '); 751: #endif /* IBMPC */ 752: if (n <= 0) 753: break; 754: } else if (isctrl(c)) { 755: #ifndef IBMPC 756: thebyte = ('^' | or_byte); 757: soutputc(thebyte); 758: thebyte = (((c == '\177') ? '?' : c + '@') | or_byte); 759: soutputc(thebyte); 760: #else /* IBMPC */ 761: soutputc('^'); 762: c = ((c == '\177') ? '?' : c + '@'); 763: soutputc(c); 764: #endif /* IBMPC */ 765: col += 2; 766: } else { 767: #ifndef IBMPC 768: thebyte = (c | or_byte); 769: soutputc(thebyte); 770: #else /* IBMPC */ 771: if (c == 255) c = 1; 772: if (c == ' ' && inversep) c = 255; 773: soutputc(c); 774: #endif /* IBMPC */ 775: col += 1; 776: } 777: } 778: if (n <= 0) { 779: if ((*line == '\0') && (c != '\t') && !isctrl(c)) 780: #ifndef IBMPC 781: sputc(c|or_byte); 782: #else /* IBMPC */ 783: sputc(c); 784: #endif /* IBMPC */ 785: else 786: #ifndef IBMPC 787: sputc('!'|or_byte); 788: #else /* IBMPC */ 789: sputc('!'); 790: #endif /* IBMPC */ 791: } 792: if (cursor > Curline->s_length) 793: Curline->s_length = cursor; 794: #ifdef IBMPC 795: force = 0; 796: #endif 797: return !aborted; 798: } 799: #endif /* MAC */ 800: /* This is for writing a buffer line to the screen. This is to 801: minimize the amount of copying from one buffer to another buffer. 802: This gets the info directly from the disk buffers. */ 803: 804: int 805: BufSwrite(linenum) 806: { 807: register int n = cursend - cursor, 808: col = 0, 809: c = -1; 810: register char *bp; 811: int StartCol = DesiredScreen[linenum].s_offset, 812: visspace = DesiredScreen[linenum].s_window->w_flags & W_VISSPACE, 813: aborted = 0; 814: 815: bp = lcontents(DesiredScreen[linenum].s_lp); 816: if (*bp) for (;;) { 817: if (col >= StartCol) { 818: DesiredScreen[linenum].s_offset = col; 819: break; 820: } 821: 822: c = *bp++ & CHARMASK; 823: if (c == '\0') 824: break; 825: if (c == '\t') 826: col += (tabstop - (col % tabstop)); 827: else if (isctrl(c)) 828: col += 2; 829: else 830: col += 1; 831: } 832: #ifdef MAC 833: sputc(BUFSTART); /* Okay because we can't be interrupted */ 834: #endif 835: 836: if (c != '\0') while (c = *bp++) { 837: #if !(defined(IBMPC) || defined(MAC)) /* will never get true so why bother */ 838: if (AbortCnt < 0) { 839: AbortCnt = BufSize; 840: if (InputPending = charp()) { 841: aborted = 1; 842: break; 843: } 844: } 845: #endif /* (defined(IBMPC) || defined(MAC)) */ 846: if (c == '\t') { 847: int nchars = (tabstop - (col % tabstop)); 848: 849: col += nchars; 850: if (visspace) { 851: soutputc('>'); 852: nchars -= 1; 853: } 854: while (--nchars >= 0) 855: soutputc(' '); 856: if (n <= 0) 857: break; 858: } else if (isctrl(c)) { 859: soutputc('^'); 860: soutputc((c == '\177') ? '?' : c + '@'); 861: col += 2; 862: } else { 863: if (c == ' ' && visspace) 864: c = '_'; 865: #ifdef IBMPC 866: if (c == 255) 867: c = 1; 868: #endif /* IBMPC */ 869: soutputc(c); 870: col += 1; 871: } 872: } 873: if (n <= 0) { 874: if ((*bp == '\0') && (c != '\t') && !isctrl(c)) 875: sputc(c); 876: else 877: sputc('!'); 878: } 879: if (cursor > Curline->s_length) 880: Curline->s_length = cursor; 881: #ifdef MAC 882: sputc(BUFFLUSH); 883: #endif 884: return !aborted; /* Didn't abort */ 885: } 886: 887: void 888: i_set(nline, ncol) 889: register int nline, 890: ncol; 891: { 892: Curline = &Screen[nline]; 893: cursor = Curline->s_line + ncol; 894: cursend = &Curline->s_line[CO - 1]; 895: i_line = nline; 896: i_col = ncol; 897: } 898: 899: /* Insert `num' lines a top, but leave all the lines BELOW `bottom' 900: alone (at least they won't look any different when we are done). 901: This changes the screen array AND does the physical changes. */ 902: 903: void 904: v_ins_line(num, top, bottom) 905: { 906: register int i; 907: 908: /* Save the screen pointers. */ 909: 910: for(i = 0; i < num && top + i <= bottom; i++) 911: Savelines[i] = Screen[bottom - i]; 912: 913: /* Num number of bottom lines will be lost. 914: Copy everything down num number of times. */ 915: 916: for (i = bottom; i > top && i-num >= 0; i--) 917: Screen[i] = Screen[i - num]; 918: 919: /* Restore the saved ones, making them blank. */ 920: 921: for (i = 0; i < num; i++) { 922: Screen[top + i] = Savelines[i]; 923: clrline(Screen[top + i].s_line, Screen[top + i].s_length); 924: Screen[top + i].s_length = Screen[top + i].s_line; 925: } 926: 927: #if !(defined(IBMPC) || defined(MAC)) 928: (*TTins_line)(top, bottom, num); 929: #endif 930: 931: #ifdef MAC 932: i_lines(top, bottom, num); 933: #endif 934: 935: #ifdef IBMPC 936: scr_win(-num, top, 0, bottom, CHPL-1); 937: #endif 938: } 939: 940: /* Delete `num' lines starting at `top' leaving the lines below `bottom' 941: alone. This updates the internal image as well as the physical image. */ 942: 943: void 944: v_del_line(num, top, bottom) 945: { 946: register int i, 947: bot; 948: 949: bot = bottom; 950: 951: /* Save the lost lines. */ 952: 953: for (i = 0; i < num && top + i <= bottom; i++) 954: Savelines[i] = Screen[top + i]; 955: 956: /* Copy everything up num number of lines. */ 957: 958: for (i = top; num + i <= bottom; i++) 959: Screen[i] = Screen[i + num]; 960: 961: /* Restore the lost ones, clearing them. */ 962: 963: for (i = 0; i < num; i++) { 964: Screen[bottom - i] = Savelines[i]; 965: clrline(Screen[bot].s_line, Screen[bot].s_length); 966: Screen[bot].s_length = Screen[bot].s_line; 967: bot -= 1; 968: } 969: 970: #if !(defined(IBMPC) || defined(MAC)) 971: (*TTdel_line)(top, bottom, num); 972: #endif 973: 974: #ifdef MAC 975: d_lines(top, bottom, num); 976: #endif 977: 978: #ifdef IBMPC 979: scr_win(num, top, 0, bottom, CHPL-1); 980: #endif 981: 982: } 983: 984: #ifndef MAC /* remainder of this file */ 985: #ifdef IBMPC 986: 987: /* No cursor optimization on an IBMPC, this simplifies things a lot. 988: Think about it: it would be silly! 989: */ 990: 991: int phystab = 8; 992: 993: void 994: Placur(line, col) 995: { 996: cur_mov(line, col); 997: CapCol = col; 998: CapLine = line; 999: } 1000: 1001: void 1002: SO_on() 1003: { 1004: if (Mdcolor) 1005: setcolor(Mdcolor&0xf, Mdcolor>>4); 1006: else 1007: setcolor(Bgcolor, Fgcolor); 1008: } 1009: 1010: void 1011: SO_off() 1012: { 1013: setcolor(Fgcolor, Bgcolor); 1014: } 1015: 1016: extern int EGA; 1017: 1018: void 1019: 1020: UnsetTerm(foo) 1021: char *foo; 1022: { 1023: Placur(ILI, 0); 1024: clr_eoln(); 1025: if (EGA) 1026: reset_43(); 1027: } 1028: 1029: 1030: void 1031: ResetTerm() 1032: { 1033: if (EGA) 1034: init_43(); 1035: else 1036: init_term(); 1037: 1038: do_sgtty(); /* this is so if you change baudrate or stuff 1039: like that, JOVE will notice. */ 1040: ttyset(ON); 1041: } 1042: 1043: #else /* IBMPC */ 1044: 1045: /* The cursor optimization happens here. You may decide that this 1046: is going too far with cursor optimization, or perhaps it should 1047: limit the amount of checking to when the output speed is slow. 1048: What ever turns you on ... */ 1049: 1050: private struct cursaddr { 1051: int cm_numchars, 1052: (*cm_proc)(); 1053: }; 1054: 1055: private char *Cmstr; 1056: private struct cursaddr *HorMin, 1057: *VertMin, 1058: *DirectMin; 1059: 1060: private void 1061: GENi_lines(), 1062: GENd_lines(), 1063: ForMotion(), 1064: ForTab(), 1065: BackMotion(), 1066: RetTab(), 1067: DownMotion(), 1068: UpMotion(), 1069: GoDirect(), 1070: HomeGo(), 1071: BottomUp(); 1072: 1073: 1074: private struct cursaddr WarpHor[] = { 1075: 0, ForMotion, 1076: 0, ForTab, 1077: 0, BackMotion, 1078: 0, RetTab 1079: }; 1080: 1081: private struct cursaddr WarpVert[] = { 1082: 0, DownMotion, 1083: 0, UpMotion 1084: }; 1085: 1086: private struct cursaddr WarpDirect[] = { 1087: 0, GoDirect, 1088: 0, HomeGo, 1089: 0, BottomUp 1090: }; 1091: 1092: #undef FORWARD 1093: #define FORWARD 0 /* Move forward */ 1094: #define FORTAB 1 /* Forward using tabs */ 1095: #undef BACKWARD 1096: #define BACKWARD 2 /* Move backward */ 1097: #define RETFORWARD 3 /* Beginning of line and then tabs */ 1098: #define NUMHOR 4 1099: 1100: #define DOWN 0 /* Move down */ 1101: #define UPMOVE 1 /* Move up */ 1102: #define NUMVERT 2 1103: 1104: #define DIRECT 0 /* Using CM */ 1105: #define HOME 1 /* HOME */ 1106: #define LOWER 2 /* Lower Line */ 1107: #define NUMDIRECT 3 1108: 1109: #define home() Placur(0, 0) 1110: #define LowLine() putpad(LL, 1), CapLine = ILI, CapCol = 0 1111: #define PrintHo() putpad(HO, 1), CapLine = CapCol = 0 1112: 1113: int phystab = 8; 1114: 1115: private void 1116: GoDirect(line, col) 1117: register int line, 1118: col; 1119: { 1120: putpad(Cmstr, 1); 1121: CapLine = line; 1122: CapCol = col; 1123: } 1124: 1125: private void 1126: RetTab(col) 1127: register int col; 1128: { 1129: putchar('\r'); 1130: CapCol = 0; 1131: ForTab(col); 1132: } 1133: 1134: private void 1135: HomeGo(line, col) 1136: { 1137: PrintHo(); 1138: DownMotion(line); 1139: ForTab(col); 1140: } 1141: 1142: private void 1143: BottomUp(line, col) 1144: register int line, 1145: col; 1146: { 1147: LowLine(); 1148: UpMotion(line); 1149: ForTab(col); 1150: } 1151: 1152: /* Tries to move forward using tabs (if possible). It tabs to the 1153: closest tabstop which means it may go past 'destcol' and backspace 1154: to it. */ 1155: 1156: private void 1157: ForTab(destcol) 1158: int destcol; 1159: { 1160: register int tabgoal, 1161: ntabs, 1162: tabstp = phystab; 1163: 1164: if (TABS && (tabstp > 0)) { 1165: tabgoal = destcol + (tabstp / 2); 1166: tabgoal -= (tabgoal % tabstp); 1167: 1168: /* Don't tab to last place or else it is likely to screw up. */ 1169: if (tabgoal >= CO) 1170: tabgoal -= tabstp; 1171: 1172: ntabs = (tabgoal / tabstp) - (CapCol / tabstp); 1173: while (--ntabs >= 0) 1174: putchar('\t'); 1175: CapCol = tabgoal; 1176: } 1177: if (CapCol > destcol) 1178: BackMotion(destcol); 1179: else if (CapCol < destcol) 1180: ForMotion(destcol); 1181: } 1182: 1183: private void 1184: ForMotion(destcol) 1185: register int destcol; 1186: { 1187: register int nchars = destcol - CapCol; 1188: register char *cp = &Screen[CapLine].s_line[CapCol]; 1189: 1190: while (--nchars >= 0) 1191: putchar(*cp++ & CHARMASK); 1192: CapCol = destcol; 1193: } 1194: 1195: private void 1196: BackMotion(destcol) 1197: register int destcol; 1198: { 1199: register int nchars = CapCol - destcol; 1200: 1201: if (BC) 1202: while (--nchars >= 0) 1203: putpad(BC, 1); 1204: else 1205: while (--nchars >= 0) 1206: putchar('\b'); 1207: CapCol = destcol; 1208: } 1209: 1210: private void 1211: DownMotion(destline) 1212: register int destline; 1213: { 1214: register int nlines = destline - CapLine; 1215: 1216: while (--nlines >= 0) 1217: putpad(NL, 1); 1218: CapLine = destline; 1219: } 1220: 1221: private void 1222: UpMotion(destline) 1223: register int destline; 1224: { 1225: register int nchars = CapLine - destline; 1226: 1227: while (--nchars >= 0) 1228: putpad(UP, 1); 1229: CapLine = destline; 1230: } 1231: 1232: #ifdef ID_CHAR 1233: static int EIlen; 1234: #endif 1235: extern int IMlen; 1236: 1237: void 1238: InitCM() 1239: { 1240: HOlen = HO ? strlen(HO) : 1000; 1241: LLlen = LL ? strlen(LL) : 1000; 1242: UPlen = UP ? strlen(UP) : 1000; 1243: #ifdef ID_CHAR 1244: if (EI) 1245: EIlen = strlen(EI); 1246: #endif 1247: } 1248: 1249: void 1250: Placur(line, col) 1251: { 1252: int dline, /* Number of lines to move */ 1253: dcol; /* Number of columns to move */ 1254: register int best, 1255: i; 1256: register struct cursaddr *cp; 1257: int xtracost = 0; /* Misc addition to cost. */ 1258: 1259: #define CursMin(which,addrs,max) \ 1260: for (best = 0, cp = &addrs[1], i = 1; i < max; i++, cp++) \ 1261: if (cp->cm_numchars < addrs[best].cm_numchars) \ 1262: best = i; \ 1263: which = &addrs[best]; 1264: 1265: if (line == CapLine && col == CapCol) 1266: return; /* We are already there. */ 1267: 1268: dline = line - CapLine; 1269: dcol = col - CapCol; 1270: #ifdef ID_CHAR 1271: if (IN_INSmode && MI) 1272: xtracost = EIlen + IMlen; 1273: /* If we're already in insert mode, it is likely that we will 1274: want to be in insert mode again, after the insert. */ 1275: #endif 1276: 1277: /* Number of characters to move horizontally for each case. 1278: 1: Just move forward by typing the right character on the screen. 1279: 2: Print the correct number of back spaces. 1280: 3: Try tabbing to the correct place. 1281: 4: Try going to the beginning of the line, and then tab. */ 1282: 1283: if (dcol == 1 || dcol == 0) { /* Most common case. */ 1284: HorMin = &WarpHor[FORWARD]; 1285: HorMin->cm_numchars = dcol + xtracost; 1286: } else { 1287: WarpHor[FORWARD].cm_numchars = dcol >= 0 ? dcol + xtracost : 1000; 1288: WarpHor[BACKWARD].cm_numchars = dcol < 0 ? -(dcol + xtracost) : 1000; 1289: WarpHor[FORTAB].cm_numchars = dcol >= 0 && TABS ? 1290: ForNum(CapCol, col) + xtracost : 1000; 1291: WarpHor[RETFORWARD].cm_numchars = (xtracost + 1 + (TABS ? ForNum(0, col) : col)); 1292: 1293: /* Which is the shortest of the bunch */ 1294: 1295: CursMin(HorMin, WarpHor, NUMHOR); 1296: } 1297: 1298: /* Moving vertically is more simple. */ 1299: 1300: WarpVert[DOWN].cm_numchars = dline >= 0 ? dline : 1000; 1301: WarpVert[UPMOVE].cm_numchars = dline < 0 ? ((-dline) * UPlen) : 1000; 1302: 1303: /* Which of these is simpler */ 1304: CursMin(VertMin, WarpVert, NUMVERT); 1305: 1306: /* Homing first and lowering first are considered 1307: direct motions. 1308: Homing first's total is the sum of the cost of homing 1309: and the sum of tabbing (if possible) to the right. */ 1310: 1311: if (VertMin->cm_numchars + HorMin->cm_numchars <= 3) { 1312: DirectMin = &WarpDirect[DIRECT]; /* A dummy ... */ 1313: DirectMin->cm_numchars = 100; 1314: } else { 1315: WarpDirect[DIRECT].cm_numchars = CM ? 1316: strlen(Cmstr = tgoto(CM, col, line)) : 1000; 1317: WarpDirect[HOME].cm_numchars = HOlen + line + 1318: WarpHor[RETFORWARD].cm_numchars; 1319: WarpDirect[LOWER].cm_numchars = LLlen + ((ILI - line) * UPlen) + 1320: WarpHor[RETFORWARD].cm_numchars; 1321: CursMin(DirectMin, WarpDirect, NUMDIRECT); 1322: } 1323: 1324: if (HorMin->cm_numchars + VertMin->cm_numchars < DirectMin->cm_numchars) { 1325: if (line != CapLine) 1326: (*VertMin->cm_proc)(line); 1327: if (col != CapCol) { 1328: #ifdef ID_CHAR 1329: if (IN_INSmode) /* We may use real characters ... */ 1330: INSmode(0); 1331: #endif 1332: (*HorMin->cm_proc)(col); 1333: } 1334: } else { 1335: #ifdef ID_CHAR 1336: if (IN_INSmode && !MI) 1337: INSmode(0); 1338: #endif 1339: (*DirectMin->cm_proc)(line, col); 1340: } 1341: } 1342: 1343: #define abs(x) ((x) >= 0 ? (x) : -(x)) 1344: 1345: int 1346: ForNum(from, to) 1347: register int from; 1348: { 1349: register int tabgoal, 1350: tabstp = phystab; 1351: int numchars = 0; 1352: 1353: if (from >= to) 1354: return from - to; 1355: if (TABS && (tabstp > 0)) { 1356: tabgoal = to + (tabstp / 2); 1357: tabgoal -= (tabgoal % tabstp); 1358: if (tabgoal >= CO) 1359: tabgoal -= tabstp; 1360: numchars = (tabgoal / tabstop) - (from / tabstp); 1361: from = tabgoal; 1362: } 1363: return numchars + abs(from - to); 1364: } 1365: 1366: #ifdef WIRED_TERMS 1367: 1368: void 1369: BGi_lines(top, bottom, num) 1370: { 1371: printf("\033[%d;%dr\033[%dL\033[r", top + 1, bottom + 1, num); 1372: CapCol = CapLine = 0; 1373: } 1374: 1375: void 1376: SUNi_lines(top, bottom, num) 1377: { 1378: Placur(bottom - num + 1, 0); 1379: printf("\033[%dM", num); 1380: Placur(top, 0); 1381: printf("\033[%dL", num); 1382: } 1383: 1384: void 1385: C100i_lines(top, bottom, num) 1386: { 1387: if (num <= 1) { 1388: GENi_lines(top, bottom, num); 1389: return; 1390: } 1391: printf("\033v%c%c%c%c", ' ', ' ', ' ' + bottom + 1, ' ' + CO); 1392: CapLine = CapCol = 0; 1393: Placur(top, 0); 1394: while (num--) 1395: putpad(AL, ILI - CapLine); 1396: printf("\033v%c%c%c%c", ' ', ' ', ' ' + LI, ' ' + CO); 1397: CapLine = CapCol = 0; 1398: } 1399: 1400: #endif /* WIRED_TERMS */ 1401: 1402: private void 1403: GENi_lines(top, bottom, num) 1404: { 1405: register int i; 1406: 1407: if (CS) { 1408: putpad(tgoto(CS, bottom, top), 1); 1409: CapCol = CapLine = 0; 1410: Placur(top, 0); 1411: for (i = 0; i < num; i++) 1412: putpad(SR, bottom - top); 1413: putpad(tgoto(CS, ILI, 0), 1); 1414: CapCol = CapLine = 0; 1415: } else { 1416: Placur(bottom - num + 1, 0); 1417: if (M_DL && (num > 1)) { 1418: char minibuf[16]; 1419: 1420: sprintf(minibuf, M_DL, num); 1421: putpad(minibuf, ILI - CapLine); 1422: } else { 1423: for (i = 0; i < num; i++) 1424: putpad(DL, ILI - CapLine); 1425: } 1426: Placur(top, 0); 1427: if (M_AL && (num > 1)) { 1428: char minibuf[16]; 1429: 1430: sprintf(minibuf, M_AL, num); 1431: putpad(minibuf, ILI - CapLine); 1432: } else { 1433: for (i = 0; i < num; i++) 1434: putpad(AL, ILI - CapLine); 1435: } 1436: } 1437: } 1438: 1439: #ifdef WIRED_TERMS 1440: 1441: void 1442: BGd_lines(top, bottom, num) 1443: { 1444: printf("\033[%d;%dr\033[%dM\033[r", top + 1, bottom + 1, num); 1445: CapCol = CapLine = 0; 1446: } 1447: 1448: void 1449: SUNd_lines(top, bottom, num) 1450: { 1451: Placur(top, 0); 1452: printf("\033[%dM", num); 1453: Placur(bottom + 1 - num, 0); 1454: printf("\033[%dL", num); 1455: } 1456: 1457: void 1458: C100d_lines(top, bottom, num) 1459: { 1460: if (num <= 1) { 1461: GENd_lines(top, bottom, num); 1462: return; 1463: } 1464: printf("\033v%c%c%c%c", ' ', ' ', ' ' + bottom + 1, ' ' + CO); 1465: CapLine = CapCol = 0; 1466: Placur(top, 0); 1467: while (num--) 1468: putpad(DL, ILI - CapLine); 1469: printf("\033v%c%c%c%c", ' ', ' ', ' ' + LI, ' ' + CO); 1470: CapLine = CapCol = 0; 1471: } 1472: 1473: #endif /* WIRED_TERMS */ 1474: 1475: private void 1476: GENd_lines(top, bottom, num) 1477: { 1478: register int i; 1479: 1480: if (CS) { 1481: putpad(tgoto(CS, bottom, top), 1); 1482: CapCol = CapLine = 0; 1483: Placur(bottom, 0); 1484: for (i = 0; i < num; i++) 1485: putpad(SF, bottom - top); 1486: putpad(tgoto(CS, ILI, 0), 1); 1487: CapCol = CapLine = 0; 1488: } else { 1489: Placur(top, 0); 1490: if (M_DL && (num > 1)) { 1491: char minibuf[16]; 1492: 1493: sprintf(minibuf, M_DL, num); 1494: putpad(minibuf, ILI - top); 1495: } else { 1496: for (i = 0; i < num; i++) 1497: putpad(DL, ILI - top); 1498: } 1499: Placur(bottom + 1 - num, 0); 1500: if (M_AL && (num > 1)) { 1501: char minibuf[16]; 1502: 1503: sprintf(minibuf, M_AL, num); 1504: putpad(minibuf, ILI - CapLine); 1505: } else { 1506: for (i = 0; i < num; i++) 1507: putpad(AL, ILI - CapLine); 1508: } 1509: } 1510: } 1511: 1512: struct ID_lookup { 1513: char *ID_name; 1514: int (*I_proc)(); /* proc to insert lines */ 1515: int (*D_proc)(); /* proc to delete lines */ 1516: } ID_trms[] = { 1517: "generic", GENi_lines, GENd_lines, /* This should stay here */ 1518: #ifdef WIRED_TERMS 1519: "sun", SUNi_lines, SUNd_lines, 1520: "bg", BGi_lines, BGd_lines, 1521: "c1", C100i_lines, C100d_lines, 1522: #endif /* WIRED_TERMS */ 1523: 0, 0, 0 1524: }; 1525: 1526: void 1527: IDline_setup(tname) 1528: char *tname; 1529: { 1530: register struct ID_lookup *idp; 1531: 1532: for (idp = &ID_trms[1]; idp->ID_name; idp++) 1533: if (strncmp(idp->ID_name, tname, strlen(idp->ID_name)) == 0) 1534: break; 1535: if (idp->ID_name == 0) 1536: idp = &ID_trms[0]; 1537: TTins_line = idp->I_proc; 1538: TTdel_line = idp->D_proc; 1539: } 1540: 1541: #endif /* IBMPC */ 1542: #endif /* MAC */