|
|
1.1 root 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: time(&now);
857: if (!force && (now < last_chk + MailInt))
858: return value;
859: last_chk = now;
860: if (force)
861: last_time = now;
862: if (stat(Mailbox, &stbuf) < 0) {
863: value = FALSE;
864: return FALSE;
865: }
866: last_val = value;
867: value = ((stbuf.st_mtime > last_time) &&
868: (stbuf.st_size > 0) &&
869: (stbuf.st_size >= last_size) &&
870: (stbuf.st_mtime + 5 > stbuf.st_atime));
871: if (value == TRUE &&
872: ((value != last_val) || (stbuf.st_size != last_size)))
873: dobell(3);
874: if (stbuf.st_size < last_size)
875: last_time = now;
876: last_size = stbuf.st_size;
877: return value;
878: }
879:
880: #endif /* UNIX */
881:
882: /* Print the mode line. */
883:
884: private char *mode_p,
885: *mend_p;
886: int BriteMode = 1; /* modeline should standout */
887:
888: private void
889: mode_app(str)
890: register char *str;
891: {
892: if (mode_p >= mend_p)
893: return;
894: while ((mode_p < mend_p) && (*mode_p++ = *str++))
895: ;
896: mode_p -= 1; /* back over the null */
897: }
898:
899: char ModeFmt[120] = "%3c %w %[%sJOVE (%M) Buffer: %b \"%f\" %]%s%m*- %((%t)%s%)%e";
900:
901: private void
902: ModeLine(w)
903: register Window *w;
904: {
905: extern int i_line;
906: extern char *pwd();
907: int n,
908: ign_some = NO;
909: char line[MAXCOLS],
910: *fmt = ModeFmt,
911: fillc,
912: c;
913: register Buffer *thisbuf = w->w_bufp;
914: register Buffer *bp;
915:
916: mode_p = line;
917: mend_p = &line[(sizeof line) - 1];
918:
919: #if defined(UNIX) || (defined (MSDOS) && !defined(IBMPC))
920: if (BriteMode != 0 && SO == 0)
921: BriteMode = 0;
922: fillc = BriteMode ? ' ' : '-';
923: #endif /* UNIX */
924: #ifdef IBMPC /* very subtle - don't mess up attributes too much */
925: fillc = '-'; /*BriteMode ? ' ' : '-';*/
926: #endif /* IBMPC */
927: #ifdef MAC
928: fillc = '_'; /* looks better on a Mac */
929: #endif /* MAC */
930:
931: while (c = *fmt++) {
932: if (c != '%') {
933: if (c == '\\')
934: if ((c = *fmt++) == '\0')
935: break;
936: if (!ign_some)
937: *mode_p++ = c;
938: continue;
939: }
940: if ((c = *fmt++) == '\0') /* char after the '%' */
941: break;
942: if (ign_some && c != ')')
943: continue;
944: n = 1;
945: if (c >= '0' && c <= '9') {
946: n = 0;
947: while (c >= '0' && c <= '9') {
948: n = n * 10 + (c - '0');
949: c = *fmt++;
950: }
951: }
952: switch (c) {
953: case '(':
954: if (w->w_next != fwind) /* Not bottom window. */
955: ign_some = YES;
956: break;
957:
958: case ')':
959: ign_some = NO;
960: break;
961:
962: case '[':
963: case ']':
964: {
965: char *strs = (c == '[') ? "[[[[[[[[[[" : "]]]]]]]]]]";
966:
967: mode_app(strs + 10 - RecDepth);
968: break;
969: }
970:
971: #ifdef UNIX
972: case 'C': /* check mail here */
973: if (chkmail(NO))
974: mode_app("[New mail]");
975: break;
976:
977: #endif /* UNIX */
978:
979: case 'M':
980: {
981: static char *mmodes[] = {
982: "Fundamental ",
983: "Text ",
984: "C ",
985: #ifdef LISP
986: "Lisp ",
987: #endif
988: 0
989: };
990:
991: mode_app(mmodes[thisbuf->b_major]);
992:
993: if (BufMinorMode(thisbuf, Fill))
994: mode_app("Fill ");
995: if (BufMinorMode(thisbuf, Abbrev))
996: mode_app("Abbrev ");
997: if (BufMinorMode(thisbuf, OverWrite))
998: mode_app("OvrWt ");
999: if (BufMinorMode(thisbuf, Indent))
1000: mode_app("AI ");
1001: if (InMacDefine)
1002: mode_app("Def ");
1003: mode_p -= 1; /* Back over the extra space. */
1004: break;
1005: }
1006:
1007: case 'c':
1008: while (--n >= 0)
1009: *mode_p++ = fillc;
1010: break;
1011:
1012: #ifdef CHDIR
1013: case 'd': /* print working directory */
1014: mode_app(pr_name(pwd(), YES));
1015: break;
1016: #endif
1017:
1018: case 'e':
1019: {
1020: /* 2 space pad pluss padding for magic cookies */
1021: char *last_p = &line[CO - 2 - (2 * SG)];
1022:
1023: while (mode_p < last_p)
1024: *mode_p++ = fillc;
1025:
1026: goto outahere; /* %e means we're done! */
1027: }
1028:
1029: case 'b':
1030: mode_app(thisbuf->b_name);
1031: break;
1032:
1033: case 'f':
1034: case 'F':
1035: if (thisbuf->b_fname == 0)
1036: mode_app("[No file]");
1037: else {
1038: if (c == 'f')
1039: mode_app(pr_name(thisbuf->b_fname, YES));
1040: else
1041: mode_app(basename(thisbuf->b_fname));
1042: }
1043: break;
1044:
1045: #ifdef LOAD_AV
1046: case 'l':
1047: {
1048: double theavg;
1049: char minibuf[10];
1050:
1051: get_la(&theavg);
1052: theavg += .005; /* round to nearest .01 */
1053: sprintf(minibuf, "%d.%02d",
1054: (int) theavg,
1055: (int)((theavg - (int) theavg) * 100));
1056: mode_app(minibuf);
1057: break;
1058: }
1059: #endif
1060:
1061: case 'm':
1062: if (IsModified(w->w_bufp))
1063: *mode_p++ = fmt[0];
1064: else
1065: *mode_p++ = fmt[1];
1066: fmt += 2; /* skip two characters */
1067: break;
1068:
1069: case 'n':
1070: {
1071: char tmp[16];
1072: for (bp = world, n = 1; bp != 0; bp = bp->b_next, n++)
1073: if (bp == thisbuf)
1074: break;
1075:
1076: sprintf(tmp, "%d", n);
1077: mode_app(tmp);
1078: break;
1079: }
1080:
1081: #ifdef IPROCS
1082: case 'p':
1083: if (thisbuf->b_type == B_PROCESS) {
1084: char tmp[40];
1085:
1086: sprintf(tmp, "(%s)", (thisbuf->b_process == 0) ?
1087: "No process" :
1088: pstate(thisbuf->b_process));
1089: mode_app(tmp);
1090: break;
1091: }
1092: #endif
1093:
1094: case 's':
1095: if (mode_p[-1] == ' ')
1096: continue;
1097: *mode_p++ = ' ';
1098: break;
1099:
1100: case 't':
1101: {
1102: char timestr[12];
1103:
1104: mode_app(get_time((time_t *) 0, timestr, 11, 16));
1105: break;
1106: }
1107:
1108: case 'w':
1109: if (w->w_LRscroll > 0)
1110: mode_app(">");
1111: }
1112: }
1113:
1114: outahere:
1115: *mode_p = 0;
1116:
1117: /* Highlight mode line. */
1118: if (BriteMode) {
1119: #ifdef ID_CHAR
1120: if (IN_INSmode)
1121: INSmode(0);
1122: #endif
1123: #ifdef TERMCAP
1124: putpad(SO, 1);
1125: #else
1126: SO_on();
1127: #endif /* TERMCAP */
1128: }
1129: if (swrite(line, BriteMode, YES))
1130: do_cl_eol(i_line);
1131: else
1132: UpdModLine = 1;
1133: if (BriteMode)
1134: #ifdef TERMCAP
1135: putpad(SE, 1);
1136: #else
1137: SO_off();
1138: #endif /* TERMCAP */
1139: }
1140:
1141: /* This tries to place the current line of the current window in the
1142: center of the window, OR to place it at the arg'th line of the window.
1143: This also causes the horizontal position of the line to be centered,
1144: if the line needs scrolling, or moved all the way back to the left,
1145: if that's possible. */
1146: void
1147: RedrawDisplay()
1148: {
1149: int line;
1150: Line *newtop = prev_line((curwind->w_line = curline), is_an_arg() ?
1151: arg_value() : HALF(curwind));
1152:
1153: if ((line = in_window(curwind, curwind->w_line)) != -1)
1154: PhysScreen[line].s_offset = -1;
1155: if (newtop == curwind->w_top)
1156: v_clear(FLine(curwind), FLine(curwind) + SIZE(curwind));
1157: else
1158: SetTop(curwind, newtop);
1159: }
1160:
1161: void
1162: v_clear(line1, line2)
1163: register int line1;
1164: {
1165: register struct scrimage *phys_p, *des_p;
1166:
1167: phys_p = &PhysScreen[line1];
1168: des_p = &DesiredScreen[line1];
1169:
1170: while (line1 <= line2) {
1171: i_set(line1, 0);
1172: cl_eol();
1173: phys_p->s_id = des_p->s_id = 0;
1174: phys_p += 1;
1175: des_p += 1;
1176: line1 += 1;
1177: }
1178: }
1179:
1180: void
1181: ClAndRedraw()
1182: {
1183: cl_scr(YES);
1184: }
1185:
1186: void
1187: NextPage()
1188: {
1189: Line *newline;
1190:
1191: if (Asking)
1192: return;
1193: if (arg_value() < 0) {
1194: negate_arg_value();
1195: PrevPage();
1196: return;
1197: }
1198: if (arg_type() == YES)
1199: UpScroll();
1200: else {
1201: if (in_window(curwind, curwind->w_bufp->b_last) != -1) {
1202: rbell();
1203: return;
1204: }
1205: newline = next_line(curwind->w_top, max(1, SIZE(curwind) - 1));
1206: SetTop(curwind, curwind->w_line = newline);
1207: if (curwind->w_bufp == curbuf)
1208: SetLine(newline);
1209: }
1210: }
1211:
1212: #ifdef MSDOS /* kg */
1213:
1214: void
1215: PageScrollUp()
1216: {
1217: int i, n;
1218:
1219: n = max(1, SIZE(curwind) - 1);
1220: for (i=0; i<n; i++) {
1221: UpScroll();
1222: redisplay();
1223: }
1224: }
1225:
1226: void
1227: PageScrollDown()
1228: {
1229: int i, n;
1230:
1231: n = max(1, SIZE(curwind) - 1);
1232: for (i=0; i<n; i++) {
1233: DownScroll();
1234: redisplay();
1235: }
1236: }
1237: #endif /* MSDOS */
1238:
1239: void
1240: PrevPage()
1241: {
1242: Line *newline;
1243:
1244: if (Asking)
1245: return;
1246: if (arg_value() < 0) {
1247: negate_arg_value();
1248: NextPage();
1249: return;
1250: }
1251: if (arg_type() == YES)
1252: DownScroll();
1253: else {
1254: newline = prev_line(curwind->w_top, max(1, SIZE(curwind) - 1));
1255: SetTop(curwind, curwind->w_line = newline);
1256: if (curwind->w_bufp == curbuf)
1257: SetLine(newline);
1258: }
1259: }
1260:
1261: void
1262: UpScroll()
1263: {
1264: SetTop(curwind, next_line(curwind->w_top, arg_value()));
1265: if ((curwind->w_bufp == curbuf) &&
1266: (in_window(curwind, curline) == -1))
1267: SetLine(curwind->w_top);
1268: }
1269:
1270: void
1271: DownScroll()
1272: {
1273: SetTop(curwind, prev_line(curwind->w_top, arg_value()));
1274: if ((curwind->w_bufp == curbuf) &&
1275: (in_window(curwind, curline) == -1))
1276: SetLine(curwind->w_top);
1277: }
1278:
1279: int VisBell = NO,
1280: RingBell = NO; /* So if we have a lot of errors ...
1281: ring the bell only ONCE */
1282: void
1283: rbell()
1284: {
1285: RingBell = YES;
1286: }
1287:
1288: /* Message prints the null terminated string onto the bottom line of the
1289: terminal. */
1290:
1291: void
1292: message(str)
1293: char *str;
1294: {
1295: if (InJoverc)
1296: return;
1297: UpdMesg = YES;
1298: errormsg = NO;
1299: if (str != mesgbuf)
1300: null_ncpy(mesgbuf, str, (sizeof mesgbuf) - 1);
1301: }
1302:
1303: /* End of Window */
1304:
1305: void
1306: Eow()
1307: {
1308: if (Asking)
1309: return;
1310: SetLine(next_line(curwind->w_top, SIZE(curwind) - 1 -
1311: min(SIZE(curwind) - 1, arg_value() - 1)));
1312: if (!is_an_arg())
1313: Eol();
1314: }
1315:
1316: /* Beginning of Window */
1317:
1318: void
1319: Bow()
1320: {
1321: if (Asking)
1322: return;
1323: SetLine(next_line(curwind->w_top, min(SIZE(curwind) - 1, arg_value() - 1)));
1324: }
1325:
1326: private int LineNo,
1327: last_col,
1328: DoAutoNL;
1329: private Window *old_wind; /* save the window we were in BEFORE
1330: before we were called, if UseBuffers
1331: is nonzero */
1332:
1333: int UseBuffers = FALSE;
1334: int TOabort = 0;
1335:
1336: /* This initializes the typeout. If send-typeout-to-buffers is set
1337: the buffer NAME is created (emptied if it already exists) and output
1338: goes to the buffer. Otherwise output is drawn on the screen and
1339: erased by TOstop() */
1340:
1341: void
1342: TOstart(name, auto_newline)
1343: char *name;
1344: {
1345: if (UseBuffers) {
1346: old_wind = curwind;
1347: pop_wind(name, YES, B_SCRATCH);
1348: } else
1349: DisabledRedisplay = YES;
1350: TOabort = LineNo = last_col = 0;
1351: DoAutoNL = auto_newline;
1352: }
1353:
1354: /* VARARGS1 */
1355:
1356: void
1357: Typeout(fmt, va_alist)
1358: char *fmt;
1359: va_dcl
1360: {
1361: if (TOabort)
1362: return;
1363:
1364: if (!UseBuffers && (LineNo == ILI - 1)) {
1365: register int c;
1366:
1367: LineNo = 0;
1368: last_col = 0;
1369: f_mess("--more--");
1370: if ((c = getchar()) != ' ') {
1371: TOabort = YES;
1372: if (c != AbortChar && c != RUBOUT)
1373: Ungetc(c);
1374: f_mess(NullStr);
1375: return;
1376: }
1377: f_mess(NullStr);
1378: }
1379:
1380: if (fmt) {
1381: extern int i_col;
1382: char string[132];
1383: va_list ap;
1384:
1385: va_start(ap);
1386: format(string, sizeof string, fmt, ap);
1387: va_end(ap);
1388: if (UseBuffers)
1389: ins_str(string, NO);
1390: else {
1391: i_set(LineNo, last_col);
1392: (void) swrite(string, NO, YES);
1393: last_col = i_col;
1394: }
1395: }
1396: if (!UseBuffers) {
1397: PhysScreen[LineNo].s_id = -1;
1398: if (fmt == 0 || DoAutoNL == YES) {
1399: cl_eol();
1400: flusho();
1401: LineNo += 1;
1402: last_col = 0;
1403: }
1404: } else if (fmt == 0 || DoAutoNL != 0)
1405: ins_str("\n", NO);
1406: }
1407:
1408: void
1409: TOstop()
1410: {
1411: int c;
1412:
1413: if (UseBuffers) {
1414: ToFirst();
1415: SetWind(old_wind);
1416: } else {
1417: if (TOabort) {
1418: DisabledRedisplay = NO;
1419: return;
1420: }
1421: if (last_col != 0)
1422: Typeout((char *) 0);
1423: Typeout("----------");
1424: cl_eol();
1425: flusho();
1426: c = getchar();
1427: if (c != ' ')
1428: Ungetc(c);
1429: DisabledRedisplay = NO;
1430: }
1431: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.