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