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 "ctype.h" 10: #include "termcap.h" 11: 12: 13: #ifdef MAC 14: # include "mac.h" 15: #else 16: # include <varargs.h> 17: # include <sys/stat.h> 18: #endif 19: 20: #include <signal.h> 21: 22: #ifdef MAC 23: # undef private 24: # define private 25: #endif 26: 27: #ifdef LINT_ARGS 28: private void 29: #ifdef ID_CHAR 30: DeTab(int, char *, char *, int, int), 31: DelChar(int, int, int), 32: InsChar(int, int, int, char *), 33: #endif 34: DoIDline(int), 35: do_cl_eol(int), 36: ModeLine(Window *), 37: mode_app(char *), 38: GotoDot(void), 39: UpdLine(int), 40: UpdWindow(Window *, int); 41: 42: private int 43: AddLines(int, int), 44: DelLines(int, int), 45: UntilEqual(int); 46: #else 47: private void 48: #ifdef ID_CHAR 49: DeTab(), 50: DelChar(), 51: InsChar(), 52: #endif 53: DoIDline(), 54: do_cl_eol(), 55: GotoDot(), 56: ModeLine(), 57: mode_app(), 58: UpdLine(), 59: UpdWindow(); 60: private int 61: AddLines(), 62: DelLines(), 63: UntilEqual(); 64: #endif /* LINT_ARGS */ 65: 66: #ifdef MAC 67: # undef private 68: # define private static 69: #endif 70: 71: int DisabledRedisplay = NO; 72: 73: /* Kludge windows gets called by the routines that delete lines from the 74: buffer. If the w->w_line or w->w_top are deleted and this procedure 75: is not called, the redisplay routine will barf. */ 76: 77: void 78: ChkWindows(line1, line2) 79: Line *line1; 80: register Line *line2; 81: { 82: register Window *w = fwind; 83: register Line *lp; 84: 85: do { 86: for (lp = line1->l_next; lp != line2->l_next; lp = lp->l_next) { 87: if (lp == w->w_top) 88: w->w_flags |= W_TOPGONE; 89: if (lp == w->w_line) 90: w->w_flags |= W_CURGONE; 91: } 92: w = w->w_next; 93: } while (w != fwind); 94: } 95: 96: extern int RingBell; 97: 98: void 99: redisplay() 100: { 101: extern int AbortCnt; 102: register Window *w = fwind; 103: int lineno, 104: done_ID = NO, 105: i; 106: register struct scrimage *des_p, 107: *phys_p; 108: 109: if (DisabledRedisplay == YES) 110: return; 111: curwind->w_line = curwind->w_bufp->b_dot; 112: curwind->w_char = curwind->w_bufp->b_char; 113: #ifdef MAC 114: InputPending = 0; 115: #else 116: if (InputPending = charp()) /* calls CheckEvent, which could */ 117: return; /* result in a call to rediplay(). We don't want that. */ 118: #endif 119: #ifdef JOB_CONTROL 120: if (UpdFreq) 121: sighold(SIGALRM); 122: #endif 123: if (RingBell) { 124: dobell(1); 125: RingBell = 0; 126: } 127: AbortCnt = BufSize; /* initialize this now */ 128: if (UpdMesg) 129: DrawMesg(YES); 130: 131: for (lineno = 0, w = fwind; lineno < ILI; w = w->w_next) { 132: UpdWindow(w, lineno); 133: lineno += w->w_height; 134: } 135: 136: UpdModLine = 0; /* Now that we've called update window, we can 137: assume that the modeline will be updated. But 138: if while redrawing the modeline the user types 139: a character, ModeLine() is free to set this on 140: again so that the modeline will be fully drawn 141: at the next redisplay. */ 142: 143: des_p = DesiredScreen; 144: phys_p = PhysScreen; 145: for (i = 0; i < ILI; i++, des_p++, phys_p++) { 146: if (!done_ID && (des_p->s_id != phys_p->s_id)) { 147: DoIDline(i); 148: done_ID = YES; 149: } 150: if ((des_p->s_flags & (DIRTY | L_MOD)) || 151: (des_p->s_id != phys_p->s_id) || 152: (des_p->s_vln != phys_p->s_vln) || 153: (des_p->s_offset != phys_p->s_offset)) 154: UpdLine(i); 155: if (InputPending) 156: goto ret; 157: } 158: 159: 160: if (Asking) { 161: Placur(LI - 1, min(CO - 2, calc_pos(mesgbuf, Asking))); 162: /* Nice kludge */ 163: flusho(); 164: } else 165: GotoDot(); 166: ret: 167: #ifdef JOB_CONTROL 168: if (UpdFreq) 169: sigrelse(SIGALRM); 170: #else 171: ; /* yuck */ 172: #endif 173: #ifdef MAC 174: if(Windchange) docontrols(); 175: #endif /* MAC */ 176: } 177: 178: #ifndef IBMPC 179: private void 180: dobell(n) 181: { 182: while (--n >= 0) { 183: #ifndef MAC 184: if (VisBell && VB) 185: putstr(VB); 186: else 187: putpad(BL, 1); 188: #else 189: SysBeep(5); 190: #endif 191: } 192: flusho(); 193: } 194: #endif /* IBMPC */ 195: 196: /* find_pos() returns the position on the line, that C_CHAR represents 197: in LINE */ 198: 199: int 200: find_pos(line, c_char) 201: Line *line; 202: { 203: return calc_pos(lcontents(line), c_char); 204: } 205: 206: int 207: calc_pos(lp, c_char) 208: register char *lp; 209: register int c_char; 210: { 211: register int pos = 0; 212: register int c; 213: 214: 215: while ((--c_char >= 0) && ((c = *lp++) & CHARMASK) != 0) { 216: if (c == '\t') 217: pos += (tabstop - (pos % tabstop)); 218: else if (isctrl(c)) 219: pos += 2; 220: else 221: pos += 1; 222: } 223: return pos; 224: } 225: 226: int UpdModLine = 0, 227: UpdMesg = 0, 228: CanScroll = 0; 229: 230: private void 231: DoIDline(start) 232: { 233: register struct scrimage *des_p = &DesiredScreen[start]; 234: struct scrimage *phys_p = &PhysScreen[start]; 235: register int i, 236: j; 237: 238: /* Some changes have been made. Try for insert or delete lines. 239: If either case has happened, Addlines and/or DelLines will do 240: necessary scrolling, also CONVERTING PhysScreen to account for the 241: physical changes. The comparison continues from where the 242: insertion/deletion takes place; this doesn't happen very often, 243: usually it happens with more than one window with the same 244: buffer. */ 245: 246: if (!CanScroll) 247: return; /* We should never have been called! */ 248: 249: for (i = start; i < ILI; i++, des_p++, phys_p++) 250: if (des_p->s_id != phys_p->s_id) 251: break; 252: 253: for (; i < ILI; i++) { 254: for (j = i + 1; j < ILI; j++) { 255: des_p = &DesiredScreen[j]; 256: phys_p = &PhysScreen[j]; 257: if (des_p->s_id != 0 && des_p->s_id == phys_p->s_id) 258: break; 259: if (des_p->s_id == PhysScreen[i].s_id) { 260: if (des_p->s_id == 0) 261: continue; 262: if (AddLines(i, j - i)) { 263: DoIDline(j); 264: return; 265: } 266: break; 267: } 268: if ((des_p = &DesiredScreen[i])->s_id == phys_p->s_id) { 269: if (des_p->s_id == 0) 270: continue; 271: if (DelLines(i, j - i)) { 272: DoIDline(i); 273: return; 274: } 275: break; 276: } 277: } 278: } 279: } 280: 281: /* Make DesiredScreen reflect what the screen should look like when we are done 282: with the redisplay. This deals with horizontal scrolling. Also makes 283: sure the current line of the Window is in the window. */ 284: 285: int ScrollAll = NO; 286: 287: private void 288: UpdWindow(w, start) 289: register Window *w; 290: { 291: Line *lp; 292: int i, 293: upper, /* top of window */ 294: lower, /* bottom of window */ 295: strt_col, /* starting print column of current line */ 296: ntries = 0; /* # of tries at updating window */ 297: register struct scrimage *des_p, 298: *phys_p; 299: Buffer *bp = w->w_bufp; 300: 301: retry: 302: if (w->w_flags & W_CURGONE) { 303: w->w_line = bp->b_dot; 304: w->w_char = bp->b_char; 305: } 306: if (w->w_flags & W_TOPGONE) 307: CentWind(w); /* reset topline of screen */ 308: w->w_flags &= ~(W_CURGONE | W_TOPGONE); 309: 310: /* make sure that the current line is in the window */ 311: upper = start; 312: lower = upper + w->w_height - 1; /* don't include modeline */ 313: for (i = upper, lp = w->w_top; i < lower && lp != 0; lp = lp->l_next, i++) 314: if (lp == w->w_line) 315: break; 316: if (i == lower || lp == 0) { 317: ntries += 1; 318: if (ntries == 1) { 319: CalcWind(w); 320: goto retry; 321: } else if (ntries == 2) { 322: w->w_top = w->w_line = w->w_bufp->b_first; 323: printf("\rERROR in redisplay: I got hopelessly lost!"); 324: dobell(2); 325: goto retry; 326: } else if (ntries == 3) { 327: printf("\n\rOops, still lost, quitting ...\r\n"); 328: finish(1); 329: } 330: } 331: 332: /* first do some calculations for the current line */ 333: { 334: int diff = (w->w_flags & W_NUMLINES) ? 8 : 0, 335: end_col; 336: 337: strt_col = (ScrollAll == YES) ? w->w_LRscroll : 338: PhysScreen[i].s_offset; 339: end_col = strt_col + (CO - 2) - diff; 340: /* Right now we are displaying from strt_col to 341: end_col of the buffer line. These are PRINT 342: columns, not actual characters. */ 343: w->w_dotcol = find_pos(w->w_line, w->w_char); 344: /* if the new dotcol is out of range, reselect 345: a horizontal window */ 346: if ((PhysScreen[i].s_offset == -1) || 347: (w->w_dotcol < strt_col) || 348: (w->w_dotcol >= end_col)) { 349: if (w->w_dotcol < ((CO - 2) - diff)) 350: strt_col = 0; 351: else 352: strt_col = w->w_dotcol - (CO / 2); 353: if (ScrollAll == YES) { 354: if (w->w_LRscroll != strt_col) 355: UpdModLine = YES; 356: w->w_LRscroll = strt_col; 357: } 358: } 359: w->w_dotline = i; 360: w->w_dotcol += diff; 361: } 362: 363: des_p = &DesiredScreen[upper]; 364: phys_p = &PhysScreen[upper]; 365: for (i = upper, lp = w->w_top; lp != 0 && i < lower; i++, des_p++, phys_p++, lp = lp->l_next) { 366: des_p->s_window = w; 367: des_p->s_lp = lp; 368: des_p->s_id = lp->l_dline & ~DIRTY; 369: des_p->s_flags = isdirty(lp) ? L_MOD : 0; 370: if (w->w_flags & W_NUMLINES) 371: des_p->s_vln = w->w_topnum + (i - upper); 372: else 373: des_p->s_vln = 0; 374: 375: if (lp == w->w_line) 376: des_p->s_offset = strt_col; 377: else 378: des_p->s_offset = w->w_LRscroll; 379: } 380: 381: /* Is structure assignment faster than copy each field separately? */ 382: if (i < lower) { 383: static struct scrimage dirty_plate = { 0, DIRTY, 0, 0, 0, 0 }, 384: clean_plate = { 0, 0, 0, 0, 0, 0 }; 385: 386: for (; i < lower; i++, des_p++, phys_p++) 387: if (phys_p->s_id != 0) 388: *des_p = dirty_plate; 389: else 390: *des_p = clean_plate; 391: } 392: 393: des_p->s_window = w; 394: des_p->s_flags = 0; 395: if (((des_p->s_id = (int) w->w_bufp) != phys_p->s_id) || UpdModLine) 396: des_p->s_flags = MODELINE | DIRTY; 397: #ifdef MAC 398: if(UpdModLine) Modechange = 1; 399: if(w == curwind && w->w_control) SetScrollBar(w->w_control); 400: #endif 401: } 402: 403: /* Write whatever is in mesgbuf (maybe we are Asking, or just printed 404: a message). Turns off the UpdateMesg line flag. */ 405: 406: void 407: DrawMesg(abortable) 408: { 409: #ifndef MAC /* same reason as in redisplay() */ 410: if (charp()) 411: return; 412: #endif 413: i_set(ILI, 0); 414: if (swrite(mesgbuf, NO, abortable)) { 415: cl_eol(); 416: UpdMesg = 0; 417: } 418: flusho(); 419: } 420: 421: /* Goto the current position in the current window. Presumably redisplay() 422: has already been called, and curwind->{w_dotline,w_dotcol} have been set 423: correctly. */ 424: 425: private void 426: GotoDot() 427: { 428: if (InputPending) 429: return; 430: Placur(curwind->w_dotline, curwind->w_dotcol - 431: PhysScreen[curwind->w_dotline].s_offset); 432: flusho(); 433: } 434: 435: private int 436: UntilEqual(start) 437: register int start; 438: { 439: register struct scrimage *des_p = &DesiredScreen[start], 440: *phys_p = &PhysScreen[start]; 441: 442: while ((start < ILI) && (des_p->s_id != phys_p->s_id)) { 443: des_p += 1; 444: phys_p += 1; 445: start += 1; 446: } 447: 448: return start; 449: } 450: 451: /* Calls the routine to do the physical changes, and changes PhysScreen to 452: reflect those changes. */ 453: 454: private int 455: AddLines(at, num) 456: register int at, 457: num; 458: { 459: register int i; 460: int bottom = UntilEqual(at + num); 461: 462: if (num == 0 || num >= ((bottom - 1) - at)) 463: return NO; /* we did nothing */ 464: v_ins_line(num, at, bottom - 1); 465: 466: /* Now change PhysScreen to account for the physical change. */ 467: 468: for (i = bottom - 1; i - num >= at; i--) 469: PhysScreen[i] = PhysScreen[i - num]; 470: for (i = 0; i < num; i++) 471: PhysScreen[at + i].s_id = 0; 472: return YES; /* we did something */ 473: } 474: 475: private int 476: DelLines(at, num) 477: register int at, 478: num; 479: { 480: register int i; 481: int bottom = UntilEqual(at + num); 482: 483: if (num == 0 || num >= ((bottom - 1) - at)) 484: return NO; 485: v_del_line(num, at, bottom - 1); 486: 487: for (i = at; num + i < bottom; i++) 488: PhysScreen[i] = PhysScreen[num + i]; 489: for (i = bottom - num; i < bottom; i++) 490: PhysScreen[i].s_id = 0; 491: return YES; 492: } 493: 494: /* Update line linenum in window w. Only set PhysScreen to DesiredScreen 495: if the swrite or cl_eol works, that is nothing is interupted by 496: characters typed. */ 497: 498: private void 499: UpdLine(linenum) 500: register int linenum; 501: { 502: register struct scrimage *des_p = &DesiredScreen[linenum]; 503: register Window *w = des_p->s_window; 504: 505: i_set(linenum, 0); 506: if (des_p->s_flags & MODELINE) 507: ModeLine(w); 508: else if (des_p->s_id) { 509: des_p->s_lp->l_dline &= ~DIRTY; 510: des_p->s_flags &= ~(DIRTY | L_MOD); 511: #ifdef ID_CHAR 512: if (!UseIC && (w->w_flags & W_NUMLINES)) 513: #else 514: if (w->w_flags & W_NUMLINES) 515: #endif 516: (void) swrite(sprint("%6d ", des_p->s_vln), NO, YES); 517: 518: #ifdef ID_CHAR 519: if (UseIC) { 520: char outbuf[MAXCOLS], 521: *lptr; 522: int fromcol = (w->w_flags & W_NUMLINES) ? 8 : 0; 523: 524: if (w->w_flags & W_NUMLINES) 525: sprintf(outbuf, "%6d ", des_p->s_vln); 526: lptr = lcontents(des_p->s_lp); 527: DeTab(des_p->s_offset, lptr, outbuf + fromcol, 528: (sizeof outbuf) - 1 - fromcol, 529: des_p->s_window->w_flags & W_VISSPACE); 530: if (IDchar(outbuf, linenum, 0)) 531: PhysScreen[linenum] = *des_p; 532: else if (i_set(linenum, 0), swrite(outbuf, NO, YES)) 533: do_cl_eol(linenum); 534: else 535: PhysScreen[linenum].s_id = -1; 536: } else 537: #endif /* ID_CHAR */ 538: if (BufSwrite(linenum)) 539: do_cl_eol(linenum); 540: else 541: PhysScreen[linenum].s_id = -1; 542: } else if (PhysScreen[linenum].s_id) /* not the same ... make sure */ 543: do_cl_eol(linenum); 544: } 545: 546: private void 547: do_cl_eol(linenum) 548: register int linenum; 549: { 550: cl_eol(); 551: PhysScreen[linenum] = DesiredScreen[linenum]; 552: } 553: 554: #ifdef ID_CHAR 555: 556: /* From here to the end of the file is code that tries to utilize the 557: insert/delete character feature on some terminals. It is very confusing 558: and not so well written code, AND there is a lot of it. You may want 559: to use the space for something else. */ 560: 561: extern struct screenline *Screen; 562: int IN_INSmode = 0; 563: 564: int UseIC; 565: 566: int DClen, 567: MDClen, 568: IClen, 569: MIClen, 570: IMlen, 571: CElen; 572: 573: void 574: disp_opt_init() 575: { 576: DClen = DC ? strlen(DC) : 0; 577: MDClen = M_DC ? strlen(M_DC) : 9999; 578: IClen = IC ? strlen(IC) : 0; 579: MIClen = M_IC ? strlen(M_IC) : 9999; 580: IMlen = IM ? strlen(IM) : 0; 581: CElen = CE ? strlen(CE) : 0; 582: 583: UseIC = (IC || IM || M_IC); 584: } 585: 586: void 587: INSmode(on) 588: { 589: if (on && !IN_INSmode) { 590: putpad(IM, 1); 591: IN_INSmode = YES; 592: } else if (!on && IN_INSmode) { 593: putpad(EI, 1); 594: IN_INSmode = NO; 595: } 596: } 597: 598: private void 599: DeTab(s_offset, buf, outbuf, limit, visspace) 600: register char *buf; 601: char *outbuf; 602: { 603: register char *phys_p = outbuf, 604: c; 605: register int pos = 0; 606: char *limitp = &outbuf[limit]; 607: 608: #define OkayOut(ch) if ((pos++ >= s_offset) && (phys_p < limitp))\ 609: *phys_p++ = ch;\ 610: else 611: 612: while (c = *buf++) { 613: if (c == '\t') { 614: int nchars = (tabstop - (pos % tabstop)); 615: 616: if (visspace) { 617: OkayOut('>'); 618: nchars -= 1; 619: } 620: while (--nchars >= 0) 621: OkayOut(' '); 622: 623: } else if (isctrl(c)) { 624: OkayOut('^'); 625: OkayOut(c == 0177 ? '?' : c + '@'); 626: } else { 627: if (visspace && c == ' ') 628: c = '_'; 629: OkayOut(c); 630: } 631: if (pos - s_offset >= CO) { 632: phys_p = &outbuf[CO - 1]; 633: *phys_p++ = '!'; 634: break; 635: } 636: } 637: *phys_p = 0; 638: } 639: 640: /* ID character routines full of special cases and other fun stuff like that. 641: It actually works though ... 642: 643: Returns Non-Zero if you are finished (no differences left). */ 644: 645: private int 646: IDchar(new, lineno, col) 647: register char *new; 648: { 649: register int i; 650: int j, 651: oldlen, 652: NumSaved; 653: register struct screenline *sline = &Screen[lineno]; 654: 655: oldlen = sline->s_length - sline->s_line; 656: 657: for (i = col; i < oldlen && new[i] != 0; i++) 658: if (sline->s_line[i] != new[i]) 659: break; 660: if (new[i] == 0 || i == oldlen) 661: return (new[i] == 0 && i == oldlen); 662: 663: for (j = i + 1; j < oldlen && new[j]; j++) { 664: if (new[j] == sline->s_line[i]) { 665: NumSaved = IDcomp(new + j, sline->s_line + i, 666: strlen(new)) + NumSimilar(new + i, 667: sline->s_line + i, j - i); 668: if (OkayInsert(NumSaved, j - i)) { 669: InsChar(lineno, i, j - i, new); 670: return(IDchar(new, lineno, j)); 671: } 672: } 673: } 674: 675: for (j = i + 1; j < oldlen && new[i]; j++) { 676: if (new[i] == sline->s_line[j]) { 677: NumSaved = IDcomp(new + i, sline->s_line + j, 678: oldlen - j); 679: if (OkayDelete(NumSaved, j - i, new[oldlen] == 0)) { 680: DelChar(lineno, i, j - i); 681: return(IDchar(new, lineno, j)); 682: } 683: } 684: } 685: return 0; 686: } 687: 688: private int 689: NumSimilar(s, t, n) 690: register char *s, 691: *t; 692: { 693: register int num = 0; 694: 695: while (n--) 696: if (*s++ == *t++) 697: num += 1; 698: return num; 699: } 700: 701: private int 702: IDcomp(s, t, len) 703: register char *s, 704: *t; 705: { 706: register int i; 707: int num = 0, 708: nonspace = 0; 709: char c; 710: 711: for (i = 0; i < len; i++) { 712: if ((c = *s++) != *t++) 713: break; 714: if (c != ' ') 715: nonspace++; 716: if (nonspace) 717: num += 1; 718: } 719: 720: return num; 721: } 722: 723: private int 724: OkayDelete(Saved, num, samelength) 725: { 726: /* If the old and the new are the same length, then we don't 727: * have to clear to end of line. We take that into consideration. 728: */ 729: return ((Saved + (!samelength ? CElen : 0)) 730: > min(MDClen, DClen * num)); 731: } 732: 733: private int 734: OkayInsert(Saved, num) 735: { 736: register int n = 0; 737: 738: if (IC) /* Per character prefixes */ 739: n = min(num * IClen, MIClen); 740: 741: if (IM && !IN_INSmode) { 742: /* Good terminal. Fewer characters in this case */ 743: n += IMlen; 744: } 745: 746: n += num; /* The characters themselves */ 747: 748: return Saved > n; 749: } 750: 751: extern int CapCol; 752: extern char *cursend; 753: extern struct screenline *Curline; 754: 755: private void 756: DelChar(lineno, col, num) 757: { 758: register char *from, 759: *to; 760: register int i; 761: struct screenline *sp = (&Screen[lineno]); 762: 763: Placur(lineno, col); 764: if (M_DC && num > 1) { 765: char minibuf[16]; 766: 767: sprintf(minibuf, M_DC, num); 768: putpad(minibuf, num); 769: } else { 770: for (i = num; --i >= 0; ) 771: putpad(DC, 1); 772: } 773: 774: to = sp->s_line + col; 775: from = to + num; 776: 777: byte_copy(from, to, sp->s_length - from + 1); 778: clrline(sp->s_length - num, sp->s_length); 779: sp->s_length -= num; 780: } 781: 782: private void 783: InsChar(lineno, col, num, new) 784: char *new; 785: { 786: register char *sp1, 787: *sp2, /* To push over the array. */ 788: *sp3; /* Last character to push over. */ 789: int i; 790: 791: i_set(lineno, 0); 792: sp2 = Curline->s_length + num; 793: 794: if (sp2 >= cursend) { 795: i_set(lineno, CO - num - 1); 796: cl_eol(); 797: sp2 = cursend - 1; 798: } 799: Curline->s_length = sp2; 800: sp1 = sp2 - num; 801: sp3 = Curline->s_line + col; 802: 803: while (sp1 >= sp3) 804: *sp2-- = *sp1--; 805: 806: new += col; 807: byte_copy(new, sp3, num); 808: /* The internal screen is correct, and now we have to do 809: the physical stuff. */ 810: 811: Placur(lineno, col); 812: if (IM) { 813: if (!IN_INSmode) 814: INSmode(1); 815: } else if (M_IC && num > 1) { 816: char minibuf[16]; 817: 818: sprintf(minibuf, M_IC, num); 819: putpad(minibuf, num); 820: } else if (IC) { 821: for (i = 0; i < num; i++) 822: putpad(IC, 1); 823: } 824: for (i = 0; i < num; i++) { 825: putchar(new[i]); 826: if (IN_INSmode) 827: putpad(IP, 1); 828: } 829: CapCol += num; 830: } 831: 832: #endif /* ID_CHAR */ 833: 834: #ifdef UNIX /* obviously ... no mail today if not Unix*/ 835: 836: /* chkmail() returns nonzero if there is new mail since the 837: last time we checked. */ 838: 839: char Mailbox[FILESIZE]; /* initialized in main */ 840: int MailInt = 60; /* check no more often than 60 seconds */ 841: #ifdef BIFF 842: int BiffChk = NO; /* whether or not to turn off biff while in JOVE */ 843: #endif 844: 845: int 846: chkmail(force) 847: { 848: time_t now; 849: static time_t last_chk = 0; 850: static int value = FALSE; 851: static off_t last_size = 0; 852: struct stat stbuf; 853: int last_val; 854: static time_t last_time = 0; 855: 856: if (MailInt == 0) 857: return FALSE; 858: time(&now); 859: if ((now < last_chk + MailInt) && !force) 860: return value; 861: last_chk = now; 862: if (force) 863: last_time = now; 864: if (stat(Mailbox, &stbuf) < 0) { 865: value = FALSE; 866: return FALSE; 867: } 868: last_val = value; 869: value = ((stbuf.st_mtime > last_time) && 870: (stbuf.st_size > 0) && 871: (stbuf.st_size >= last_size) && 872: (stbuf.st_mtime + 5 > stbuf.st_atime)); 873: if (value == TRUE && 874: ((value != last_val) || (stbuf.st_size != last_size))) 875: dobell(3); 876: if (stbuf.st_size < last_size) 877: last_time = now; 878: last_size = stbuf.st_size; 879: return value; 880: } 881: 882: #endif /* UNIX */ 883: 884: /* Print the mode line. */ 885: 886: private char *mode_p, 887: *mend_p; 888: int BriteMode = 1; /* modeline should standout */ 889: 890: private void 891: mode_app(str) 892: register char *str; 893: { 894: if (mode_p >= mend_p) 895: return; 896: while ((mode_p < mend_p) && (*mode_p++ = *str++)) 897: ; 898: mode_p -= 1; /* back over the null */ 899: } 900: 901: char ModeFmt[120] = "%3c %w %[%sJOVE (%M) Buffer: %b \"%f\" %]%s%m*- %((%t)%s%)%e"; 902: 903: private void 904: ModeLine(w) 905: register Window *w; 906: { 907: extern int i_line; 908: extern char *pwd(); 909: int n, 910: ign_some = NO; 911: char line[MAXCOLS], 912: *fmt = ModeFmt, 913: fillc, 914: c; 915: register Buffer *thisbuf = w->w_bufp; 916: register Buffer *bp; 917: 918: mode_p = line; 919: mend_p = &line[(sizeof line) - 1]; 920: 921: #if defined(UNIX) || (defined (MSDOS) && !defined(IBMPC)) 922: if (BriteMode != 0 && SO == 0) 923: BriteMode = 0; 924: fillc = BriteMode ? ' ' : '-'; 925: #endif /* UNIX */ 926: #ifdef IBMPC /* very subtle - don't mess up attributes too much */ 927: fillc = '-'; /*BriteMode ? ' ' : '-';*/ 928: #endif /* IBMPC */ 929: #ifdef MAC 930: fillc = '_'; /* looks better on a Mac */ 931: #endif /* MAC */ 932: 933: while (c = *fmt++) { 934: if (c != '%') { 935: if (c == '\\') 936: if ((c = *fmt++) == '\0') 937: break; 938: if (!ign_some) 939: *mode_p++ = c; 940: continue; 941: } 942: if ((c = *fmt++) == '\0') /* char after the '%' */ 943: break; 944: if (ign_some && c != ')') 945: continue; 946: n = 1; 947: if (c >= '0' && c <= '9') { 948: n = 0; 949: while (c >= '0' && c <= '9') { 950: n = n * 10 + (c - '0'); 951: c = *fmt++; 952: } 953: } 954: switch (c) { 955: case '(': 956: if (w->w_next != fwind) /* Not bottom window. */ 957: ign_some = YES; 958: break; 959: 960: case ')': 961: ign_some = NO; 962: break; 963: 964: case '[': 965: case ']': 966: { 967: char *strs = (c == '[') ? "[[[[[[[[[[" : "]]]]]]]]]]"; 968: 969: mode_app(strs + 10 - RecDepth); 970: break; 971: } 972: 973: #ifdef UNIX 974: case 'C': /* check mail here */ 975: if (chkmail(NO)) 976: mode_app("[New mail]"); 977: break; 978: 979: #endif /* UNIX */ 980: 981: case 'M': 982: { 983: static char *mmodes[] = { 984: "Fundamental ", 985: "Text ", 986: "C ", 987: #ifdef LISP 988: "Lisp ", 989: #endif 990: 0 991: }; 992: 993: mode_app(mmodes[thisbuf->b_major]); 994: 995: if (BufMinorMode(thisbuf, Fill)) 996: mode_app("Fill "); 997: if (BufMinorMode(thisbuf, Abbrev)) 998: mode_app("Abbrev "); 999: if (BufMinorMode(thisbuf, OverWrite)) 1000: mode_app("OvrWt "); 1001: if (BufMinorMode(thisbuf, Indent)) 1002: mode_app("AI "); 1003: if (InMacDefine) 1004: mode_app("Def "); 1005: mode_p -= 1; /* Back over the extra space. */ 1006: break; 1007: } 1008: 1009: case 'c': 1010: while (--n >= 0) 1011: *mode_p++ = fillc; 1012: break; 1013: 1014: #ifdef CHDIR 1015: case 'd': /* print working directory */ 1016: mode_app(pr_name(pwd(), YES)); 1017: break; 1018: #endif 1019: 1020: case 'e': 1021: { 1022: /* 2 space pad pluss padding for magic cookies */ 1023: char *last_p = &line[CO - 2 - (2 * SG)]; 1024: 1025: while (mode_p < last_p) 1026: *mode_p++ = fillc; 1027: 1028: goto outahere; /* %e means we're done! */ 1029: } 1030: 1031: case 'b': 1032: mode_app(thisbuf->b_name); 1033: break; 1034: 1035: case 'f': 1036: case 'F': 1037: if (thisbuf->b_fname == 0) 1038: mode_app("[No file]"); 1039: else { 1040: if (c == 'f') 1041: mode_app(pr_name(thisbuf->b_fname, YES)); 1042: else 1043: mode_app(basename(thisbuf->b_fname)); 1044: } 1045: break; 1046: 1047: #ifdef LOAD_AV 1048: case 'l': 1049: { 1050: double theavg; 1051: char minibuf[10]; 1052: 1053: get_la(&theavg); 1054: theavg += .005; /* round to nearest .01 */ 1055: sprintf(minibuf, "%d.%02d", 1056: (int) theavg, 1057: (int)((theavg - (int) theavg) * 100)); 1058: mode_app(minibuf); 1059: break; 1060: } 1061: #endif 1062: 1063: case 'm': 1064: if (IsModified(w->w_bufp)) 1065: *mode_p++ = fmt[0]; 1066: else 1067: *mode_p++ = fmt[1]; 1068: fmt += 2; /* skip two characters */ 1069: break; 1070: 1071: case 'n': 1072: { 1073: char tmp[16]; 1074: for (bp = world, n = 1; bp != 0; bp = bp->b_next, n++) 1075: if (bp == thisbuf) 1076: break; 1077: 1078: sprintf(tmp, "%d", n); 1079: mode_app(tmp); 1080: break; 1081: } 1082: 1083: #ifdef IPROCS 1084: case 'p': 1085: if (thisbuf->b_type == B_PROCESS) { 1086: char tmp[40]; 1087: 1088: sprintf(tmp, "(%s)", (thisbuf->b_process == 0) ? 1089: "No process" : 1090: pstate(thisbuf->b_process)); 1091: mode_app(tmp); 1092: break; 1093: } 1094: #endif 1095: 1096: case 's': 1097: if (mode_p[-1] == ' ') 1098: continue; 1099: *mode_p++ = ' '; 1100: break; 1101: 1102: case 't': 1103: { 1104: char timestr[12]; 1105: 1106: mode_app(get_time((time_t *) 0, timestr, 11, 16)); 1107: break; 1108: } 1109: 1110: case 'w': 1111: if (w->w_LRscroll > 0) 1112: mode_app(">"); 1113: } 1114: } 1115: 1116: outahere: 1117: *mode_p = 0; 1118: 1119: /* Highlight mode line. */ 1120: if (BriteMode) { 1121: #ifdef ID_CHAR 1122: if (IN_INSmode) 1123: INSmode(0); 1124: #endif 1125: #ifdef TERMCAP 1126: putpad(SO, 1); 1127: #else 1128: SO_on(); 1129: #endif /* TERMCAP */ 1130: } 1131: if (swrite(line, BriteMode, YES)) 1132: do_cl_eol(i_line); 1133: else 1134: UpdModLine = 1; 1135: if (BriteMode) 1136: #ifdef TERMCAP 1137: putpad(SE, 1); 1138: #else 1139: SO_off(); 1140: #endif /* TERMCAP */ 1141: } 1142: 1143: /* This tries to place the current line of the current window in the 1144: center of the window, OR to place it at the arg'th line of the window. 1145: This also causes the horizontal position of the line to be centered, 1146: if the line needs scrolling, or moved all the way back to the left, 1147: if that's possible. */ 1148: void 1149: RedrawDisplay() 1150: { 1151: int line; 1152: Line *newtop = prev_line((curwind->w_line = curline), is_an_arg() ? 1153: arg_value() : HALF(curwind)); 1154: 1155: if ((line = in_window(curwind, curwind->w_line)) != -1) 1156: PhysScreen[line].s_offset = -1; 1157: if (newtop == curwind->w_top) 1158: v_clear(FLine(curwind), FLine(curwind) + SIZE(curwind)); 1159: else 1160: SetTop(curwind, newtop); 1161: } 1162: 1163: void 1164: v_clear(line1, line2) 1165: register int line1; 1166: { 1167: register struct scrimage *phys_p, *des_p; 1168: 1169: phys_p = &PhysScreen[line1]; 1170: des_p = &DesiredScreen[line1]; 1171: 1172: while (line1 <= line2) { 1173: i_set(line1, 0); 1174: cl_eol(); 1175: phys_p->s_id = des_p->s_id = 0; 1176: phys_p += 1; 1177: des_p += 1; 1178: line1 += 1; 1179: } 1180: } 1181: 1182: void 1183: ClAndRedraw() 1184: { 1185: cl_scr(YES); 1186: } 1187: 1188: void 1189: NextPage() 1190: { 1191: Line *newline; 1192: 1193: if (Asking) 1194: return; 1195: if (arg_value() < 0) { 1196: negate_arg_value(); 1197: PrevPage(); 1198: return; 1199: } 1200: if (arg_type() == YES) 1201: UpScroll(); 1202: else { 1203: if (in_window(curwind, curwind->w_bufp->b_last) != -1) { 1204: rbell(); 1205: return; 1206: } 1207: newline = next_line(curwind->w_top, max(1, SIZE(curwind) - 1)); 1208: SetTop(curwind, curwind->w_line = newline); 1209: if (curwind->w_bufp == curbuf) 1210: SetLine(newline); 1211: } 1212: } 1213: 1214: #ifdef MSDOS /* kg */ 1215: 1216: void 1217: PageScrollUp() 1218: { 1219: int i, n; 1220: 1221: n = max(1, SIZE(curwind) - 1); 1222: for (i=0; i<n; i++) { 1223: UpScroll(); 1224: redisplay(); 1225: } 1226: } 1227: 1228: void 1229: PageScrollDown() 1230: { 1231: int i, n; 1232: 1233: n = max(1, SIZE(curwind) - 1); 1234: for (i=0; i<n; i++) { 1235: DownScroll(); 1236: redisplay(); 1237: } 1238: } 1239: #endif /* MSDOS */ 1240: 1241: void 1242: PrevPage() 1243: { 1244: Line *newline; 1245: 1246: if (Asking) 1247: return; 1248: if (arg_value() < 0) { 1249: negate_arg_value(); 1250: NextPage(); 1251: return; 1252: } 1253: if (arg_type() == YES) 1254: DownScroll(); 1255: else { 1256: newline = prev_line(curwind->w_top, max(1, SIZE(curwind) - 1)); 1257: SetTop(curwind, curwind->w_line = newline); 1258: if (curwind->w_bufp == curbuf) 1259: SetLine(newline); 1260: } 1261: } 1262: 1263: void 1264: UpScroll() 1265: { 1266: SetTop(curwind, next_line(curwind->w_top, arg_value())); 1267: if ((curwind->w_bufp == curbuf) && 1268: (in_window(curwind, curline) == -1)) 1269: SetLine(curwind->w_top); 1270: } 1271: 1272: void 1273: DownScroll() 1274: { 1275: SetTop(curwind, prev_line(curwind->w_top, arg_value())); 1276: if ((curwind->w_bufp == curbuf) && 1277: (in_window(curwind, curline) == -1)) 1278: SetLine(curwind->w_top); 1279: } 1280: 1281: int VisBell = NO, 1282: RingBell = NO; /* So if we have a lot of errors ... 1283: ring the bell only ONCE */ 1284: void 1285: rbell() 1286: { 1287: RingBell = YES; 1288: } 1289: 1290: /* Message prints the null terminated string onto the bottom line of the 1291: terminal. */ 1292: 1293: void 1294: message(str) 1295: char *str; 1296: { 1297: if (InJoverc) 1298: return; 1299: UpdMesg = YES; 1300: errormsg = NO; 1301: if (str != mesgbuf) 1302: null_ncpy(mesgbuf, str, (sizeof mesgbuf) - 1); 1303: } 1304: 1305: /* End of Window */ 1306: 1307: void 1308: Eow() 1309: { 1310: if (Asking) 1311: return; 1312: SetLine(next_line(curwind->w_top, SIZE(curwind) - 1 - 1313: min(SIZE(curwind) - 1, arg_value() - 1))); 1314: if (!is_an_arg()) 1315: Eol(); 1316: } 1317: 1318: /* Beginning of Window */ 1319: 1320: void 1321: Bow() 1322: { 1323: if (Asking) 1324: return; 1325: SetLine(next_line(curwind->w_top, min(SIZE(curwind) - 1, arg_value() - 1))); 1326: } 1327: 1328: private int LineNo, 1329: last_col, 1330: DoAutoNL; 1331: private Window *old_wind; /* save the window we were in BEFORE 1332: before we were called, if UseBuffers 1333: is nonzero */ 1334: 1335: int UseBuffers = FALSE; 1336: int TOabort = 0; 1337: 1338: /* This initializes the typeout. If send-typeout-to-buffers is set 1339: the buffer NAME is created (emptied if it already exists) and output 1340: goes to the buffer. Otherwise output is drawn on the screen and 1341: erased by TOstop() */ 1342: 1343: void 1344: TOstart(name, auto_newline) 1345: char *name; 1346: { 1347: if (UseBuffers) { 1348: old_wind = curwind; 1349: pop_wind(name, YES, B_SCRATCH); 1350: } else 1351: DisabledRedisplay = YES; 1352: TOabort = LineNo = last_col = 0; 1353: DoAutoNL = auto_newline; 1354: } 1355: 1356: /* VARARGS1 */ 1357: 1358: void 1359: Typeout(fmt, va_alist) 1360: char *fmt; 1361: va_dcl 1362: { 1363: if (TOabort) 1364: return; 1365: 1366: if (!UseBuffers && (LineNo == ILI - 1)) { 1367: register int c; 1368: 1369: LineNo = 0; 1370: last_col = 0; 1371: f_mess("--more--"); 1372: if ((c = getchar()) != ' ') { 1373: TOabort = YES; 1374: if (c != AbortChar && c != RUBOUT) 1375: Ungetc(c); 1376: f_mess(NullStr); 1377: return; 1378: } 1379: f_mess(NullStr); 1380: } 1381: 1382: if (fmt) { 1383: extern int i_col; 1384: char string[132]; 1385: va_list ap; 1386: 1387: va_start(ap); 1388: format(string, sizeof string, fmt, ap); 1389: va_end(ap); 1390: if (UseBuffers) 1391: ins_str(string, NO); 1392: else { 1393: i_set(LineNo, last_col); 1394: (void) swrite(string, NO, YES); 1395: last_col = i_col; 1396: } 1397: } 1398: if (!UseBuffers) { 1399: PhysScreen[LineNo].s_id = -1; 1400: if (fmt == 0 || DoAutoNL == YES) { 1401: cl_eol(); 1402: flusho(); 1403: LineNo += 1; 1404: last_col = 0; 1405: } 1406: } else if (fmt == 0 || DoAutoNL != 0) 1407: ins_str("\n", NO); 1408: } 1409: 1410: void 1411: TOstop() 1412: { 1413: int c; 1414: 1415: if (UseBuffers) { 1416: ToFirst(); 1417: SetWind(old_wind); 1418: } else { 1419: if (TOabort) { 1420: DisabledRedisplay = NO; 1421: return; 1422: } 1423: if (last_col != 0) 1424: Typeout((char *) 0); 1425: Typeout("----------"); 1426: cl_eol(); 1427: flusho(); 1428: c = getchar(); 1429: if (c != ' ') 1430: Ungetc(c); 1431: DisabledRedisplay = NO; 1432: } 1433: }