[comp.sources.unix] v14i069: Jove, an emacs variant, version 4.9, Part13/21

rsalz@bbn.com (Rich Salz) (04/28/88)

Submitted-by: Jonathan Payne <jpayne@cs.rochester.edu>
Posting-number: Volume 14, Issue 69
Archive-name: jove4.9/part13

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 13 (of 21)."
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f './disp.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./disp.c'\"
else
echo shar: Extracting \"'./disp.c'\" \(28346 characters\)
sed "s/^X//" >'./disp.c' <<'END_OF_FILE'
X/***************************************************************************
X * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
X * is provided to you without charge, and with no warranty.  You may give  *
X * away copies of JOVE, including sources, provided that this notice is    *
X * included in all the files.                                              *
X ***************************************************************************/
X
X#include "jove.h"
X#include "ctype.h"
X#include "termcap.h"
X
X
X#ifdef MAC
X#	include "mac.h"
X#else
X#	include <varargs.h>
X#	include <sys/stat.h>
X#endif
X
X#include <signal.h>
X
X#ifdef MAC
X#	undef private
X#	define private
X#endif
X
X#ifdef	LINT_ARGS
private void
X#ifdef ID_CHAR
X	DeTab(int, char *, char *, int, int),
X	DelChar(int, int, int),
X	InsChar(int, int, int, char *),
X#endif
X	DoIDline(int),
X	do_cl_eol(int),
X	ModeLine(Window *),
X	mode_app(char *),
X	GotoDot(void),
X	UpdLine(int),
X	UpdWindow(Window *, int);
X
private int
X	AddLines(int, int),
X	DelLines(int, int),
X	UntilEqual(int);
X#else
private void
X#ifdef ID_CHAR
X	DeTab(),
X	DelChar(),
X	InsChar(),
X#endif
X	DoIDline(),
X	do_cl_eol(),
X	GotoDot(),
X	ModeLine(),
X	mode_app(),
X	UpdLine(),
X	UpdWindow();
private int
X	AddLines(),
X	DelLines(),
X	UntilEqual();
X#endif	/* LINT_ARGS */
X
X#ifdef MAC
X#	undef private
X#	define private static
X#endif
X
int	DisabledRedisplay = NO;
X
X/* Kludge windows gets called by the routines that delete lines from the
X   buffer.  If the w->w_line or w->w_top are deleted and this procedure
X   is not called, the redisplay routine will barf. */
X
void
ChkWindows(line1, line2)
Line	*line1;
register Line	*line2;
X{
X	register Window	*w = fwind;
X	register Line	*lp;
X
X	do {
X		for (lp = line1->l_next; lp != line2->l_next; lp = lp->l_next) {
X			if (lp == w->w_top)
X				w->w_flags |= W_TOPGONE;
X			if (lp == w->w_line)
X				w->w_flags |= W_CURGONE;
X		}
X		w = w->w_next;
X	} while (w != fwind);
X}
X
extern int	RingBell;
X
void
redisplay()
X{
X	extern int	AbortCnt;
X	register Window	*w = fwind;
X	int	lineno,
X		done_ID = NO,
X		i;
X	register struct scrimage	*des_p,
X					*phys_p;
X
X	if (DisabledRedisplay == YES)
X		return;
X	curwind->w_line = curwind->w_bufp->b_dot;
X	curwind->w_char = curwind->w_bufp->b_char;
X#ifdef MAC
X	InputPending = 0;
X#else	
X	if (InputPending = charp())	/* calls CheckEvent, which could */
X		return;	/* result in a call to rediplay(). We don't want that. */
X#endif
X#ifdef JOB_CONTROL
X	if (UpdFreq)
X		sighold(SIGALRM);
X#endif
X	if (RingBell) {
X		dobell(1);
X		RingBell = 0;
X	}
X	AbortCnt = BufSize;		/* initialize this now */
X	if (UpdMesg)
X		DrawMesg(YES);
X
X	for (lineno = 0, w = fwind; lineno < ILI; w = w->w_next) {
X		UpdWindow(w, lineno);
X		lineno += w->w_height;
X	}
X
X	UpdModLine = 0;	/* Now that we've called update window, we can
X			   assume that the modeline will be updated.  But
X			   if while redrawing the modeline the user types
X			   a character, ModeLine() is free to set this on
X			   again so that the modeline will be fully drawn
X			   at the next redisplay. */
X
X	des_p = DesiredScreen;
X	phys_p = PhysScreen;
X	for (i = 0; i < ILI; i++, des_p++, phys_p++) {
X		if (!done_ID && (des_p->s_id != phys_p->s_id)) {
X			DoIDline(i);
X			done_ID = YES;
X		}
X		if ((des_p->s_flags & (DIRTY | L_MOD)) ||
X		    (des_p->s_id != phys_p->s_id) ||
X		    (des_p->s_vln != phys_p->s_vln) ||
X		    (des_p->s_offset != phys_p->s_offset))
X			UpdLine(i);
X		if (InputPending)
X			goto ret;
X	}
X
X
X	if (Asking) {
X		Placur(LI - 1, min(CO - 2, calc_pos(mesgbuf, Asking)));
X			/* Nice kludge */
X		flusho();
X	} else
X		GotoDot();
ret:
X#ifdef JOB_CONTROL
X	if (UpdFreq)
X		sigrelse(SIGALRM);
X#else
X	;	/* yuck */
X#endif
X#ifdef MAC
X	if(Windchange) docontrols();
X#endif /* MAC */
X}
X
X#ifndef IBMPC
private void
dobell(n)
X{
X	while (--n >= 0) {
X#ifndef MAC
X		if (VisBell && VB)
X			putstr(VB);
X		else
X			putpad(BL, 1);
X#else
X		SysBeep(5);
X#endif
X	}
X	flusho();
X}
X#endif /* IBMPC */
X
X/* find_pos() returns the position on the line, that C_CHAR represents
X   in LINE */
X
int
find_pos(line, c_char)
Line	*line;
X{
X	return calc_pos(lcontents(line), c_char);
X}
X
int
calc_pos(lp, c_char)
register char	*lp;
register int	c_char;
X{
X	register int	pos = 0;
X	register int	c;
X
X
X	while ((--c_char >= 0) && ((c = *lp++) & CHARMASK) != 0) {
X		if (c == '\t')
X			pos += (tabstop - (pos % tabstop));
X		else if (isctrl(c))
X			pos += 2;
X		else
X			pos += 1;
X 	}
X	return pos;
X}
X
int	UpdModLine = 0,
X	UpdMesg = 0,
X	CanScroll = 0;
X
private void
DoIDline(start)
X{
X	register struct scrimage	*des_p = &DesiredScreen[start];
X	struct scrimage	*phys_p = &PhysScreen[start];
X	register int	i,
X			j;
X
X	/* Some changes have been made.  Try for insert or delete lines.
X	   If either case has happened, Addlines and/or DelLines will do
X	   necessary scrolling, also CONVERTING PhysScreen to account for the
X	   physical changes.  The comparison continues from where the
X	   insertion/deletion takes place; this doesn't happen very often,
X	   usually it happens with more than one window with the same
X	   buffer. */
X
X	if (!CanScroll)
X		return;		/* We should never have been called! */
X
X	for (i = start; i < ILI; i++, des_p++, phys_p++)
X		if (des_p->s_id != phys_p->s_id)
X			break;
X
X	for (; i < ILI; i++) {
X		for (j = i + 1; j < ILI; j++) {
X			des_p = &DesiredScreen[j];
X			phys_p = &PhysScreen[j];
X			if (des_p->s_id != 0 && des_p->s_id == phys_p->s_id)
X				break;
X			if (des_p->s_id == PhysScreen[i].s_id) {
X				if (des_p->s_id == 0)
X					continue;
X				if (AddLines(i, j - i)) {
X					DoIDline(j);
X					return;
X				}
X				break;
X			}
X			if ((des_p = &DesiredScreen[i])->s_id == phys_p->s_id) {
X				if (des_p->s_id == 0)
X					continue;
X				if (DelLines(i, j - i)) {
X					DoIDline(i);
X					return;
X				}
X				break;
X			}
X		}
X	}
X}
X
X/* Make DesiredScreen reflect what the screen should look like when we are done
X   with the redisplay.  This deals with horizontal scrolling.  Also makes
X   sure the current line of the Window is in the window. */
X
int	ScrollAll = NO;
X
private void
UpdWindow(w, start)
register Window	*w;
X{
X	Line	*lp;
X	int	i,
X		upper,		/* top of window */
X		lower,		/* bottom of window */
X		strt_col,	/* starting print column of current line */
X		ntries = 0;	/* # of tries at updating window */
X	register struct scrimage	*des_p,
X					*phys_p;
X	Buffer	*bp = w->w_bufp;
X
retry:
X	if (w->w_flags & W_CURGONE) {
X		w->w_line = bp->b_dot;
X		w->w_char = bp->b_char;
X	}
X	if (w->w_flags & W_TOPGONE)
X		CentWind(w);	/* reset topline of screen */
X	w->w_flags &= ~(W_CURGONE | W_TOPGONE);
X
X	/* make sure that the current line is in the window */
X	upper = start;
X	lower = upper + w->w_height - 1;	/* don't include modeline */
X	for (i = upper, lp = w->w_top; i < lower && lp != 0; lp = lp->l_next, i++)
X		if (lp == w->w_line)
X			break;
X	if (i == lower || lp == 0) {
X		ntries += 1;
X		if (ntries == 1) {
X			CalcWind(w);
X			goto retry;
X		} else if (ntries == 2) {
X			w->w_top = w->w_line = w->w_bufp->b_first;
X			printf("\rERROR in redisplay: I got hopelessly lost!");
X			dobell(2);
X			goto retry;
X		} else if (ntries == 3) {
X			printf("\n\rOops, still lost, quitting ...\r\n");
X			finish(1);
X		}
X	}
X
X	/* first do some calculations for the current line */
X	{
X		int	diff = (w->w_flags & W_NUMLINES) ? 8 : 0,
X			end_col;
X
X		strt_col = (ScrollAll == YES) ? w->w_LRscroll :
X			   PhysScreen[i].s_offset;
X		end_col = strt_col + (CO - 2) - diff;
X		/* Right now we are displaying from strt_col to
X		   end_col of the buffer line.  These are PRINT
X		   columns, not actual characters. */
X		w->w_dotcol = find_pos(w->w_line, w->w_char);
X		/* if the new dotcol is out of range, reselect
X		   a horizontal window */
X		if ((PhysScreen[i].s_offset == -1) ||
X		    (w->w_dotcol < strt_col) ||
X		    (w->w_dotcol >= end_col)) {
X			if (w->w_dotcol < ((CO - 2) - diff))
X				strt_col = 0;
X			else
X				strt_col = w->w_dotcol - (CO / 2);
X			if (ScrollAll == YES) {
X				if (w->w_LRscroll != strt_col)
X					UpdModLine = YES;
X				w->w_LRscroll = strt_col;
X			}
X		}
X		w->w_dotline = i;
X		w->w_dotcol += diff;
X	}
X
X	des_p = &DesiredScreen[upper];
X	phys_p = &PhysScreen[upper];
X	for (i = upper, lp = w->w_top; lp != 0 && i < lower; i++, des_p++, phys_p++, lp = lp->l_next) {
X		des_p->s_window = w;
X		des_p->s_lp = lp;
X		des_p->s_id = lp->l_dline & ~DIRTY;
X		des_p->s_flags = isdirty(lp) ? L_MOD : 0;
X		if (w->w_flags & W_NUMLINES)
X			des_p->s_vln = w->w_topnum + (i - upper);
X		else
X			des_p->s_vln = 0;
X
X		if (lp == w->w_line)
X			des_p->s_offset = strt_col;
X		else
X			des_p->s_offset = w->w_LRscroll;
X	}
X
X	/* Is structure assignment faster than copy each field separately? */
X	if (i < lower) {
X		static struct scrimage	dirty_plate = { 0, DIRTY, 0, 0, 0, 0 },
X					clean_plate = { 0, 0, 0, 0, 0, 0 };
X
X		for (; i < lower; i++, des_p++, phys_p++)
X			if (phys_p->s_id != 0)
X				*des_p = dirty_plate;
X			else
X				*des_p = clean_plate;
X	}
X
X	des_p->s_window = w;
X	des_p->s_flags = 0;
X	if (((des_p->s_id = (int) w->w_bufp) != phys_p->s_id) || UpdModLine)
X		des_p->s_flags = MODELINE | DIRTY;
X#ifdef MAC
X	if(UpdModLine) Modechange = 1;
X	if(w == curwind && w->w_control) SetScrollBar(w->w_control);
X#endif
X}
X
X/* Write whatever is in mesgbuf (maybe we are Asking, or just printed
X   a message).  Turns off the UpdateMesg line flag. */
X
void
DrawMesg(abortable)
X{
X#ifndef MAC		/* same reason as in redisplay() */
X	if (charp())
X		return;
X#endif
X	i_set(ILI, 0);
X	if (swrite(mesgbuf, NO, abortable)) {
X		cl_eol();
X		UpdMesg = 0;
X	}
X	flusho();
X}
X
X/* Goto the current position in the current window.  Presumably redisplay()
X   has already been called, and curwind->{w_dotline,w_dotcol} have been set
X   correctly. */
X
private void
GotoDot()
X{
X	if (InputPending)
X		return;
X	Placur(curwind->w_dotline, curwind->w_dotcol -
X				PhysScreen[curwind->w_dotline].s_offset);
X	flusho();
X}
X
private int
UntilEqual(start)
register int	start;
X{
X	register struct scrimage	*des_p = &DesiredScreen[start],
X					*phys_p = &PhysScreen[start];
X
X	while ((start < ILI) && (des_p->s_id != phys_p->s_id)) {
X		des_p += 1;
X		phys_p += 1;
X		start += 1;
X	}
X
X	return start;
X}
X
X/* Calls the routine to do the physical changes, and changes PhysScreen to
X   reflect those changes. */
X
private int
AddLines(at, num)
register int	at,
X		num;
X{
X	register int	i;
X	int	bottom = UntilEqual(at + num);
X
X	if (num == 0 || num >= ((bottom - 1) - at))
X		return NO;				/* we did nothing */
X	v_ins_line(num, at, bottom - 1);
X
X	/* Now change PhysScreen to account for the physical change. */
X
X	for (i = bottom - 1; i - num >= at; i--)
X		PhysScreen[i] = PhysScreen[i - num];
X	for (i = 0; i < num; i++)
X		PhysScreen[at + i].s_id = 0;
X	return YES;					/* we did something */
X}
X
private int
DelLines(at, num)
register int	at,
X		num;
X{
X	register int	i;
X	int	bottom = UntilEqual(at + num);
X
X	if (num == 0 || num >= ((bottom - 1) - at))
X		return NO;
X	v_del_line(num, at, bottom - 1);
X
X	for (i = at; num + i < bottom; i++)
X		PhysScreen[i] = PhysScreen[num + i];
X	for (i = bottom - num; i < bottom; i++)
X		PhysScreen[i].s_id = 0;
X	return YES;
X}
X
X/* Update line linenum in window w.  Only set PhysScreen to DesiredScreen
X   if the swrite or cl_eol works, that is nothing is interupted by 
X   characters typed. */ 
X
private void
UpdLine(linenum)
register int	linenum;
X{
X	register struct scrimage	*des_p = &DesiredScreen[linenum];
X	register Window	*w = des_p->s_window;
X
X	i_set(linenum, 0);
X	if (des_p->s_flags & MODELINE)
X		ModeLine(w);
X	else if (des_p->s_id) {
X		des_p->s_lp->l_dline &= ~DIRTY;
X		des_p->s_flags &= ~(DIRTY | L_MOD);
X#ifdef ID_CHAR
X		if (!UseIC && (w->w_flags & W_NUMLINES))
X#else
X		if (w->w_flags & W_NUMLINES)
X#endif
X			(void) swrite(sprint("%6d  ", des_p->s_vln), NO, YES);
X
X#ifdef ID_CHAR
X		if (UseIC) {
X			char	outbuf[MAXCOLS],
X				*lptr;
X			int	fromcol = (w->w_flags & W_NUMLINES) ? 8 : 0;
X
X			if (w->w_flags & W_NUMLINES)
X				sprintf(outbuf, "%6d  ", des_p->s_vln);
X			lptr = lcontents(des_p->s_lp);
X			DeTab(des_p->s_offset, lptr, outbuf + fromcol,
X				(sizeof outbuf) - 1 - fromcol,
X				des_p->s_window->w_flags & W_VISSPACE);
X			if (IDchar(outbuf, linenum, 0))
X				PhysScreen[linenum] = *des_p;
X			else if (i_set(linenum, 0), swrite(outbuf, NO, YES))
X				do_cl_eol(linenum);
X			else
X				PhysScreen[linenum].s_id = -1;
X		} else
X#endif /* ID_CHAR */
X		    if (BufSwrite(linenum))
X			do_cl_eol(linenum);
X		else
X			PhysScreen[linenum].s_id = -1;
X	} else if (PhysScreen[linenum].s_id)	/* not the same ... make sure */
X		do_cl_eol(linenum);
X}
X
private void
do_cl_eol(linenum)
register int	linenum;
X{
X	cl_eol();
X	PhysScreen[linenum] = DesiredScreen[linenum];
X}
X
X#ifdef ID_CHAR
X
X/* From here to the end of the file is code that tries to utilize the
X   insert/delete character feature on some terminals.  It is very confusing
X   and not so well written code, AND there is a lot of it.  You may want
X   to use the space for something else. */
X
extern struct screenline	*Screen;
int	IN_INSmode = 0;
X
int	UseIC;
X
int	DClen,
X	MDClen,
X	IClen,
X	MIClen,
X	IMlen,
X	CElen;
X
void
disp_opt_init()
X{
X	DClen = DC ? strlen(DC) : 0;
X	MDClen = M_DC ? strlen(M_DC) : 9999;
X	IClen = IC ? strlen(IC) : 0;
X	MIClen = M_IC ? strlen(M_IC) : 9999;
X	IMlen = IM ? strlen(IM) : 0;
X	CElen = CE ? strlen(CE) : 0;
X
X	UseIC = (IC || IM || M_IC);
X}
X
void
INSmode(on)
X{
X	if (on && !IN_INSmode) {
X		putpad(IM, 1);
X		IN_INSmode = YES;
X	} else if (!on && IN_INSmode) {
X		putpad(EI, 1);
X		IN_INSmode = NO;
X	}
X}
X
private void
DeTab(s_offset, buf, outbuf, limit, visspace)
register char	*buf;
char	*outbuf;
X{
X	register char	*phys_p = outbuf,
X			c;
X	register int	pos = 0;
X	char		*limitp = &outbuf[limit];
X
X#define OkayOut(ch)	if ((pos++ >= s_offset) && (phys_p < limitp))\
X				*phys_p++ = ch;\
X			else
X
X	while (c = *buf++) {
X		if (c == '\t') {
X			int	nchars = (tabstop - (pos % tabstop));
X
X			if (visspace) {
X				OkayOut('>');
X				nchars -= 1;
X			}
X			while (--nchars >= 0)
X				OkayOut(' ');
X
X		} else if (isctrl(c)) {
X			OkayOut('^');
X			OkayOut(c == 0177 ? '?' : c + '@');
X		} else {
X			if (visspace && c == ' ')
X				c = '_';
X			OkayOut(c);
X		}
X		if (pos - s_offset >= CO) {
X			phys_p = &outbuf[CO - 1];
X			*phys_p++ = '!';
X			break;
X		}			
X	}
X	*phys_p = 0;
X}
X
X/* ID character routines full of special cases and other fun stuff like that.
X   It actually works though ... 
X
X  	Returns Non-Zero if you are finished (no differences left). */
X
private int
IDchar(new, lineno, col)
register char	*new;
X{
X	register int	i;
X	int	j,
X		oldlen,
X		NumSaved;
X	register struct screenline	*sline = &Screen[lineno];
X
X	oldlen = sline->s_length - sline->s_line;
X
X	for (i = col; i < oldlen && new[i] != 0; i++)
X		if (sline->s_line[i] != new[i])
X			break;
X	if (new[i] == 0 || i == oldlen)
X		return (new[i] == 0 && i == oldlen);
X
X	for (j = i + 1; j < oldlen && new[j]; j++) {
X		if (new[j] == sline->s_line[i]) {
X			NumSaved = IDcomp(new + j, sline->s_line + i,
X					strlen(new)) + NumSimilar(new + i,
X						sline->s_line + i, j - i);
X			if (OkayInsert(NumSaved, j - i)) {
X				InsChar(lineno, i, j - i, new);
X				return(IDchar(new, lineno, j));
X			}
X		}
X	}
X
X	for (j = i + 1; j < oldlen && new[i]; j++) {
X		if (new[i] == sline->s_line[j]) {
X			NumSaved = IDcomp(new + i, sline->s_line + j,
X					oldlen - j);
X			if (OkayDelete(NumSaved, j - i, new[oldlen] == 0)) {
X				DelChar(lineno, i, j - i);
X				return(IDchar(new, lineno, j));
X			}
X		}
X	}
X	return 0;
X}
X
private int
NumSimilar(s, t, n)
register char	*s,
X		*t;
X{
X	register int	num = 0;
X
X	while (n--)
X		if (*s++ == *t++)
X			num += 1;
X	return num;
X}
X
private int
IDcomp(s, t, len)
register char	*s,
X		*t;
X{
X	register int	i;
X	int	num = 0,
X		nonspace = 0;
X	char	c;
X
X	for (i = 0; i < len; i++) {
X		if ((c = *s++) != *t++)
X			break;
X		if (c != ' ')
X			nonspace++;
X		if (nonspace)
X			num += 1;
X	}
X
X	return num;
X}
X
private int
OkayDelete(Saved, num, samelength)
X{
X	/* If the old and the new are the same length, then we don't
X	 * have to clear to end of line.  We take that into consideration.
X	 */
X	return ((Saved + (!samelength ? CElen : 0))
X		> min(MDClen, DClen * num));
X}
X
private int
OkayInsert(Saved, num)
X{
X	register int	n = 0;
X
X	if (IC)		/* Per character prefixes */
X		n = min(num * IClen, MIClen);
X
X	if (IM && !IN_INSmode) {	
X		/* Good terminal.  Fewer characters in this case */
X		n += IMlen;
X	}
X
X	n += num;	/* The characters themselves */
X
X	return Saved > n;
X}
X
extern int	CapCol;
extern char	*cursend;
extern struct screenline	*Curline;
X
private void
DelChar(lineno, col, num)
X{
X	register char	*from,
X			*to;
X	register int	i;
X	struct screenline *sp = (&Screen[lineno]);
X
X	Placur(lineno, col);
X	if (M_DC && num > 1) {
X		char	minibuf[16];
X
X		sprintf(minibuf, M_DC, num);
X		putpad(minibuf, num);
X	} else {
X		for (i = num; --i >= 0; )
X			putpad(DC, 1);
X	}
X
X	to = sp->s_line + col;
X	from = to + num;
X
X	byte_copy(from, to, sp->s_length - from + 1);
X	clrline(sp->s_length - num, sp->s_length);
X	sp->s_length -= num;
X}
X
private void
InsChar(lineno, col, num, new)
char	*new;
X{
X	register char	*sp1,
X			*sp2,	/* To push over the array. */
X			*sp3;	/* Last character to push over. */
X	int	i;
X
X	i_set(lineno, 0);
X	sp2 = Curline->s_length + num;
X
X	if (sp2 >= cursend) {
X		i_set(lineno, CO - num - 1);
X		cl_eol();
X		sp2 = cursend - 1;
X	}
X	Curline->s_length = sp2;
X	sp1 = sp2 - num;
X	sp3 = Curline->s_line + col;
X
X	while (sp1 >= sp3)
X		*sp2-- = *sp1--;
X
X	new += col;
X	byte_copy(new, sp3, num);
X	/* The internal screen is correct, and now we have to do
X	   the physical stuff. */
X
X	Placur(lineno, col);
X	if (IM) {
X		if (!IN_INSmode)
X			INSmode(1);
X	} else if (M_IC && num > 1) {
X		char	minibuf[16];
X
X		sprintf(minibuf, M_IC, num);
X		putpad(minibuf, num);
X	} else if (IC) {
X		for (i = 0; i < num; i++)
X			putpad(IC, 1);
X	}
X	for (i = 0; i < num; i++) {
X		putchar(new[i]);
X		if (IN_INSmode)
X			putpad(IP, 1);
X	}
X	CapCol += num;
X}
X
X#endif /* ID_CHAR */
X
X#ifdef UNIX		/* obviously ... no mail today if not Unix*/
X
X/* chkmail() returns nonzero if there is new mail since the
X   last time we checked. */
X
char	Mailbox[FILESIZE];	/* initialized in main */
int	MailInt = 60;	/* check no more often than 60 seconds */
X#ifdef BIFF
int	BiffChk = NO;	/* whether or not to turn off biff while in JOVE */
X#endif
X
int
chkmail(force)
X{
X	time_t	now;
X	static time_t	last_chk = 0;
X	static int	value = FALSE;
X	static off_t	last_size = 0;
X	struct stat	stbuf;
X	int	last_val;
X	static time_t	last_time = 0;
X
X	time(&now);
X	if (!force && (now < last_chk + MailInt))
X		return value;
X	last_chk = now;
X	if (force)
X		last_time = now;
X	if (stat(Mailbox, &stbuf) < 0) {
X		value = FALSE;
X		return FALSE;
X	}
X	last_val = value;
X	value = ((stbuf.st_mtime > last_time) &&
X		 (stbuf.st_size > 0) &&
X		 (stbuf.st_size >= last_size) &&
X		 (stbuf.st_mtime + 5 > stbuf.st_atime));
X	if (value == TRUE &&
X		      ((value != last_val) || (stbuf.st_size != last_size)))
X		dobell(3);
X	if (stbuf.st_size < last_size)
X		last_time = now;
X	last_size = stbuf.st_size;
X	return value;
X}
X
X#endif /* UNIX */
X
X/* Print the mode line. */
X
private char	*mode_p,
X		*mend_p;
int	BriteMode = 1;		/* modeline should standout */
X
private void
mode_app(str)
register char	*str;
X{
X	if (mode_p >= mend_p)
X		return;
X	while ((mode_p < mend_p) && (*mode_p++ = *str++))
X		;
X	mode_p -= 1;	/* back over the null */
X}
X
char	ModeFmt[120] = "%3c %w %[%sJOVE (%M)   Buffer: %b  \"%f\" %]%s%m*- %((%t)%s%)%e";
X
private void
ModeLine(w)
register Window	*w;
X{
X	extern int	i_line;
X	extern char	*pwd();
X	int	n,
X		ign_some = NO;
X	char	line[MAXCOLS],
X		*fmt = ModeFmt,
X		fillc,
X		c;
X	register Buffer	*thisbuf = w->w_bufp;
X	register Buffer *bp;
X
X	mode_p = line;
X	mend_p = &line[(sizeof line) - 1];
X
X#if defined(UNIX) || (defined (MSDOS) && !defined(IBMPC))
X	if (BriteMode != 0 && SO == 0)
X		BriteMode = 0;
X	fillc = BriteMode ? ' ' : '-';
X#endif /* UNIX */
X#ifdef IBMPC		/* very subtle - don't mess up attributes too much */
X	fillc = '-'; /*BriteMode ? ' ' : '-';*/
X#endif /* IBMPC */
X#ifdef MAC
X	fillc = '_';	/* looks better on a Mac */
X#endif /* MAC */
X
X	while (c = *fmt++) {
X		if (c != '%') {
X			if (c == '\\')
X				if ((c = *fmt++) == '\0')
X					break;
X			if (!ign_some)
X				*mode_p++ = c;
X			continue;
X		}
X		if ((c = *fmt++) == '\0')	/* char after the '%' */
X			break;
X		if (ign_some && c != ')')
X			continue;
X		n = 1;
X		if (c >= '0' && c <= '9') {
X			n = 0;
X			while (c >= '0' && c <= '9') {
X				n = n * 10 + (c - '0');
X				c = *fmt++;
X			}
X		}
X		switch (c) {
X		case '(':
X			if (w->w_next != fwind)	/* Not bottom window. */
X				ign_some = YES;
X			break;
X
X		case ')':
X			ign_some = NO;
X			break;
X
X		case '[':
X		case ']':
X		    {
X		    	char	*strs = (c == '[') ? "[[[[[[[[[[" : "]]]]]]]]]]";
X
X		    	mode_app(strs + 10 - RecDepth);
X			break;
X		    }
X			
X#ifdef UNIX
X		case 'C':	/* check mail here */
X			if (chkmail(NO))
X				mode_app("[New mail]");
X			break;
X
X#endif /* UNIX */
X
X		case 'M':
X		    {
X		    	static char	*mmodes[] = {
X				"Fundamental ",
X				"Text ",
X				"C ",
X#ifdef LISP
X				"Lisp ",
X#endif
X				0
X			};
X
X		    	mode_app(mmodes[thisbuf->b_major]);
X
X			if (BufMinorMode(thisbuf, Fill))
X				mode_app("Fill ");
X			if (BufMinorMode(thisbuf, Abbrev))
X				mode_app("Abbrev ");
X			if (BufMinorMode(thisbuf, OverWrite))
X				mode_app("OvrWt ");
X			if (BufMinorMode(thisbuf, Indent))
X				mode_app("AI ");
X			if (InMacDefine)
X				mode_app("Def ");
X			mode_p -= 1;	/* Back over the extra space. */
X			break;
X		    }
X
X		case 'c':
X			while (--n >= 0)
X				*mode_p++ = fillc;
X			break;
X
X#ifdef CHDIR
X		case 'd':	/* print working directory */
X			mode_app(pr_name(pwd(), YES));
X			break;
X#endif
X			
X		case 'e':
X		    {
X			/* 2 space pad pluss padding for magic cookies */
X			char	*last_p = &line[CO - 2 - (2 * SG)];
X
X			while (mode_p < last_p)
X				*mode_p++ = fillc;
X
X		    	goto outahere;		/* %e means we're done! */
X		    }
X
X		case 'b':
X			mode_app(thisbuf->b_name);
X			break;
X
X		case 'f':
X		case 'F':
X			if (thisbuf->b_fname == 0)
X				mode_app("[No file]");
X			else {
X				if (c == 'f')
X					mode_app(pr_name(thisbuf->b_fname, YES));
X				else
X					mode_app(basename(thisbuf->b_fname));
X			}
X			break;
X
X#ifdef LOAD_AV
X		case 'l':
X		    {
X			double	theavg;
X		    	char	minibuf[10];
X
X		    	get_la(&theavg);
X		    	theavg += .005;	/* round to nearest .01 */
X		    	sprintf(minibuf, "%d.%02d",
X			       (int) theavg,
X			       (int)((theavg - (int) theavg) * 100));
X		    	mode_app(minibuf);
X			break;
X		    }
X#endif
X
X		case 'm':
X			if (IsModified(w->w_bufp))
X				*mode_p++ = fmt[0];
X			else
X				*mode_p++ = fmt[1];
X			fmt += 2;	/* skip two characters */
X			break;
X
X		case 'n':
X		    {
X			char	tmp[16];
X			for (bp = world, n = 1; bp != 0; bp = bp->b_next, n++)
X				if (bp == thisbuf)
X					break;
X
X			sprintf(tmp, "%d", n);
X			mode_app(tmp);
X			break;
X		    }
X
X#ifdef IPROCS
X		case 'p':
X		    if (thisbuf->b_type == B_PROCESS) {
X			char	tmp[40];
X
X			sprintf(tmp, "(%s)", (thisbuf->b_process == 0) ?
X					     "No process" :
X					     pstate(thisbuf->b_process));
X			mode_app(tmp);
X			break;
X		    }
X#endif
X
X		case 's':
X			if (mode_p[-1] == ' ')
X				continue;
X			*mode_p++ = ' ';
X			break;
X
X		case 't':
X		    {
X			char	timestr[12];
X
X		    	mode_app(get_time((time_t *) 0, timestr, 11, 16));
X			break;
X		    }
X
X		case 'w':
X			if (w->w_LRscroll > 0) 
X				mode_app(">");
X		}
X	}
X
outahere:
X	*mode_p = 0;
X
X	/* Highlight mode line. */
X	if (BriteMode) {
X#ifdef ID_CHAR
X		if (IN_INSmode)
X			INSmode(0);
X#endif
X#ifdef TERMCAP
X		putpad(SO, 1);
X#else 
X		SO_on();
X#endif /* TERMCAP */
X	}
X	if (swrite(line, BriteMode, YES))
X		do_cl_eol(i_line);
X	else
X		UpdModLine = 1;
X	if (BriteMode)
X#ifdef TERMCAP
X		putpad(SE, 1);
X#else 
X		SO_off();
X#endif /* TERMCAP */
X}
X
X/* This tries to place the current line of the current window in the
X   center of the window, OR to place it at the arg'th line of the window.
X   This also causes the horizontal position of the line to be centered,
X   if the line needs scrolling, or moved all the way back to the left,
X   if that's possible. */
void
RedrawDisplay()
X{
X	int	line;
X	Line	*newtop = prev_line((curwind->w_line = curline), is_an_arg() ?
X				arg_value() : HALF(curwind));
X
X	if ((line = in_window(curwind, curwind->w_line)) != -1)
X		PhysScreen[line].s_offset = -1;
X	if (newtop == curwind->w_top)
X		v_clear(FLine(curwind), FLine(curwind) + SIZE(curwind));
X	else
X		SetTop(curwind, newtop);
X}
X
void
v_clear(line1, line2)
register int	line1;
X{
X	register struct scrimage	*phys_p, *des_p;
X
X	phys_p = &PhysScreen[line1];
X	des_p = &DesiredScreen[line1];
X
X	while (line1 <= line2) {
X		i_set(line1, 0);
X		cl_eol();
X		phys_p->s_id = des_p->s_id = 0;
X		phys_p += 1;
X 		des_p += 1;
X		line1 += 1;
X	}
X}
X
void
ClAndRedraw()
X{
X	cl_scr(YES);
X}
X
void
NextPage()
X{
X	Line	*newline;
X
X	if (Asking)
X		return;
X	if (arg_value() < 0) {
X		negate_arg_value();
X		PrevPage();
X		return;
X	}
X	if (arg_type() == YES)
X		UpScroll();
X	else {
X		if (in_window(curwind, curwind->w_bufp->b_last) != -1) {
X			rbell();
X			return;
X		}
X		newline = next_line(curwind->w_top, max(1, SIZE(curwind) - 1));
X		SetTop(curwind, curwind->w_line = newline);
X		if (curwind->w_bufp == curbuf)
X			SetLine(newline);
X	}
X}
X
X#ifdef MSDOS		/* kg */
X
void
PageScrollUp()
X{
X	int i, n;
X
X    n = max(1, SIZE(curwind) - 1);
X	for (i=0; i<n; i++) {
X	    UpScroll();
X	    redisplay();
X	}
X}
X
void
PageScrollDown()
X{
X   	int i, n;
X
X	n = max(1, SIZE(curwind) - 1);
X	for (i=0; i<n; i++) {
X	    DownScroll();
X	    redisplay();
X	}
X}
X#endif /* MSDOS */
X
void
PrevPage()
X{
X	Line	*newline;
X
X	if (Asking)
X		return;
X	if (arg_value() < 0) {
X		negate_arg_value();
X		NextPage();
X		return;
X	}
X	if (arg_type() == YES)
X		DownScroll();
X	else {
X		newline = prev_line(curwind->w_top, max(1, SIZE(curwind) - 1));
X		SetTop(curwind, curwind->w_line = newline);
X		if (curwind->w_bufp == curbuf)
X			SetLine(newline);
X	}
X}
X
void
UpScroll()
X{
X	SetTop(curwind, next_line(curwind->w_top, arg_value()));
X	if ((curwind->w_bufp == curbuf) &&
X	    (in_window(curwind, curline) == -1))
X		SetLine(curwind->w_top);
X}
X
void
DownScroll()
X{
X	SetTop(curwind, prev_line(curwind->w_top, arg_value()));
X	if ((curwind->w_bufp == curbuf) &&
X	    (in_window(curwind, curline) == -1))
X		SetLine(curwind->w_top);
X}
X
int	VisBell = NO,
X	RingBell = NO;	/* So if we have a lot of errors ...
X			   ring the bell only ONCE */
void
rbell()
X{
X	RingBell = YES;
X}
X
X/* Message prints the null terminated string onto the bottom line of the
X   terminal. */
X
void
message(str)
char	*str;
X{
X	if (InJoverc)
X		return;
X	UpdMesg = YES;
X	errormsg = NO;
X	if (str != mesgbuf)
X		null_ncpy(mesgbuf, str, (sizeof mesgbuf) - 1);
X}
X
X/* End of Window */
X
void
Eow()
X{
X	if (Asking)
X		return;
X	SetLine(next_line(curwind->w_top, SIZE(curwind) - 1 -
X			min(SIZE(curwind) - 1, arg_value() - 1)));
X	if (!is_an_arg())
X		Eol();
X}
X
X/* Beginning of Window */
X
void
Bow()
X{
X	if (Asking)
X		return;
X	SetLine(next_line(curwind->w_top, min(SIZE(curwind) - 1, arg_value() - 1)));
X}
X
private int	LineNo,
X		last_col,
X		DoAutoNL;
private Window	*old_wind;	/* save the window we were in BEFORE
X				   before we were called, if UseBuffers
X				   is nonzero */
X
int	UseBuffers = FALSE;
int	TOabort = 0;
X
X/* This initializes the typeout.  If send-typeout-to-buffers is set
X   the buffer NAME is created (emptied if it already exists) and output
X   goes to the buffer.  Otherwise output is drawn on the screen and
X   erased by TOstop() */
X
void
TOstart(name, auto_newline)
char	*name;
X{
X	if (UseBuffers) {
X		old_wind = curwind;
X		pop_wind(name, YES, B_SCRATCH);
X	} else
X		DisabledRedisplay = YES;
X	TOabort = LineNo = last_col = 0;
X	DoAutoNL = auto_newline;
X}
X
X/* VARARGS1 */
X
void
Typeout(fmt, va_alist)
char	*fmt;
va_dcl
X{
X	if (TOabort)
X		return;
X
X	if (!UseBuffers && (LineNo == ILI - 1)) {
X		register int	c;
X
X		LineNo = 0;
X		last_col = 0;
X		f_mess("--more--");
X		if ((c = getchar()) != ' ') {
X			TOabort = YES;
X			if (c != AbortChar && c != RUBOUT)
X				Ungetc(c);
X			f_mess(NullStr);
X			return;
X		}
X		f_mess(NullStr);
X	}
X
X	if (fmt) {
X		extern int	i_col;
X		char	string[132];
X		va_list	ap;
X
X		va_start(ap);
X		format(string, sizeof string, fmt, ap);
X		va_end(ap);
X		if (UseBuffers)
X			ins_str(string, NO);
X		else {
X			i_set(LineNo, last_col);
X			(void) swrite(string, NO, YES);
X			last_col = i_col;
X		}
X	}
X	if (!UseBuffers) {
X		PhysScreen[LineNo].s_id = -1;
X		if (fmt == 0 || DoAutoNL == YES) {
X			cl_eol();
X			flusho();
X			LineNo += 1;
X			last_col = 0;
X		}
X	} else if (fmt == 0 || DoAutoNL != 0)
X		ins_str("\n", NO);
X}
X
void
TOstop()
X{
X	int	c;
X
X	if (UseBuffers) {
X		ToFirst();
X		SetWind(old_wind);
X	} else {
X		if (TOabort) {
X			DisabledRedisplay = NO;
X			return;
X		}
X		if (last_col != 0)
X			Typeout((char *) 0);
X  		Typeout("----------");
X		cl_eol();
X		flusho();
X		c = getchar();
X		if (c != ' ')
X			Ungetc(c);
X		DisabledRedisplay = NO;
X	}
X}
END_OF_FILE
if test 28346 -ne `wc -c <'./disp.c'`; then
    echo shar: \"'./disp.c'\" unpacked with wrong size!
fi
# end of './disp.c'
fi
echo shar: End of archive 13 \(of 21\).
cp /dev/null ark13isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 21 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.