[net.sources] Window source #4 [of 0-7]: display.c

chris@umcp-cs.UUCP (07/03/83)

: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
	all=TRUE
fi
/bin/echo 'Extracting display.c'
sed 's/^X//' <<'//go.sysin dd *' >display.c
X/* Copyright (c) 1983 University of Maryland Computer Science Department */
X
X/* Ultra-hot screen management package
X   Original code copyright (c) James Gosling, January 1980 */
X
X/* Severe munging and destruction by Chris Torek, 1982,1983 */
X
X/****************************************************************
X
X
X
X			 /-------------\
X			/		\
X		       /		 \
X		      /			  \
X		      |	  XXXX	   XXXX	  |
X		      |	  XXXX	   XXXX	  |
X		      |	  XXX	    XXX	  |
X		      \		X	  /
X		       --\     XXX     /--
X			| |    XXX    | |
X			| |	      | |
X			| I I I I I I I |
X			|  I I I I I I	|
X			 \	       /
X			  --	     --
X			    \-------/
X		    XXX			   XXX
X		   XXXXX		  XXXXX
X		   XXXXXXXXX	     XXXXXXXXXX
X			  XXXXX	  XXXXX
X			     XXXXXXX
X			  XXXXX	  XXXXX
X		   XXXXXXXXX	     XXXXXXXXXX
X		   XXXXX		  XXXXX
X		    XXX			   XXX
X
X			  **************
X			  *  BEWARE!!  *
X			  **************
X
X			All ye who enter here:
X		    Most of the code in this module
X		       is twisted beyond belief!
X
X			   Tread carefully.
X
X		    If you think you understand it,
X			      You Don't,
X			    So Look Again.
X
X ****************************************************************/
X
X/* DJH -- Added Ding() for bell */
X
X#include "win.h"
X#include "Trm.h"
X#include <stdio.h>
X#include <sgtty.h>
X
X#ifdef lint
X#undef	VAX		/* Don't let lint know about Vax dependent stuff */
X#endif
X
X/* the following macros are used to access terminal specific routines.
X   Really, no one outside of display.c should be using them, except for
X   the initialize/cleanup routines */
X#define topos (*W_tt.t_topos)
X#define reset (*W_tt.t_reset)
X#define INSmode (*W_tt.t_INSmode)
X#define insertlines (*W_tt.t_inslines)
X#define deletelines (*W_tt.t_dellines)
X#define blanks (*W_tt.t_blanks)
X#define wipeline (*W_tt.t_wipeline)
X#define wipescreen (*W_tt.t_wipescreen)
X#define deletechars (*W_tt.t_delchars)
X#define	ScreenWidth (W_tt.t_width)
X#define ScreenLength (W_tt.t_length)
X
X#define MScreenWidth 135
X#define MScreenLength 60
X#define min(a,b) (a<b ? a : b)
X#define max(a,b) (a>b ? a : b)
X#define hidden static
X#define visible
X#define procedure
X#define function
X
Xhidden struct line {		/* a line as it appears in a list of
X				   lines (as in the physical and virtual
X				   display lists) */
X    int     hash;		/* hash value for this line, 0 if not
X				   known */
X    struct line *next;		/* pointer to the next line in a list of
X				   lines */
X    short   DrawCost;		/* the cost of redrawing this line */
X    short   length;		/* the number of valid characters in the
X				   line */
X    short   touched;		/* true iff UpdateLine should be done */
X    Ch      body[MScreenWidth];	/* the actual text of the line */
X}
X		   *FreeLines;	/* free space list */
X
Xhidden WindowSize;		/* the number of lines on which line ID
X				   operations should be done */
Xhidden Ch NullStr[MScreenWidth];/* type Ch equivalent of line of blanks */
Xint baud_rate;			/* Terminal speed, so we can calculate
X				   the number of characters required to
X				   make the cursor sit still for n secs. */
Xhidden CheckForInput;		/* -ve iff UpdateLine should bother
X				   checking for input */
Xhidden char OneLineBuf[MScreenWidth];/* For use by dumpstring and
X				        UpdateEasyLine */
X
X/* 'newline' returns a pointer to a new line object, either from the
X   free list or from the general unix pool */
Xhidden struct line *newline ()
X{
X    register struct line   *p = FreeLines;
X    register Ch *c;
X
X    if (p) {
X	FreeLines = p -> next;
X#ifdef DEBUG
X	if (p -> hash != 12345) {
X/*	    register FILE *f = fopen ("EMACS_TRACE", "w");
X	    topos (23, 1);
X	    printf ("*****Bogus value in display free list"); */
X	    FreeLines = 0;
X/*	    if (f) {
X		register int *p1 = ((int *) p) - 10;
X		register char *p2 = (char *) p1;
X		register i;
X		fprintf (f, "Bogus value in display free list at %o\n", p);
X		for (i=0; i<25; i++) {
X		    fprintf (f, "%11o: %011o %9d  %03o %03o %03o %03o\n",
X				p1, *p1, *p1,
X				p2[0], p2[1], p2[2], p2[3]);
X		    p1++; p2 += 4;
X		}
X		fclose (f);
X	    } */
X	    return newline ();
X	}
X#endif
X    }
X    else {
X	static Leakage;
X	p = (struct line   *) malloc (sizeof *p);
X	if (++Leakage>(2*MScreenLength)) printf ("*****Display core leakage!");
X    }
X    p -> length = 0;
X    p -> hash = 0;
X    p -> touched = 1;
X    for (c = &p -> body[ScreenWidth]; c > p -> body;)
X	(--c) -> ch_all = ' ';
X    return p;
X}
X
X/* 'ReleaseLine' returns a line object to the free list */
Xhidden procedure ReleaseLine (p)
Xregister struct line   *p; {
X    if (p) {
X	if (p -> hash == 12345) {
X	    printf("\rBogus re-release!");
X	    fflush(stdout);
X	    /* abort(); */
X	    return;
X	}
X	p -> next = FreeLines;
X	p -> hash = 12345;
X	FreeLines = p;
X    }
X}
X
Xhidden struct line *PhysScreen[MScreenLength + 1];
X /* the current (physical) screen */
Xhidden struct line *DesiredScreen[MScreenLength + 1];
X /* the desired (virtual) screen */
X
Xvisible int
X	    ScreenGarbaged,	/* set to 1 iff screen content is
X				   uncertain. */
X	    InputPending,	/* true iff input is known to be pending */
X	    LastRedisplayPaused,/* true iff last redisplay paused */
X#ifdef DEBUG
X	    RDdebug,		/* line redraw debug switch */
X	    IDdebug,		/* line insertion/deletion debug */
X#endif DEBUG
X	    WDCurrentLine,	/* current line for writing to the
X				   virtual screen. */
X	    WDleft;		/* number of columns left on the current
X				   line of the virtual screen. */
Xvisible Ch
X	    *WDcursor;		/* pointer into a line object, indicates
X				   where to put the next character */
X
X/* 'WDCharAt' returns a pointer to the Ch at position (row,col) in the
X   virtual screen.  This is purely for the grotesque attributes in
X   HP264?s where one must know what attribute is desired after the end
X   of a string. */
Xvisible Ch *WDCharAt (row, col) {
X    register struct line *p;
X
X    if ((p = DesiredScreen[row]) == 0 || p -> length < col)
X	return &NullStr[0];	/* blank */
X    else
X	return &p -> body[col - 1];
X}
X
X/* 'WDsetpos' positions the cursor at position (row,col) in the virtual
X   screen */
Xvisible procedure WDsetpos (row, col)
Xregister    row,
X	    col; {
X    register struct line   *p;
X    register    n;
X
X    if (WDCurrentLine >= 0
X	    && (p = DesiredScreen[WDCurrentLine]) -> length
X	    <= (n = ScreenWidth - WDleft))
X	p -> length = WDleft > 0 ? n : ScreenWidth;
X    if (!DesiredScreen[row])
X	DesiredScreen[row] = newline ();
X    (p = DesiredScreen[row]) -> hash = 0;
X    p -> touched = 1;
X    WDcursor = &p -> body[col - 1];
X    WDCurrentLine = row;
X    WDleft = ScreenWidth + 1 - col;
X}
X
X/* 'WDclearline' positions the cursor at the beginning of the
X   indicated line and clears the line (in the image) */
Xvisible procedure WDclearline (row) {
X    register Ch *c;
X    register struct line *p;
X    WDsetpos (row, 1);
X    (p = DesiredScreen[row]) -> length = 0;
X    for (c = &p -> body[ScreenWidth]; c > p -> body;)
X	(--c) -> ch_all = ' ';
X}
X
X
X/* 'hashline' computes a hash value for a line, unless the hash value
X   is already known.  This hash code has a few important properties:
X	- it is independant of the number of leading and trailing spaces
X	- it will never be zero
X 
X   As a side effect, an estimate of the cost of redrawing the line is
X   calculated */
Xhidden procedure hashline (p)
Xregister struct line   *p; {
X    register Ch    *c,
X		   *l;
X    register    h;
X
X    if (!p || p -> hash) {
X	if (p && p->hash==12345) printf ("****Free line in screen");
X	return;
X    }
X    h = 0;
X    c = p -> body;
X    l = &p -> body[p -> length];
X    while (--l > c && l -> ch_all == ' ');
X    while (c <= l && c -> ch_all == ' ')
X	c++;
X    p -> DrawCost = l - c + 1;
X    while (c <= l)
X	h = (h << 5) + h + c++ -> ch_all;
X    p -> hash = h!=12345 && h ? h : 1;
X}
X
X/*	1   2   3   4   ....	Each Mij represents the minumum cost of
X      +---+---+---+---+-----	rearranging the first i lines to map onto
X    1 |   |   |   |   |		the first j lines (the j direction
X      +---+---+---+---+-----	represents the desired contents of a line,
X    2 |   |  \| ^ |   |		i the current contents).  The algorithm
X      +---+---\-|-+---+-----	used is a dynamic programming one, where
X    3 |   | <-+Mij|   |		M[i,j] = min( M[i-1,j],
X      +---+---+---+---+-----		      M[i,j-1]+redraw cost for j,2
X    4 |   |   |   |   |			      M[i-1,j-1]+the cost of
X      +---+---+---+---+-----			converting line i to line j);
X    . |   |   |   |   |		Line i can be converted to line j by either
X    .				just drawing j, or if they match, by moving
X    .				line i to line j (with insert/delete line)
X */
X
Xhidden struct Msquare {
X    short   cost;		/* the value of Mij */
X    char    fromi,
X	    fromj;		/* the coordinates of the square that
X				   the optimal move comes from */
X}                       M[MScreenLength + 1][MScreenLength + 1];
X
Xhidden procedure calcM () {
X    register struct Msquare *p;
X    register    i,
X		j,
X		movecost,
X		cost;
X    int     reDrawCost,
X	    idcost,
X	    leftcost;
X    double  fidcost;
X
X    cost = 0;
X    movecost = 0;
X    for (i = 0; i <= ScreenLength; i++) {
X	p = &M[i][0];
X/*	M[i][i].cost = 0;  */
X	p[i].cost = 0;
X	M[0][i].cost = cost + movecost;
X/*	M[i][0].cost = movecost;  */
X	p[0].cost = movecost;
X	M[0][i].fromi = 0; 
X/*	M[0][i].fromj = M[i][i].fromj = i - 1;  */
X	M[0][i].fromj = p[i].fromj = i - 1;
X/*	M[i][0].fromi = M[i][i].fromi = i - 1;  */
X	p[0].fromi = p[i].fromi = i - 1;
X/*	M[i][0].fromj = 0;  */
X	p[0].fromj = 0;
X	movecost += W_tt.t_ILmf * (ScreenLength - i) + W_tt.t_ILov;
X	if (DesiredScreen[i + 1])
X	    cost += DesiredScreen[i + 1] -> DrawCost;
X    }
X
X    fidcost = W_tt.t_ILmf * (WindowSize + 1) + W_tt.t_ILov;
X    for (i = 1; i <= WindowSize; i++)
X    {
X	p = &M[i][0];
X	fidcost -= W_tt.t_ILmf;
X	idcost = fidcost;
X	for (j = 1; j <= WindowSize; j++) {
X	    p++; 
X/*	    p = &M[i][j]; */
X	    cost =  DesiredScreen[j] ? DesiredScreen[j] -> DrawCost : 0;
X	    reDrawCost = cost;
X	    if (PhysScreen[i] && DesiredScreen[j]
X		    && PhysScreen[i] -> hash == DesiredScreen[j] -> hash)
X		cost = 0;
X/*	    idcost = W_tt.t_ILmf * (WindowSize - i + 1) + W_tt.t_ILov; */
X/*	    movecost = M[i - 1][j].cost + (j == WindowSize ? 0 : idcost); */
X	    movecost = p[-MScreenLength-1].cost
X				+ (j == WindowSize ? 0 : idcost);
X	    p -> fromi = i - 1;	/* now using movecost for */
X	    p -> fromj = j;	/* the minumum cost. */
X	    if ((
X/*			leftcost = M[i][j - 1].cost */
X			leftcost = p[-1].cost
X				+ (i == WindowSize ? 0 : idcost) + reDrawCost
X		    ) < movecost) {
X		movecost = leftcost;
X		p -> fromi = i;
X		p -> fromj = j - 1;
X	    }
X/*	    cost += M[i - 1][j - 1].cost; */
X	    cost += p[-MScreenLength-2].cost;
X	    if (cost < movecost)
X		movecost = cost,
X		    p -> fromi = i - 1, p -> fromj = j - 1;
X	    p -> cost = movecost;
X	}
X    }
X}
X
X/* calculate and perform the optimal sequence of insertions/deltions
X   given the matrix M from routine calcM */
X
Xhidden procedure CalcID (i, j, InsertsDesired)
Xregister    i,
X	    j; {
X    register    ni,
X		nj;
X    register struct Msquare *p = &M[i][j];
X    if (i > 0 || j > 0) {
X	ni = p -> fromi;
X	nj = p -> fromj;
X	if (ni == i) {
X	    CalcID (ni, nj, i != WindowSize ? InsertsDesired + 1 : 0);
X	    InsertsDesired = 0;
X	    if (InputPending) {
X		if (PhysScreen[j] != DesiredScreen[j])
X		    ReleaseLine (PhysScreen[j]);
X		PhysScreen[j] = 0;
X		ReleaseLine (DesiredScreen[j]);
X		DesiredScreen[j] = 0;
X		LastRedisplayPaused++;
X	    }
X	    else {
X		UpdateLine ((struct line *) 0, DesiredScreen[j], j);
X		if (PhysScreen[j] != DesiredScreen[j])
X		    ReleaseLine (PhysScreen[j]);
X		PhysScreen[j] = DesiredScreen[j];
X		DesiredScreen[j] = 0;
X	    }
X	}
X	else
X	    if (nj == j) {
X		if (j != WindowSize) {
X		    register    nni,
X				dlc = 1;
X		    for (; ni;) {
X			p = &M[ni][nj];
X			nni = p -> fromi;
X			if (p -> fromj == nj) {
X			    dlc++;
X			    ni = nni;
X			}
X			else
X			    break;
X		    }
X		    topos (i - dlc + 1, 1);
X		    deletelines (dlc);
X		}
X		CalcID (ni, nj, 0);
X	    }
X	    else {
X		register struct line   *old = PhysScreen[i];
X#ifdef DOEARLY
X		register    DoneEarly = 0;
X#endif
X		if (old == DesiredScreen[i]) DesiredScreen[i] = 0;
X		PhysScreen[i] = 0;
X
X#ifdef DOEARLY
X	    /* The following hack and all following lines involving the
X	       variable "DoneEarly" cause the bottom line of the screen to
X	       be redisplayed before any others if it has changed and it
X	       would be redrawn in-place.  This is purely for Emacs,
X	       people using this package for other things might want to
X	       lobotomize this section. */
X		if (i == ScreenLength && j == ScreenLength
X/*			&& old != PhysScreen[j]) { */
X			&& DesiredScreen[j]) {
X		    DoneEarly++;
X		    UpdateLine (old, DesiredScreen[j], j);
X		}
X#endif
X		CalcID (ni, nj, 0);
X		if (InputPending
X#ifdef DOEARLY
X				 && !DoneEarly
X#endif
X						) {
X		    if (PhysScreen[j] != old)
X			ReleaseLine (PhysScreen[j]);
X		    if (DesiredScreen[j] != old
X			    && DesiredScreen[j] != PhysScreen[j])
X			ReleaseLine (DesiredScreen[j]);
X		    PhysScreen[j] = old;
X		    DesiredScreen[j] = 0;
X		    LastRedisplayPaused++;
X		}
X		else {
X		    if (
X#ifdef DOEARLY
X			!DoneEarly &&
X#endif
X					(DesiredScreen[j] || i != j))
X			UpdateLine (old, DesiredScreen[j], j);
X		    if (PhysScreen[j] != DesiredScreen[j])
X			ReleaseLine (PhysScreen[j]);
X		    if (old != DesiredScreen[j] && old != PhysScreen[j])
X			ReleaseLine (old);
X		    PhysScreen[j] = DesiredScreen[j];
X		    DesiredScreen[j] = 0;
X		}
X	    }
X    }
X    if (InsertsDesired) {
X	topos (j + 1, 1);
X	insertlines (InsertsDesired);
X    }
X}
X
X/* modify current screen line 'old' to match desired line 'new',
X   the old line is at position ln.  Each line
X   is scanned and partitioned into 4 regions:
X
X	     <osp><----m1-----><-od--><----m2----->
X    old:    "     Twas brillig and the slithy toves"
X    new:    "        Twas brillig where a slithy toves"
X	     <-nsp--><----m1-----><-nd--><----m2----->
X
X	nsp, osp	- number of leading spaces on each line
X	m1		- length of a leading matching sequence
X	m2		- length of a trailing matching sequence
X	nd, od		- length of the differing sequences
X */
Xhidden procedure UpdateLine (old, new, ln)
Xregister struct line	*old,
X			*new; {
X    register Ch		*op,
X			*np,
X			*ol,
X			*nl;
X    Ch *Iop, *Inp;		/* for saving initial values */
X    int	osp,
X	nsp,
X	m1,
X	m2,
X	od,
X	nd,
X	t,
X	OldLineWipeTo,
X	rv = 1;
X
X    if (old == new)
X	return 0;		/* did nothing */
X    if (old) {
X	op = old -> body;
X	ol = &old -> body[OldLineWipeTo = old -> length];
X    }
X    else
X	op = NullStr, ol = op, OldLineWipeTo = 1;
X    if (new) {
X	np = new -> body;
X	nl = &new -> body[new -> length];
X    }
X    else
X	np = NullStr, nl = np;
X
X/* ACT 11-Nov-1982 Do cheap update if obvious that fanciness goes nowhere */
X
X    if (!W_tt.t_needspaces && np != NullStr && op == NullStr) {
X	UpdateEasyLine (ln, np, nl);
X	goto cleanup;
X    }
X    Inp = np, Iop = op;
X    osp = 0, nsp = 0, m1 = 0, m2 = 0;
X
X/* calculate the magic parameters */
X    while ((--ol) -> ch_all == ' ' && ol >= op)
X	--OldLineWipeTo;
X    while ((--nl) -> ch_all == ' ' && nl >= np)
X	--new -> length;
X    while (op -> ch_all == ' ' && op <= ol)
X	op++, osp++;
X    while (np -> ch_all == ' ' && np <= nl)
X	np++, nsp++;
X    if (ol < op && !W_tt.t_needspaces)
X	osp = nsp;
X    while (op -> ch_all == np -> ch_all && op <= ol && np <= nl)
X	    op++, np++, m1++;
X    while (ol -> ch_all == nl -> ch_all && op <= ol && np <= nl)
X	ol--, nl--, m2++;
X    od = ol - op + 1;
X    nd = nl - np + 1;
X
X/* forget matches which would be expensive to capitalize on */
X    if (m1 || m2) {
X	register int    c0,
X			c1,
X			c2,
X			c3;
X	c0 = nsp + m1 + m2;
X	if (c1 = nsp - osp)
X	    c1 = c1<0 ? W_tt.t_DCov - c1*W_tt.t_DCmf
X		      : W_tt.t_ICov + c1*W_tt.t_ICmf;
X	if (c3 = nd - od)
X	    c3 = c3<0 ? W_tt.t_DCov - c3*W_tt.t_DCmf
X		      : W_tt.t_ICov + c3*W_tt.t_ICmf;
X	if (c2 = (nsp + nd) - (osp + od))
X	    c2 = c2<0 ? W_tt.t_DCov - c2*W_tt.t_DCmf
X		      : W_tt.t_ICov + c2*W_tt.t_ICmf;
X	c3 += c1;
X	c1 += m2;
X	c2 += m1;
X	if (m2 && (c0 < c2 && c0 < c3 || c1 < c2 && c1 < c3)) {
X	    nd += m2;
X	    od += m2;
X	    ol += m2;
X	    nl += m2;
X	    m2 = 0;
X	}
X	if (m1 && (c0 < c1 && c0 < c3 || c2 < c1 && c2 < c3)) {
X	    nd += m1;
X	    od += m1;
X	    np -= m1;
X	    op -= m1;
X	    m1 = 0;
X	}
X    }
X#ifdef DEBUG
X    if (RDdebug && (m1 || m2 || nd || od)) {
X	fprintf (stderr,"%2d nsp=%2d osp=%2d m1=%2d nd=%2d od=%2d m2=%2d\n",
X		ln, nsp, osp, m1, nd, od, m2);
X    }
X#endif
X    if (m1 == 0)
X	if (m2 == 0) {
X	    if (od == 0 && nd == 0) {
X		rv = 0;		/* Jackpot! */
X		goto cleanup;
X	    }
X	    INSmode (0);
X	    if (W_tt.t_needspaces) {
X		if (nsp > osp) {
X		    topos (ln, min (nsp, osp) + 1);
X		    (*W_tt.t_modes) (0);
X		    blanks (nsp - osp);
X		}
X		dumpstring (np, nl);
X	    }
X	    else
X		dumps2 (Inp, nl, Iop, ln, 0);
X	    if (nsp + nd < osp + od) {
X		topos (ln, nsp + nd + 1);
X		wipeline (0, OldLineWipeTo);
X	    }
X	}
X	else {			/* m1==0 && m2!=0 && (nd!=0 || od!=0) */
X	    t = (nsp + nd) - (osp + od);
X	    topos (ln, min (nsp, osp) + 1);
X	    if (nsp > osp)
X		np -= nsp - osp;
X	    if (t >= 0) {
X		if (nl - t >= np) {
X		    INSmode (0);
X		    if (W_tt.t_needspaces)
X			dumpstring (np, nl - t);
X		    else
X			dumps2 (Inp, nl - t, Iop, ln, np - Inp);
X		    if (t > 0)
X			topos (ln, nl - t - Inp + 1);
X		}
X		if (t > 0)
X		    INSmode (1), dumpstring (nl - t + 1, nl);
X	    }
X	    else {
X		INSmode (0);
X		if (W_tt.t_needspaces)
X		    dumpstring (np, nl);
X		else
X		    dumps2 (Inp, nl, Iop, ln, np - Inp);
X		topos (ln, nsp + nd + 1);
X		deletechars (-t);
X	    }
X	}
X    else {			/* m1!=0 */
X	register    lsp = osp;
X	if (nsp < osp) {
X	    topos (ln, 1);
X	    deletechars (osp - nsp);
X	    lsp = nsp;
X	}
X	if (m2 == 0) {
X	    if (nd == 0 && od == 0) {
X		if (nsp > osp) {
X		    topos (ln, 1);
X		    INSmode (1);
X		    (*W_tt.t_modes) (0);
X		    blanks (nsp - osp);
X		}
X		goto cleanup;
X	    }
X#ifndef notdef
X	    if (od == 0 && !W_tt.t_needspaces)
X		while (np -> ch_all == ' ' && np <= nl) np++, m1++;
X#endif
X	    topos (ln, lsp + m1 + 1);
X	    INSmode (0);
X	    if (nsp != osp || W_tt.t_needspaces)
X		dumpstring (np, nl);
X	    else
X		dumps2 (Inp, nl, Iop, ln, np - Inp);
X	    if (nd < od) {
X		topos (ln, lsp + m1 + nd + 1);
X		wipeline (0, OldLineWipeTo);
X	    }
X	    if (nsp > osp) {
X		topos (ln, 1);
X		INSmode (1);
X		(*W_tt.t_modes) (0);
X		blanks (nsp - osp);
X	    }
X	}
X	else {			/* m1!=0 && m2!=0 && (nd!=0 || od!=0) */
X	    topos (ln, lsp + m1 + 1);
X	    t = nd - od;
X	    if (nd > 0 && od > 0) {
X		INSmode (0);
X		if (nsp == osp && !W_tt.t_needspaces) {
X		    dumps2 (Inp, np + min (nd, od) - 1, Iop, ln, np - Inp);
X		    if (nd != od)
X			topos (ln, lsp + m1 + min (nd, od) + 1);
X		}
X		else
X		    dumpstring (np, np + min (nd, od) - 1);
X	    }
X	    if (nd < od)
X		deletechars (od - nd);
X	    else
X		if (nd > od)
X		    INSmode (1), dumpstring (np + od, nl);
X	    if (nsp > osp) {
X		topos (ln, 1);
X		INSmode (1);
X		(*W_tt.t_modes) (0);
X		blanks (nsp - osp);
X	    }
X	}
X    }
Xcleanup:;
X#ifdef FIONREAD
X    if(--CheckForInput<0 && !InputPending &&
X				((stdout->_ptr - stdout->_base) > 20)){
X	fflush (stdout);
X#ifdef TIOCOUTQ			/* prevent system I/O buffering */
X	if (baud_rate < 2400) {
X	    int out1;
X	    float outtime;
X	    if (ioctl (fileno(stdin), TIOCOUTQ, &out1))
X		out1 = 0;
X	    out1 *= 10;
X	    outtime = ((float) out1) / ((float) baud_rate);
X	    if (outtime >= 1.5) sleep ((unsigned) (outtime - .5));
X	}
X#endif
X	ioctl (fileno(stdin), FIONREAD, &InputPending);
X	CheckForInput = baud_rate / 2400;
X    }
X#endif
X    return rv;
X}
X
X/* Update a line that used to be completely blank */
Xhidden procedure UpdateEasyLine (ln, st, en)
Xregister Ch *st, *en;
X{
X    register char *p;
X    register mode;
X    Ch *xstart = st, *ostart;
X
X    INSmode (0);
X    while (st < en) {
X	if (st -> ch_all == ' ' && (st+1) < en && (st+1) -> ch_all == ' ') {
X	    while (st < en && st -> ch_all == ' ')
X		st++;
X	    continue;
X	}
X	ostart = st;
X	mode = st -> Mode;
X	p = OneLineBuf;
X	while (st < en && st -> Mode == mode) {
X	    if (st -> ch_all == ' ' && (st+2) < en && (st+1) -> ch_all == ' '
X	        && (st+2) -> ch_all == ' ')
X		break;
X	    *p++ = st++ -> Char;
X	}
X	topos (ln, ostart-xstart+1);
X	(*W_tt.t_modes) (mode);
X	(*W_tt.t_writechars) (OneLineBuf, p - 1);
X    }
X}
X
Xvisible procedure WDUpdateScreen (SlowUpdate, NoInputCheck) {
X    register    n,		/* NOTE: n MUST be first register! */
X		c;
X
X    CheckForInput = 9999;
X    if (ScreenGarbaged) {
X	reset ();
X	ScreenGarbaged = 0;
X	SlowUpdate = 0;
X	for (n = 0; n <= ScreenLength; n++) {
X	    ReleaseLine (PhysScreen[n]);
X	    PhysScreen[n] = 0;
X	}
X    }
X#ifdef FIONREAD			/* one quick test */
X    if (!NoInputCheck && !InputPending)
X	ioctl (fileno(stdin), FIONREAD, &InputPending);
X#endif
X    if (WDCurrentLine >= 0
X	    && DesiredScreen[WDCurrentLine] -> length <= ScreenWidth - WDleft)
X	DesiredScreen[WDCurrentLine] -> length =
X	    WDleft > 0 ? ScreenWidth - WDleft : ScreenWidth;
X    WDCurrentLine = -1;
X    if (W_tt.t_ILov == MissingFeature)
X	SlowUpdate = 0;
X    if (SlowUpdate) {
X	for (n = 1; n <= ScreenLength; n++) {
X/*	    if (DesiredScreen[n] == 0)/* Fortunately for my current hacking,
X/*					 this is never true. ACT 24-Mar-83 */
X/*		DesiredScreen[n] = PhysScreen[n];
X/*	    else */
X		hashline (DesiredScreen[n]);
X	    hashline (PhysScreen[n]);
X	}
X	c = 0;
X	for (n = ScreenLength; n >= 1 && c <= 2; n--)
X	    if (PhysScreen[n] != DesiredScreen[n]
X		    && PhysScreen[n]
X		    && DesiredScreen[n] -> hash != PhysScreen[n] -> hash)
X		c++;
X	if (c <= 2)
X	    SlowUpdate = 0;
X	else {
X	    if (W_tt.t_window) {
X		for (n = ScreenLength;
X			n >= 1
X			&& (PhysScreen[n] == DesiredScreen[n]
X			    || PhysScreen[n]
X			    && DesiredScreen[n] -> hash == PhysScreen[n] -> hash);
X			n--);
X		WindowSize = n;
X		(*W_tt.t_window) (n);
X	    }
X	    else
X		WindowSize = ScreenLength;
X	    calcM ();
X	    CheckForInput = NoInputCheck ? 9999 : baud_rate / 2400;
X	    CalcID (ScreenLength, ScreenLength, 0);
X/*	for (n = 1; n <= ScreenLength; n++) {
X	    if (DesiredScreen[n] != PhysScreen[n]) {
X		ReleaseLine (PhysScreen[n]);
X		PhysScreen[n] = DesiredScreen[n];
X	    }
X	    DesiredScreen[n] = 0;
X	} */
X	}
X    }
X    if (!SlowUpdate) {		/* fast update */
X	for (n = 1; n <= ScreenLength; n++)
X	    if (DesiredScreen[n] && DesiredScreen[n] -> touched) {
X		if (UpdateLine (PhysScreen[n], DesiredScreen[n], n)) {
X/*		    if (PhysScreen[n] != DesiredScreen[n]) */
X			ReleaseLine (PhysScreen[n]);
X		    PhysScreen[n] = DesiredScreen[n];
X		    DesiredScreen[n] = 0;
X		}
X	    }
X    }
X    if (WSetRealCursor && !InputPending)
X	topos (WRCurRow + 1, WRCurCol + 1);
X    if (W_tt.t_donerefresh)
X	(*W_tt.t_donerefresh) ();
X    for (n = 1; n <= ScreenLength; n++) {
X	if (PhysScreen[n] != 0 && DesiredScreen[n] == 0) {
X	    DesiredScreen[n] = newline ();
X#ifdef VAX
X	    /* This bit of trickery helps a LOT. */
X	    asm ("movl	_PhysScreen[r11],r1");	/*r1=from, r0=to*/
X	    asm ("clrw	12(r0)");		/*r0->touched=0*/
X	    asm ("movw	10(r1),10(r0)");	/*r0->length=r1->length*/
X	    asm ("cvtwl	10(r1),r2");		/*r2=2*r1->length*/
X	    asm ("addl2	r2,r2");
X	    asm ("movc3	r2,14(r1),14(r0)");	/*bcopy(r1->body,r0->body,r2)*/
X#else
X	    CopyLine (PhysScreen[n], DesiredScreen[n]);
X#endif
X	}
X    }
X}
X
X#ifndef VAX
Xhidden procedure CopyLine (from, to)
Xregister struct line *from, *to;
X{
X    register Ch *cp = from -> body, *tp = to -> body;
X    register n = from -> length;
X    to -> touched = 0;
X    to -> length = from -> length;
X    while (--n>=0) *tp++ = *cp++;
X}
X#endif
X
Xvisible int VisibleBell;	/* If true and the terminal will support it
X				   then the screen will flash instead of
X				   feeping when an error occurs */
Xvisible int InverseVideo;	/* If true and the terminal will support it
X				   then we will use inverse video */
X
X/* DJH common routine for a feep */
XDing () {			/* BOGUS!  this should really be terminal
X				   type specific! */
X    if (VisibleBell && W_tt.t_flash) (*W_tt.t_flash) ();
X    else putchar (07);
X    fflush (stdout);		/* 23 May 1983 ACT */
X}
X
X/* initialize the teminal package */
XWDterm_init () {
X    static short    baud_convert[] =
X    {
X	0, 50, 75, 110, 135, 150, 200, 300, 600, 1200,
X	1800, 2400, 4800, 9600, 19200
X    };
X    int		    rv = 0;	/* Return value: 0 = OK */
X    struct sgttyb   sg;
X    extern short    ospeed;
X    extern  WTtyFd;		/* For gttying on the terminal */
X    static  BeenHere;		/* true iff we've been here before (some
X				   things must only be done once!) */
X
X#ifdef DEBUG
X    RDdebug = 0;		/* line redraw debug switch */
X    IDdebug = 0;		/* line insertion/deletion debug */
X#endif DEBUG
X    WDCurrentLine = -1;		/* current line for writing to the
X				   virtual screen. */
X    WDleft = -1;		/* number of columns left on the current
X				   line of the virtual screen. */
X    gtty (WTtyFd, &sg);
X    ospeed = sg.sg_ospeed;
X    baud_rate = sg.sg_ospeed == 0 ? 1200
X	: sg.sg_ospeed < sizeof baud_convert / sizeof baud_convert[0]
X	? baud_convert[sg.sg_ospeed] : 9600;
X    if (!BeenHere) {
X	char   *tname = (char *) getenv ("TERM");
X	struct termtype {
X	    char   *name;
X	    int     cmplen;
X	    int     (*startup) ();
X	};
X    /* A terminal driver is selected by looking up the value of the
X       environment variable TERM in the following table.  The string is
X       matched against the name, considering at most "cmplen" characters
X       to be significant.  "startup" points to the function that sets up
X       the terminal driver.  The driver is called with the terminal type
X       as a parameter and is free to use that to specialize itself. */
X    /* NOTE: The driver should return 0 if the terminal is useable.  For
X       now, only the TrmTERM driver does so. */
X	struct termtype *p;
X	extern  TrmTEK4025 ();
X	extern  TrmAmb ();
X/*	extern  TrmC100 (); */
X/*	extern  TrmI400 (); */
X/*	extern  TrmMiniB (); */
X/*	extern  TrmPERQ (); */
X	extern  TrmVT100 ();
X	extern	TrmBitG ();
X/*	extern	TrmGT40 (); */
X/*	extern	TrmGigi (); */
X	static struct termtype  termtable[] = {
X	    "4025",	99, TrmTEK4025,
X	    "aaa",	99, TrmAmb,
X	    "amb",	99, TrmAmb,
X	    "ambassador",99, TrmAmb,
X	    "BG",	99, TrmBitG,
X	    "Bit",	3,  TrmBitG,
X/*	    "C10",	3,  TrmC100, */
X/*	    "c10",	3,  TrmC100, */
X/*	    "Concept",	7,  TrmC100, */
X/*	    "concept",	7,  TrmC100, */
X/*	    "d4",	99, TrmGT40, */
X	    "D5",	99, TrmVT100,
X	    "Dq",	2,  TrmVT100,
X	    "DT80",	99, TrmVT100,
X/*	    "GG",	99, TrmGigi, */
X/*	    "Gigi",	4,  TrmGigi, */
X/*	    "gt40",	99, TrmGT40, */
X/*	    "GT40",	99, TrmGT40, */
X/*	    "perq",	4,  TrmC100, */
X/*	    "i400",	99, TrmI400, */
X	    "Mb",	99, TrmAmb,
X/*	    "minibee",	99, TrmMiniB, */
X	    "tek4025",	99, TrmTEK4025,
X	    "VT1",	3,  TrmVT100,
X	    "vt1",	3,  TrmVT100,
X	    "X5",	99, TrmTEK4025,
X	    0, 0, 0
X	};
X	BeenHere++;
X	if (tname == 0)
X	    tname = "sd";
X	{			/* Initialize NullStr */
X	    register Ch *p;
X	    for (p = NullStr; p < &NullStr[MScreenWidth]; )
X		p++ -> ch_all = ' ';
X	}
X	W_tt.t_frames[0] = '+', W_tt.t_frames[2] = '+';
X	W_tt.t_frames[5] = '+', W_tt.t_frames[7] = '+';
X	W_tt.t_frames[1] = '-', W_tt.t_frames[6] = '-';
X	W_tt.t_frames[3] = '|', W_tt.t_frames[4] = '|';
X
X	for (p = termtable; p -> name; p++)
X	    if (strcmpn (p -> name, tname, p -> cmplen) == 0) {
X		rv = (*p -> startup) (tname);
X		break;
X	    }
X	if (p -> name == 0)
X	    rv = TrmTERM (tname);
X	if (rv)
X	    return rv;
X    }
X    rv = (*W_tt.t_init) (baud_rate);
X    if (rv)
X	return rv;
X    if (W_tt.t_length > MScreenLength)
X	W_tt.t_length = MScreenLength;
X    if (W_tt.t_width > MScreenWidth)
X	W_tt.t_width = MScreenWidth;
X    (*W_tt.t_reset) ();
X    return 0;
X}
X
X/* Debugging routines -- called from sdb only */
X
X/* print out the insert/delete cost matrix */
X#ifdef DEBUG
XPrintM () {
X    register    i,
X		j;
X    register struct Msquare *p;
X    for (i = 0; i <= ScreenLength; i++) {
X	for (j = 0; j <= ScreenLength; j++) {
X	    p = &M[i][j];
X	    fprintf (stderr, "%4d%c", p -> cost,
X		    p -> fromi < i && p -> fromj < j ? '\\' :
X		    p -> fromi < i ? '^' :
X		    p -> fromj < j ? '<' : ' ');
X	}
X	fprintf (stderr, "\n");
X    }
X    fprintf (stderr, "\014");
X}
X#endif
X
Xvisible procedure
XNoOperation () {}
X
Xhidden procedure dumpstring (start, end)
Xregister Ch *start, *end;
X{
X    register char *p;
X    register mode;
X
X    do {
X	mode = start -> Mode;
X	p = OneLineBuf;
X	while (start <= end && start -> Mode == mode)
X	    *p++ = start++ -> Char;
X	(*W_tt.t_modes) (mode);
X	(*W_tt.t_writechars) (OneLineBuf, p - 1);
X    } while (start <= end);
X}
X
X/* Update a line that hasn't shifted left or right -- can compare char by
X   char and skip over equal chunks */
X/* NOTE: We have carefully guaranteed that whenever st<=en, os<=(the end of
X   the line that os pointed to) and that all "extra" chars in a line (ie
X   past the "end") are (type Ch) blanks */
Xhidden procedure dumps2 (st, en, os, ln, skip)
Xregister Ch *st, *en, *os;
X{
X    register char *p;
X    register mode;
X    Ch *xstart = st, *ostart;
X
X    st += skip;
X    os += skip;
X    while (st <= en) {
X	if (st -> ch_all == os -> ch_all && st+1 <= en &&
X			(st+1)->ch_all == (os+1)->ch_all) {
X	    while (st <= en && st -> ch_all == os -> ch_all)
X		st++, os++;
X	    continue;
X	}
X	ostart = st;
X	mode = st -> Mode;
X	p = OneLineBuf;
X	while (st <= en && st -> Mode == mode) {
X	    if (st->ch_all == os->ch_all && st+2 <= en &&
X			(st+1)->ch_all == (os+1)->ch_all &&
X			(st+2)->ch_all == (os+2)->ch_all)
X		break;
X	    *p++ = st++ -> Char;
X	    os++;
X	}
X	topos (ln, ostart-xstart+1);
X	(*W_tt.t_modes) (mode);
X	(*W_tt.t_writechars) (OneLineBuf, p - 1);
X    }
X}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 display.c
	/bin/echo -n '	'; /bin/ls -ld display.c
fi
-- 
UUCP:	{seismo,allegra,brl-bmd}!umcp-cs!chris
CSNet:	chris@umcp-cs
ARPA:	chris.umcp-cs@UDel-Relay