Vile 03/17 - vi feel-alike (multi-window)

Paul Fox pgf at cayman.COM
Sat Jun 8 08:09:16 AEST 1991


#!/bin/sh
# this is vileshar.03 (part 3 of Vile)
# do not concatenate these parts, unpack them in order with /bin/sh
# file crypt.c continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 3; then
	echo Please unpack part "$Scheck" next!
	exit 1
 else
	exit 0
 fi
) < _shar_seq_.tmp || exit 1
echo 'x - continuing file crypt.c'
sed 's/^X//' << 'SHAR_EOF' >> 'crypt.c' &&
X *		file from one computer should be able to be decrypted 
X *		on another computer.
X *
X *	    3.	The encryption had to be inexpensive, both in terms
X *		of speed and space.
X *
X *	    4.	The system needed to be secure against all but the
X *		most determined of attackers.
X *
X *	For encryption of a block of data, one calls crypt passing 
X *	a pointer to the data block and its length. The data block is 
X *	encrypted in place, that is, the encrypted output overwrites 
X *	the input.  Decryption is totally isomorphic, and is performed 
X *	in the same manner by the same routine.  
X *
X *	Before using this routine for encrypting data, you are expected 
X *	to specify an encryption key.  This key is an arbitrary string,
X *	to be supplied by the user.  To set the key takes two calls to 
X *	crypt().  First, you call 
X *
X *		crypt(NULL, vector)
X *
X *	This resets all internal control information.  Typically (and 
X *	specifically in the case on MICRO-emacs) you would use a "vector" 
X *	of 0.  Other values can be used to customize your editor to be 
X *	"incompatable" with the normally distributed version.  For 
X *	this purpose, the best results will be obtained by avoiding
X *	multiples of 95.
X *
X *	Then, you "encrypt" your password by calling 
X *
X *		crypt(pass, strlen(pass))
X *
X *	where "pass" is your password string.  Crypt() will destroy 
X *	the original copy of the password (it becomes encrypted), 
X *	which is good.  You do not want someone on a multiuser system 
X *	to peruse your memory space and bump into your password.  
X *	Still, it is a better idea to erase the password buffer to 
X *	defeat memory perusal by a more technical snooper.  
X *
X *	For the interest of cryptologists, at the heart of this 
X *	function is a Beaufort Cipher.  The cipher alphabet is the 
X *	range of printable characters (' ' to '~'), all "control" 
X *	and "high-bit" characters are left unaltered.
X *
X *	The key is a variant autokey, derived from a wieghted sum 
X *	of all the previous clear text and cipher text.  A counter 
X *	is used as salt to obiterate any simple cyclic behavior 
X *	from the clear text, and key feedback is used to assure 
X *	that the entire message is based on the original key, 
X *	preventing attacks on the last part of the message as if 
X *	it were a pure autokey system.
X *
X *	Overall security of encrypted data depends upon three 
X *	factors:  the fundamental cryptographic system must be 
X *	difficult to compromise; exhaustive searching of the key 
X *	space must be computationally expensive; keys and plaintext 
X *	must remain out of sight.  This system satisfies this set
X *	of conditions to within the degree desired for MicroEMACS.
X *
X *	Though direct methods of attack (against systems such as 
X *	this) do exist, they are not well known and will consume 
X *	considerable amounts of computing time.  An exhaustive
X *	search requires over a billion investigations, on average.
X *
X *	The choice, entry, storage, manipulation, alteration, 
X *	protection and security of the keys themselves are the 
X *	responsiblity of the user.  
X *
X **********/
X
crypt(bptr, len)
register char *bptr;	/* buffer of characters to be encrypted */
register int len;	/* number of characters in the buffer */
{
X	register int cc;	/* current character being considered */
X
X	static long key = 0;	/* 29 bit encipherment key */
X	static int salt = 0;	/* salt to spice up key with */
X
X	if (!bptr) {		/* is there anything here to encrypt? */
X		key = len;	/* set the new key */
X		salt = len;	/* set the new salt */
X		return;
X	}
X	while (len--) {		/* for every character in the buffer */
X
X		cc = *bptr;	/* get a character out of the buffer */
X
X		/* only encipher printable characters */
X		if ((cc >= ' ') && (cc <= '~')) {
X
/**  If the upper bit (bit 29) is set, feed it back into the key.  This 
X	assures us that the starting key affects the entire message.  **/
X
X			key &= 0x1FFFFFFFL;	/* strip off overflow */
X			if (key & 0x10000000L) {
X				key ^= 0x0040A001L;	/* feedback */
X			}
X
/**  Down-bias the character, perform a Beaufort encipherment, and 
X	up-bias the character again.  We want key to be positive 
X	so that the left shift here will be more portable and the 
X	mod95() faster   **/
X
X			cc = mod95((int)(key % 95) - (cc - ' ')) + ' ';
X
/**  the salt will spice up the key a little bit, helping to obscure 
X	any patterns in the clear text, particularly when all the 
X	characters (or long sequences of them) are the same.  We do 
X	not want the salt to go negative, or it will affect the key 
X	too radically.  It is always a good idea to chop off cyclics 
X	to prime values.  **/
X
X			if (++salt >= 20857) {	/* prime modulus */
X				salt = 0;
X			}
X
/**  our autokey (a special case of the running key) is being 
X	generated by a wieghted checksum of clear text, cipher 
X	text, and salt.   **/
X
X			key = key + key + cc + *bptr + salt;
X		}
X		*bptr++ = cc;	/* put character back into buffer */
X	}
X	return;
}
X
static int mod95(val)
X
register int val;
X
{
X	/*  The mathematical MOD does not match the computer MOD  */
X
X	/*  Yes, what I do here may look strange, but it gets the
X		job done, and portably at that.  */
X
X	while (val >= 9500)
X		val -= 9500;
X	while (val >= 950)
X		val -= 950;
X	while (val >= 95)
X		val -= 95;
X	while (val < 0)
X		val += 95;
X	return (val);
}
#else
nocrypt()
{
}
#endif
SHAR_EOF
echo 'File crypt.c is complete' &&
chmod 0444 crypt.c ||
echo 'restore of crypt.c failed'
Wc_c="`wc -c < 'crypt.c'`"
test 6989 -eq "$Wc_c" ||
	echo 'crypt.c: original size 6989, current size' "$Wc_c"
# ============= csrch.c ==============
echo 'x - extracting csrch.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'csrch.c' &&
X
#include "estruct.h"
#include "edef.h"
X
/* These functions perform vi's on-this-line character scanning functions.
X	written for vile by Paul Fox, (c)1990
*/
static short lastscan;
static short lastchar;
#define BACK 0
#define FORW 1
#define DIREC 1
X
#define F 0
#define T 2
#define TYPE 2
X
X
fscan(f,n,c)
{
X	int i = 0;
X	int doto;
X
X	if (n <= 0) n = 1;
X
X	lastchar = c;
X	lastscan = FORW;
X
X	doto = curwp->w_doto;
X
X	i = doto+1;
X	while(i < llength(curwp->w_dotp)) {
X		if ( c == lgetc(curwp->w_dotp,i)) {
X			doto = i;
X			n--;
X			if (!n) break;
X		}
X		i++;
X	}
X
X	if ( i == llength(curwp->w_dotp)) {
X		TTbeep();
X		return(FALSE);
X	}
X	if (doingopcmd)
X		doto++;
X
X	curwp->w_doto = doto;
X	curwp->w_flag |= WFMOVE;
X	return(TRUE);
X			
}
X
bscan(f,n,c)
{
X	int i = 0;
X	int doto;
X
X	if (n <= 0) n = 1;
X
X	lastchar = c;
X	lastscan = BACK;
X
X	doto = curwp->w_doto;
X
X	i = doto-1;
X	while(i >= 0) {
X		if ( c == lgetc(curwp->w_dotp,i)) {
X			doto = i;
X			n--;
X			if (!n) break;
X		}
X		i--;
X	}
X
X	if ( i < 0 ) {
X		TTbeep();
X		return(FALSE);
X	}
X
X	curwp->w_doto = doto;
X	curwp->w_flag |= WFMOVE;
X	return(TRUE);
X
}
X
/* f */
fcsrch(f,n)
{
X	register int c;
X
X        c = kbd_key();
X	if (c == quotec)
X		c = tgetc();
X	else if (c == abortc)
X		return FALSE;
X	else
X		c = kcod2key(c);
X
X	return(fscan(f,n,c));
}
X
/* F */
bcsrch(f,n)
{
X	register int c;
X
X        c = kbd_key();
X	if (c == quotec)
X		c = tgetc();
X	else if (c == abortc)
X		return FALSE;
X	else
X		c = kcod2key(c);
X
X	return(bscan(f,n,c));
}
X
/* t */
fcsrch_to(f,n)
{
X	int s;
X	s = fcsrch(f,n);
X	if (s == TRUE)
X		s = backchar(FALSE,1);
X	lastscan |= T;
X	return(s);
}
X
/* T */
bcsrch_to(f,n)
{
X	int s;
X	s = bcsrch(f,n);
X	if (s == TRUE)
X		s = forwchar(FALSE,1);
X	lastscan |= T;
X	return(s);
}
X
/* ; */
rep_csrch(f,n)
{
X	int s;
X	int ls = lastscan;
X
X	if ((ls & DIREC) == FORW) {
X		s = fscan(f,n,lastchar);
X		if ((ls & TYPE) == T) {
X			if (s == TRUE)
X				s = backchar(FALSE,1);
X			lastscan |= T;
X		}
X		return(s);
X	} else {
X		s = bscan(f,n,lastchar);
X		if ((ls & TYPE) == T) {
X			if (s == TRUE)
X				s = forwchar(FALSE,1);
X			lastscan |= T;
X		}
X		return(s);
X	}
}
X
/* , */
rev_csrch(f,n)
{
X	int s;
X
X	lastscan ^= DIREC;
X	s = rep_csrch(f,n);
X	lastscan ^= DIREC;
X	return(s);
}
SHAR_EOF
chmod 0444 csrch.c ||
echo 'restore of csrch.c failed'
Wc_c="`wc -c < 'csrch.c'`"
test 2171 -eq "$Wc_c" ||
	echo 'csrch.c: original size 2171, current size' "$Wc_c"
# ============= dg10.c ==============
echo 'x - extracting dg10.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'dg10.c' &&
/*
X * The routines in this file provide support for the Data General Model 10
X * Microcomputer.
X */
X
#define	termdef	1			/* don't define "term" external */
X
#include        <stdio.h>
#include	"estruct.h"
#include        "edef.h"
X
#if     DG10
X
#define NROW    24                      /* Screen size.                 */
#define NCOL    80                      /* Edit if you want to.         */
#define	NPAUSE	100			/* # times thru update to pause */
#define	MARGIN	8			/* size of minimim margin and	*/
#define	SCRSIZ	64			/* scroll size for extended lines */
#define BEL     0x07                    /* BEL character.               */
#define ESC     30                      /* DG10 ESC character.          */
X
extern  int     ttopen();               /* Forward references.          */
extern  int     ttgetc();
extern  int     ttputc();
extern  int     ttflush();
extern  int     ttclose();
extern	int	dg10kopen();
extern	int	dg10kclose();
extern  int     dg10move();
extern  int     dg10eeol();
extern  int     dg10eeop();
extern  int     dg10beep();
extern  int     dg10open();
extern	int	dg10rev();
extern	int	dg10close();
extern	int	dg10cres();
X
#if	COLOR
extern	int	dg10fcol();
extern	int	dg10bcol();
X
int	cfcolor = -1;		/* current forground color */
int	cbcolor = -1;		/* current background color */
int	ctrans[] = {		/* emacs -> DG10 color translation table */
X	0, 4, 2, 6, 1, 5, 3, 7};
#endif
X
/*
X * Standard terminal interface dispatch table. Most of the fields point into
X * "termio" code.
X */
TERM    term    = {
X	NROW-1,
X        NROW-1,
X        NCOL,
X        NCOL,
X	MARGIN,
X	SCRSIZ,
X	NPAUSE,
X        dg10open,
X        dg10close,
X	dg10kopen,
X	dg10kclose,
X        ttgetc,
X        ttputc,
X        ttflush,
X        dg10move,
X        dg10eeol,
X        dg10eeop,
X        dg10beep,
X	dg10rev,
X	dg10cres
#if	COLOR
X	, dg10fcol,
X	dg10bcol
#endif
};
X
#if	COLOR
dg10fcol(color)		/* set the current output color */
X
int color;	/* color to set */
X
{
X	if (color == cfcolor)
X		return;
X	ttputc(ESC);
X	ttputc(0101);
X	ttputc(ctrans[color]);
X	cfcolor = color;
}
X
dg10bcol(color)		/* set the current background color */
X
int color;	/* color to set */
X
{
X	if (color == cbcolor)
X		return;
X	ttputc(ESC);
X	ttputc(0102);
X	ttputc(ctrans[color]);
X        cbcolor = color;
}
#endif
X
dg10move(row, col)
{
X	ttputc(16);
X        ttputc(col);
X	ttputc(row);
}
X
dg10eeol()
{
X        ttputc(11);
}
X
dg10eeop()
{
#if	COLOR
X	dg10fcol(gfcolor);
X	dg10bcol(gbcolor);
#endif
X        ttputc(ESC);
X        ttputc(0106);
X        ttputc(0106);
}
X
dg10rev(state)		/* change reverse video state */
X
int state;	/* TRUE = reverse, FALSE = normal */
X
{
#if	COLOR
X	if (state == TRUE) {
X		dg10fcol(0);
X		dg10bcol(7);
X	}
#else
X	ttputc(ESC);
X	ttputc(state ? 0104: 0105);
#endif
}
X
dg10cres()	/* change screen resolution */
X
{
X	return(TRUE);
}
X
spal()		/* change palette string */
X
{
X	/*	Does nothing here	*/
}
X
dg10beep()
{
X        ttputc(BEL);
X        ttflush();
}
X
dg10open()
{
X	strcpy(sres, "NORMAL");
X	revexist = TRUE;
X        ttopen();
}
X
dg10close()
X
{
#if	COLOR
X	dg10fcol(7);
X	dg10bcol(0);
#endif
X	ttclose();
}
X
dg10kopen()
X
{
}
X
dg10kclose()
X
{
}
X
#if	FLABEL
fnclabel(f, n)		/* label a function key */
X
int f,n;	/* default flag, numeric argument [unused] */
X
{
X	/* on machines with no function keys...don't bother */
X	return(TRUE);
}
#endif
#else
dg10hello()
{
}
#endif
SHAR_EOF
chmod 0444 dg10.c ||
echo 'restore of dg10.c failed'
Wc_c="`wc -c < 'dg10.c'`"
test 3333 -eq "$Wc_c" ||
	echo 'dg10.c: original size 3333, current size' "$Wc_c"
# ============= display.c ==============
echo 'x - extracting display.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'display.c' &&
/*
X * The functions in this file handle redisplay. There are two halves, the
X * ones that update the virtual display screen, and the ones that make the
X * physical display screen the same as the virtual display screen. These
X * functions use hints that are left in the windows by the commands.
X *
X */
X
X
#include        <stdio.h>
#include        <varargs.h>
#include	"estruct.h"
#include        "edef.h"
#if UNIX
#include <signal.h>
#include <termio.h>
#if ODT
#include <sys/types.h>
#include <sys/stream.h>
#include <sys/ptem.h>
#endif
#endif
X
typedef struct  VIDEO {
X        int	v_flag;                 /* Flags */
#if	COLOR
X	int	v_fcolor;		/* current forground color */
X	int	v_bcolor;		/* current background color */
X	int	v_rfcolor;		/* requested forground color */
X	int	v_rbcolor;		/* requested background color */
#endif
X	/* allocate 4 bytes here, and malloc 4 bytes less than we need,
X		to keep malloc from rounding up. */
X        char    v_text[4];              /* Screen data. */
}       VIDEO;
X
#define VFCHG   0x0001                  /* Changed flag			*/
#define	VFEXT	0x0002			/* extended (beyond column 80)	*/
#define	VFREV	0x0004			/* reverse video status		*/
#define	VFREQ	0x0008			/* reverse video request	*/
#define	VFCOL	0x0010			/* color change requested	*/
X
VIDEO   **vscreen;                      /* Virtual screen. */
#if	! MEMMAP
VIDEO   **pscreen;                      /* Physical screen. */
#endif
X
X
int displaying = FALSE;
#ifdef SIGWINCH
/* for window size changes */
int chg_width, chg_height;
#endif
X
/*
X * Initialize the data structures used by the display code. The edge vectors
X * used to access the screens are set up. The operating system's terminal I/O
X * channel is set up. All the other things get initialized at compile time.
X * The original window has "WFCHG" set, so that it will get completely
X * redrawn on the first call to "update".
X */
vtinit()
{
X    register int i;
X    register VIDEO *vp;
X
X    TTopen();		/* open the screen */
X    TTkopen();		/* open the keyboard */
X    TTrev(FALSE);
X    vscreen = (VIDEO **) malloc(term.t_mrow*sizeof(VIDEO *));
X
X    if (vscreen == NULL)
X        exit(1);
X
#if	! MEMMAP
X    pscreen = (VIDEO **) malloc(term.t_mrow*sizeof(VIDEO *));
X
X    if (pscreen == NULL)
X        exit(1);
#endif
X
X    for (i = 0; i < term.t_mrow; ++i) {
X    	/* struct VIDEO already has 4 of the bytes */
X        vp = (VIDEO *) malloc(sizeof(struct VIDEO) + term.t_mcol - 4);
X
X        if (vp == NULL)
X            exit(1);
X
X	vp->v_flag = 0;
#if	COLOR
X	vp->v_rfcolor = 7;
X	vp->v_rbcolor = 0;
#endif
X        vscreen[i] = vp;
#if	! MEMMAP
X    	/* struct VIDEO already has 4 of the bytes */
X        vp = (VIDEO *) malloc(sizeof(struct VIDEO) + term.t_mcol - 4);
X
X        if (vp == NULL)
X            exit(1);
X
X	vp->v_flag = 0;
X        pscreen[i] = vp;
#endif
X        }
}
X
/*
X * Clean up the virtual terminal system, in anticipation for a return to the
X * operating system. Move down to the last line and advance, to make room
X * for the system prompt. Shut down the channel to the
X * terminal.
X */
vttidy(f)
{
X	ttclean(f);	/* does it all now */
}
X
/*
X * Set the virtual cursor to the specified row and column on the virtual
X * screen. There is no checking for nonsense values.
X */
vtmove(row, col)
{
X    vtrow = row;
X    vtcol = col;
}
X
/* Write a character to the virtual screen. The virtual row and
X   column are updated. If we are not yet on left edge, don't print
X   it yet. If the line is too long put a ">" in the last column.
X   This routine only puts printing characters into the virtual
X   terminal buffers. Only column overflow is checked.
*/
X
vtputc(c,list)
int c,list;
{
X	register VIDEO *vp;	/* ptr to line being updated */
X
X	vp = vscreen[vtrow];
X
X	if (c == '\t' && !list) {
X		do {
X			vtputc(' ',FALSE);
X		} while (((vtcol + taboff)&TABMASK) != 0);
X	} else if (c == '\n' && !list) {
X		return;
X	} else if (vtcol >= term.t_ncol) {
X		++vtcol;
X		vp->v_text[term.t_ncol - 1] = '>';
X	} else if (!isprint(c)) {
X		vtputc('^',FALSE);
X		vtputc(toalpha(c),FALSE);
X	} else {
X		if (vtcol >= 0)
X			vp->v_text[vtcol] = c;
X		++vtcol;
X	}
}
X
vtgetc(col)
{
X	return vscreen[vtrow]->v_text[col];
}
X
vtputsn(s,n)
char *s;
{
X	int c;
X	while (n-- && (c = *s++) != 0)
X		vtputc(c,FALSE);
}
X
/*
X * Erase from the end of the software cursor to the end of the line on which
X * the software cursor is located.
X */
vteeol()
{
X    while (vtcol < term.t_ncol)
X        vtputc(' ',FALSE);
}
X
/* upscreen:	user routine to force a screen update
X		always finishes complete update		*/
upscreen(f, n)
{
X	update(TRUE);
X	return(TRUE);
}
X
int scrflags;
/*
X * Make sure that the display is right. This is a three part process. First,
X * scan through all of the windows looking for dirty ones. Check the framing,
X * and refresh the screen. Second, make sure that "currow" and "curcol" are
X * correct for the current window. Third, make the virtual and physical
X * screens the same.
X */
update(force)
int force;	/* force update past type ahead? */
{
X	register WINDOW *wp;
X	int screencol;
X
#if	TYPEAH
X	if (force == FALSE && typahead())
X		return(SORTOFTRUE);
#endif
#if	VISMAC == 0
X	if (force == FALSE && (kbdmode == PLAY || dotcmdmode == PLAY))
X		return(TRUE);
#endif
X
X	displaying = TRUE;
X
X	/* first, propagate mode line changes to all instances of
X		a buffer displayed in more than one window */
X	wp = wheadp;
X	while (wp != NULL) {
X		if (wp->w_flag & WFMODE) {
X			if (wp->w_bufp->b_nwnd > 1) {
X				/* make sure all previous windows have this */
X				register WINDOW *owp;
X				owp = wheadp;
X				while (owp != NULL) {
X					if (owp->w_bufp == wp->w_bufp)
X						owp->w_flag |= WFMODE;
X					owp = owp->w_wndp;
X				}
X			}
X		}
X		wp = wp->w_wndp;
X	}
X
X	/* update any windows that need refreshing */
X	wp = wheadp;
X	while (wp != NULL) {
X		if (wp->w_flag) {
X			/* if the window has changed, service it */
X			reframe(wp);	/* check the framing */
X			if (wp->w_flag & (WFKILLS|WFINS)) {
X				scrflags |= (wp->w_flag & (WFINS|WFKILLS));
X				wp->w_flag &= ~(WFKILLS|WFINS);
X			}
X			if ((wp->w_flag & ~(/* WFMOVE| */WFMODE)) == WFEDIT)
X				updone(wp);	/* update EDITed line */
X			else if (wp->w_flag & ~(WFMOVE))
X				updall(wp);	/* update all lines */
X			if (scrflags || (wp->w_flag & WFMODE))
X				modeline(wp);	/* update modeline */
X			wp->w_flag = 0;
X			wp->w_force = 0;
X		}
X		/* on to the next window */
X		wp = wp->w_wndp;
X	}
X
X	/* recalc the current hardware cursor location */
X	screencol = updpos();
X
#if	MEMMAP
X	/* update the cursor and flush the buffers */
X	movecursor(currow, screencol);
#endif
X
X	/* check for lines to de-extend */
X	upddex();
X
#if	NeWS
X	newsupd(force) ;
#else
X	/* if screen is garbage, re-plot it */
X	if (sgarbf)
X		updgar();
X
X	/* update the virtual screen to the physical screen */
X	updupd(force);
#endif
X
X	/* update the cursor and flush the buffers */
X	movecursor(currow, screencol);
X	TTflush();
X	displaying = FALSE;
#if SIGWINCH
X	while (chg_width || chg_height)
X		newscreensize(chg_height,chg_width);
#endif
X	return(TRUE);
}
X
/*	reframe:	check to see if the cursor is on in the window
X			and re-frame it if needed or wanted		*/
reframe(wp)
WINDOW *wp;
{
X	register LINE *lp;
X	register int i;
X
X	/* if not a requested reframe, check for a needed one */
X	if ((wp->w_flag & WFFORCE) == 0) {
#if SCROLLCODE
X		/* loop from one line above the window to one line after */
X		lp = lback(wp->w_linep);
X		for (i = -1; i <= wp->w_ntrows; i++)
#else
X		/* loop through the window */
X		lp = wp->w_linep;
X		for (i = 0; i < wp->w_ntrows; i++)
#endif
X		{
X
X			/* if the line is in the window, no reframe */
X			if (lp == wp->w_dotp) {
#if SCROLLCODE
X				/* if not _quite_ in, we'll reframe gently */
X				if ( i < 0 || i == wp->w_ntrows) {
X					/* if the terminal can't help, then
X						we're simply outside */
X					if (term.t_scroll == NULL)
X						i = wp->w_force;
X					break;
X				}
#endif
X				return(TRUE);
X			}
X
X			/* if we are at the end of the file, reframe */
X			if (i >= 0 && lp == wp->w_bufp->b_linep)
X				break;
X
X			/* on to the next line */
X			lp = lforw(lp);
X		}
X	}
X
#if SCROLLCODE
X	if (i == -1) {	/* we're just above the window */
X		i = 1;	/* put dot at first line */
X		scrflags |= WFINS;
X	} else if (i == wp->w_ntrows) { /* we're just below the window */
X		i = -1;	/* put dot at last line */
X		scrflags |= WFKILLS;
X	} else /* put dot where requested */
#endif
X		i = wp->w_force;  /* (is 0, unless reposition() was called) */
X
X	wp->w_flag |= WFMODE;
X	
X	/* w_force specifies which line of the window dot should end up on */
X	/* 	positive --> lines from the top				*/
X	/* 	negative --> lines from the bottom			*/
X	/* 	zero --> middle of window				*/
X	
X	/* enforce some maximums */
X	if (i > 0) {
X		if (--i >= wp->w_ntrows)
X			i = wp->w_ntrows - 1;
X	} else if (i < 0) {	/* negative update???? */
X		i += wp->w_ntrows;
X		if (i < 0)
X			i = 0;
X	} else
X		i = wp->w_ntrows / 2;
X
X	/* backup to new line at top of window */
X	lp = wp->w_dotp;
X	while (i != 0 && lback(lp) != wp->w_bufp->b_linep) {
X		--i;
X		lp = lback(lp);
X	}
X
X	if (lp == wp->w_bufp->b_linep)
X		lp = lback(lp);
X		
X	/* and reset the current line-at-top-of-window */
X	wp->w_linep = lp;
X	wp->w_flag |= WFHARD;
X	wp->w_flag &= ~WFFORCE;
X	return(TRUE);
}
X
/*	updone:	update the current line	to the virtual screen		*/
X
updone(wp)
WINDOW *wp;	/* window to update current line in */
{
X	register LINE *lp;	/* line to update */
X	register int sline;	/* physical screen line to update */
X
X	/* search down the line we want */
X	lp = wp->w_linep;
X	sline = wp->w_toprow;
X	while (lp != wp->w_dotp) {
X		++sline;
X		lp = lforw(lp);
X	}
X
X	l_to_vline(wp,lp,sline);
X	vteeol();
}
X
/*	updall:	update all the lines in a window on the virtual screen */
X
updall(wp)
WINDOW *wp;	/* window to update lines in */
{
X	register LINE *lp;	/* line to update */
X	register int sline;	/* physical screen line to update */
X
X	/* search down the lines, updating them */
X	lp = wp->w_linep;
X	sline = wp->w_toprow;
X	while (sline < wp->w_toprow + wp->w_ntrows) {
X		l_to_vline(wp,lp,sline);
X		vteeol();
X		if (lp != wp->w_bufp->b_linep)
X			lp = lforw(lp);
X		++sline;
X	}
X
}
X
/* line to virtual screen line */
l_to_vline(wp,lp,sline)
WINDOW *wp;	/* window to update lines in */
LINE *lp;
{
X	int i,c;
X
X	/* and update the virtual line */
X	vscreen[sline]->v_flag |= VFCHG;
X	vscreen[sline]->v_flag &= ~VFREQ;
X	if (wp->w_sideways)
X		taboff = wp->w_sideways;
X	if (lp != wp->w_bufp->b_linep) {
X		vtmove(sline, -wp->w_sideways);
X		i = 0;
X		while ( i < llength(lp) ) {
X			vtputc(lgetc(lp, i), wp->w_bufp->b_mode & MDLIST);
X			++i;
X		}
X		vtputc('\n', wp->w_bufp->b_mode & MDLIST);
X		if (wp->w_sideways) {
X			vscreen[sline]->v_text[0] = '<';
X			if (vtcol < 1) vtcol = 1;
X		}
X	} else {
X		vtmove(sline, 0);
X		vtputc('~',FALSE);
X	}
X	taboff = 0;
#if	COLOR
X	vscreen[sline]->v_rfcolor = wp->w_fcolor;
X	vscreen[sline]->v_rbcolor = wp->w_bcolor;
#endif
}
X
/*	updpos:	update the position of the hardware cursor and handle extended
X		lines. This is the only update for simple moves.
X		returns the screen column for the cursor	*/
updpos()
{
X	register LINE *lp;
X	register int c;
X	register int i;
X
X	/* find the current row */
X	lp = curwp->w_linep;
X	currow = curwp->w_toprow;
X	while (lp != curwp->w_dotp) {
X		++currow;
X		lp = lforw(lp);
X		if (lp == curwp->w_linep) {
X			mlwrite("Bug:  lost dot updpos().  setting at top");
X			curwp->w_linep = curwp->w_dotp  = lforw(curbp->b_linep);
X			currow = curwp->w_toprow;
X		}
X	}
X
X	/* find the current column */
X	curcol = -curwp->w_sideways;
X	i = 0;
X	while (i < curwp->w_doto) {
X		c = lgetc(lp, i++);
X		if (((curwp->w_bufp->b_mode&MDLIST) == 0) && c == '\t') {
X			do {
X				curcol++;
X			} while (((curcol + curwp->w_sideways)&TABMASK) != 0);
X		} else {
X			if (!isprint(c))
X				++curcol;
X			++curcol;
X		}
X
X	}
X
X	/* if extended, flag so and update the virtual line image */
X	if (curcol >=  term.t_ncol - 1) {
X		return updext_past();
X	} else if (curwp->w_sideways && curcol < 1){
X		return updext_before();
X	} else {
X		return curcol;
X	}
}
X
/*	upddex:	de-extend any line that deserves it		*/
X
upddex()
{
X	register WINDOW *wp;
X	register LINE *lp;
X	register int i,j;
X
X	wp = wheadp;
X
X	while (wp != NULL) {
X		lp = wp->w_linep;
X		i = wp->w_toprow;
X
X		while (i < wp->w_toprow + wp->w_ntrows) {
X			if (vscreen[i]->v_flag & VFEXT) {
X				if ((wp != curwp) || (lp != wp->w_dotp) ||
X				   (curcol < term.t_ncol - 1)) {
X					l_to_vline(wp,lp,i);
X					vteeol();
X					/* this line no longer is extended */
X					vscreen[i]->v_flag &= ~VFEXT;
X				}
X			}
X			lp = lforw(lp);
X			++i;
X		}
X		/* and onward to the next window */
X		wp = wp->w_wndp;
X	}
}
X
/*	updgar:	if the screen is garbage, clear the physical screen and
X		the virtual screen and force a full update		*/
X
updgar()
{
X	register char *txt;
X	register int i,j;
X
X	for (i = 0; i < term.t_nrow; ++i) {
X		vscreen[i]->v_flag |= VFCHG;
#if	REVSTA
X		vscreen[i]->v_flag &= ~VFREV;
#endif
#if	COLOR
X		vscreen[i]->v_fcolor = gfcolor;
X		vscreen[i]->v_bcolor = gbcolor;
#endif
#if	! MEMMAP
X		txt = pscreen[i]->v_text;
X		for (j = 0; j < term.t_ncol; ++j)
X			txt[j] = ' ';
#endif
X	}
X
X	movecursor(0, 0);		 /* Erase the screen. */
X	(*term.t_eeop)();
X	sgarbf = FALSE;			 /* Erase-page clears */
X	mpresf = FALSE;			 /* the message area. */
#if	COLOR
X	mlerase();			/* needs to be cleared if colored */
#endif
}
X
/*	updupd:	update the physical screen from the virtual screen	*/
X
updupd(force)
int force;	/* forced update flag */
{
X	register VIDEO *vp1;
X	register int i;
#if SCROLLCODE
X	if (scrflags & WFKILLS)
X		scrolls(FALSE);
X	if (scrflags & WFINS)
X		scrolls(TRUE);
X	scrflags = 0;
#endif
X
X	for (i = 0; i < term.t_nrow; ++i) {
X		vp1 = vscreen[i];
X
X		/* for each line that needs to be updated*/
X		if ((vp1->v_flag & VFCHG) != 0) {
#if	TYPEAH
X			if (force == FALSE && typahead())
X				return(TRUE);
#endif
#if	MEMMAP
X			updateline(i, vp1);
#else
X			updateline(i, vp1, pscreen[i]);
#endif
X		}
X	}
X	return(TRUE);
}
X
#if SCROLLCODE
/* optimize out scrolls (line breaks, and newlines) */
/* arg. chooses between looking for inserts or deletes */
int	
scrolls(inserts)	/* returns true if it does something */
{
X	struct	VIDEO *vpv ;	/* virtual screen image */
X	struct	VIDEO *vpp ;	/* physical screen image */
X	int	i, j, k ;
X	int	rows, cols ;
X	int	first, match, count, ptarget, vtarget, end ;
X	int	longmatch, longcount;
X	int	from, to;
X
X	if (!term.t_scroll) /* no way to scroll */
X		return FALSE;
X
X	rows = term.t_nrow ;
X	cols = term.t_ncol ;
X
X	first = -1 ;
X	for (i = 0; i < rows; i++) {	/* find first wrong line */
X		if (!texttest(i,i)) {
X			first = i;
X			break;
X		}
X	}
X
X	if (first < 0)
X		return FALSE;		/* no text changes */
X
X	vpv = vscreen[first] ;
X	vpp = pscreen[first] ;
X
X	if (inserts) {
X		/* determine types of potential scrolls */
X		end = endofline(vpv->v_text,cols) ;
X		if ( end == 0 )
X			ptarget = first ;		/* newlines */
X		else if ( strncmp(vpp->v_text, vpv->v_text, end) == 0 )
X			ptarget = first + 1 ;	/* broken line newlines */
X		else 
X			ptarget = first ;
X	} else {
X		vtarget = first + 1 ;
X	}
X
X	/* find the matching shifted area */
X	match = -1 ;
X	longmatch = -1;
X	longcount = 0;
X	from = inserts ? ptarget : vtarget;
X	for (i = from+1; i < rows; i++) {
X		if (inserts ? texttest(i,from) : texttest(from,i) ) {
X			match = i ;
X			count = 1 ;
X			for (j=match+1, k=from+1; j<rows && k<rows; j++, k++) {
X				if (inserts ? texttest(j,k) : texttest(k,j))
X					count++ ;
X				else
X					break ;
X			}
X			if (longcount < count) {
X				longcount = count;
X				longmatch = match;
X			}
X		}
X	}
X	match = longmatch;
X	count = longcount;
X
X	if (!inserts) {
X		/* full kill case? */
X		if (match > 0 && texttest(first, match-1)) {
X			vtarget-- ;
X			match-- ;
X			count++ ;
X		}
X	}
X
X	/* do the scroll */
X	if (match>0 && count>2) {		 /* got a scroll */
X		/* move the count lines starting at ptarget to match */
X		/* mlwrite("scrolls: move the %d lines starting at %d to %d",
X						count,ptarget,match);
X		*/
X		if (inserts) {
X			from = ptarget;
X			to = match;
X		} else {
X			from = match;
X			to = vtarget;
X		}
X		scrscroll(from, to, count) ;
X		for (i = 0; i < count; i++) {
X			vpp = pscreen[to+i] ;
X			vpv = vscreen[to+i];
X			strncpy(vpp->v_text, vpv->v_text, cols) ;
X		}
X		if (inserts) {
X			from = ptarget;
X			to = match;
X		} else {
X			from = vtarget+count;
X			to = match+count;
X		}
X		for (i = from; i < to; i++) {
X			char *txt;
X			txt = pscreen[i]->v_text;
X			for (j = 0; j < term.t_ncol; ++j)
X				txt[j] = ' ';
X			vscreen[i]->v_flag |= VFCHG;
X		}
X		return(TRUE) ;
X	}
X	return(FALSE) ;
}
X
/* move the "count" lines starting at "from" to "to" */
scrscroll(from, to, count)
{
X	ttrow = ttcol = -1;
X	(*term.t_scroll)(from,to,count);
}
X
texttest(vrow,prow)		/* return TRUE on text match */
int	vrow, prow ;		/* virtual, physical rows */
{
struct	VIDEO *vpv = vscreen[vrow] ;	/* virtual screen image */
struct	VIDEO *vpp = pscreen[prow]  ;	/* physical screen image */
X
X	return (!memcmp(vpv->v_text, vpp->v_text, term.t_ncol)) ;
}
X
/* return the index of the first blank of trailing whitespace */
int	
endofline(s,n) 
char 	*s ;
{
int	i ;
X	for (i = n - 1; i >= 0; i--)
X		if (s[i] != ' ') return(i+1) ;
X	return(0) ;
}
X
#endif /* SCROLLCODE */
X
X
/*	updext_past: update the extended line which the cursor is currently
X		on at a column greater than the terminal width. The line
X		will be scrolled right or left to let the user see where
X		the cursor is		*/
updext_past()
{
X	register int lbound, rcursor;
X	register LINE *lp;	/* pointer to current line */
X	register int j;		/* index into line */
X
X	/* calculate what column the real cursor will end up in */
X	/* why is term.t_ncol in here? */
X	rcursor = ((curcol - term.t_ncol) % term.t_scrsiz) + term.t_margin;
X	lbound = curcol - rcursor;
X	taboff = lbound + curwp->w_sideways;
X
X	/* scan through the line outputing characters to the virtual screen */
X	/* once we reach the left edge					*/
X	vtmove(currow, -lbound-curwp->w_sideways);	/* start scanning offscreen */
X	lp = curwp->w_dotp;		/* line to output */
X	for (j = 0; j < llength(lp); ++j)
X		vtputc(lgetc(lp, j), curwp->w_bufp->b_mode&MDLIST);
X	vtputc('\n', curwp->w_bufp->b_mode&MDLIST);
X
X	/* truncate the virtual line, restore tab offset */
X	vteeol();
X	taboff = 0;
X
X	/* and put a '<' in column 1 */
X	vscreen[currow]->v_text[0] = '<';
X	vscreen[currow]->v_flag |= (VFEXT | VFCHG);
X	return rcursor;
}
X
/*	updext_before: update the extended line which the cursor is currently
X		on at a column less than the terminal width. The line
X		will be scrolled right or left to let the user see where
X		the cursor is		*/
updext_before()
{
X	register int lbound, rcursor;
X	register LINE *lp;	/* pointer to current line */
X	register int j;		/* index into line */
X
X	/* calculate what column the real cursor will end up in */
X	rcursor = (curcol % (term.t_ncol-term.t_margin));
X	lbound = curcol - rcursor + 1;
X	taboff = lbound;
X
X	/* scan through the line outputing characters to the virtual screen */
X	/* once we reach the left edge					*/
X	vtmove(currow, -lbound);	/* start scanning offscreen */
X	lp = curwp->w_dotp;		/* line to output */
X	for (j = 0; j < llength(lp); ++j)
X		vtputc(lgetc(lp, j), curwp->w_bufp->b_mode&MDLIST);
X	vtputc('\n', curwp->w_bufp->b_mode&MDLIST);
X
X	/* truncate the virtual line, restore tab offset */
X	vteeol();
X	taboff = 0;
X
X	/* and put a '<' in column 1 */
X	vscreen[currow]->v_text[0] = '<';
X	vscreen[currow]->v_flag |= (VFEXT | VFCHG);
X	return rcursor;
}
X
X
#if	NeWS
newsupd(force)	/* update the physical screen from the virtual screen */
int force;	/* forced update flag */
{
register int i ;
struct	VIDEO *vpv ;	/* virtual screen image */
struct	VIDEO *vpp ;	/* physical screen image */
int	bad, badcol, rows ;
X
X	rows = term.t_nrow ;
X
X	if (force == FALSE && typahead()) return ;
X	if (sgarbf) {
X		fastupdate() ;
X		return ;
X	}
X
X	/* if enough lines are bad try to optimize scrolls/kills */	
X	for (bad = 0, i = 0; i < rows; ++i)
X		if (!texttest(i,i)) {
X			bad++ ;
X			if (bad > 3) {
X				if (!scrolls()) kills() ;
X				break ;
X			}
X		}
X
X	/* count bad lines, if enough need fixed redo whole screen */
X	for (bad = 0, badcol = 0, i = 0; i < rows; ++i) {
X		vpv = vscreen[i] ;
X		vpv->v_flag &= ~(VFCHG|VFCOL) ;		/* clear flag */
X		if (!texttest(i,i)) {
X			vpv->v_flag |= VFCHG ;
X			bad++ ;
X		}
X		if (!colortest(i)) {
X			vpv->v_flag |= VFCOL ;
X			badcol++  ;
X		}
X	}
X	if (bad == 0 && badcol > 0) {	/* pure color update */
X		colorupdate() ;
X		return ;
X	}
X	if (bad > (3*rows)/4) {		/* full update */
X		fastupdate() ;
X		return ;
X	}
X
X	/* Fix the bad lines one by one */
X	for (i = 0; i < rows; ++i)
X		if (vscreen[i]->v_flag & (VFCHG|VFCOL)) updateline(i) ;
}
X
X
/* optimize out scrolls (line breaks, and newlines) */
int	scrolls()	/* returns true if it does something */
{
struct	VIDEO *vpv ;	/* virtual screen image */
struct	VIDEO *vpp ;	/* physical screen image */
int	i, j, k ;
int	rows, cols ;
int	first, match, count, ptarget, end ;
X
X	rows = term.t_nrow ;
X	cols = term.t_ncol ;
X
X	first = -1 ;
X	for (i = 0; i < rows; i++)	/* find first wrong line */
X		if (!texttest(i,i)) {first = i ; break ;}
X
X	if (first < 0) return(FALSE) ;		/* no text changes */
X
X	vpv = vscreen[first] ;
X	vpp = pscreen[first] ;
X
X	/* determine types of potential scrolls */
X	end = endofline(vpv->v_text,cols) ;
X	if ( end == 0 )
X		ptarget = first ;		/* newlines */
X	else if ( strncmp(vpp->v_text, vpv->v_text, end) == 0 )
X		ptarget = first + 1 ;	/* broken line newlines */
X	else return(FALSE) ;			/* no scrolls */
X
X	/* find the matching shifted area */
X	match = -1 ;
X	for (i = ptarget+1; i < rows; i++) {
X		if (texttest(i, ptarget)) {
X			match = i ;
X			count = 1 ;
X			for (j=match+1, k=ptarget+1; j<rows && k<rows; j++, k++) {
X				if (texttest(j,k))
X					count++ ;
X				else
X					break ;
X			}
X			break ;
X		}
X	}
X
X	/* do the scroll */
X	if (match>0 && count>2) {		 /* got a scroll */
X		newsscroll(ptarget, match, count) ;
X		for (i = 0; i < count; i++) {
X			vpv = vscreen[match+i] ; vpp = pscreen[match+i] ;
X			strncpy(vpp->v_text, vpv->v_text, cols) ;
X		}
X		return(TRUE) ;
X	}
X	return(FALSE) ;
}
X
X
/* optimize out line kills (full and with a partial kill) */
int	kills()		/* returns true if it does something */
{
struct	VIDEO *vpv ;	/* virtual screen image */
struct	VIDEO *vpp ;	/* physical screen image */
int	i, j, k ;
int	rows, cols ;
int	first, match, count, vtarget, end ;
X
X	rows = term.t_nrow ;
X	cols = term.t_ncol ;
X
X	first = -1 ;
X	for (i = 0; i < rows; i++)	/* find first wrong line */
X		if (!texttest(i,i)) {first = i ; break ;}
X
X	if (first < 0) return(FALSE) ;		/* no text changes */
X
X	vpv = vscreen[first] ;
X	vpp = pscreen[first] ;
X
X	vtarget = first + 1 ;
X
X	/* find the matching shifted area */
X	match = -1 ;
X	for (i = vtarget+1; i < rows; i++) {
X		if (texttest(vtarget, i)) {
X			match = i ;
X			count = 1 ;
X			for (j=match+1, k=vtarget+1; j<rows && k<rows; j++, k++) {
X				if (texttest(k,j))
X					count++ ;
X				else
X					break ;
X			}
X			break ;
X		}
X	}
X	if (texttest(first, match-1)) {		/* full kill case */
X		vtarget-- ;
X		match-- ;
X		count++ ;
X	}
X
X	/* do the scroll */
X	if (match>0 && count>2) {		/* got a scroll */
X		newsscroll(match, vtarget, count) ;
X		for (i = 0; i < count; i++) {
X			vpv = vscreen[vtarget+i] ; vpp = pscreen[vtarget+i] ;
X			strncpy(vpp->v_text, vpv->v_text, cols) ;
X		}
X		return(TRUE) ;
X	}
X	return(FALSE) ;
}
X
X
texttest(vrow,prow)		/* return TRUE on text match */
int	vrow, prow ;		/* virtual, physical rows */
{
struct	VIDEO *vpv = vscreen[vrow] ;	/* virtual screen image */
struct	VIDEO *vpp = pscreen[prow]  ;	/* physical screen image */
X
X	vpp->v_text[term.t_ncol] = 0 ;
X	vpv->v_text[term.t_ncol] = 0 ;
X	return (!strncmp(vpv->v_text, vpp->v_text, term.t_ncol)) ;
}
X
colortest(row)			/* TRUE on color match */
int	row ;	
{
struct	VIDEO *vpv = vscreen[row] ;	/* virtual screen image */
X
X	return (vpv->v_fcolor == vpv->v_rfcolor &&
X		vpv->v_bcolor == vpv->v_rbcolor) ;
}
X
X
updateline(row)
int	row ;		/* row of screen to update */
{
struct	VIDEO *vpv = vscreen[row] ;	/* virtual screen image */
struct	VIDEO *vpp = pscreen[row]  ;	/* physical screen image */
int	end ;
X
X	end = endofline(vpv->v_text, term.t_ncol) ;
X	strncpy(vpp->v_text, vpv->v_text, term.t_ncol) ;
X	vpv->v_text[end] = 0 ;
X	newsputline(row, vpv->v_text, vpv->v_rfcolor, vpv->v_rbcolor) ;
X	vpv->v_text[end] = ' ' ;
X	vpv->v_fcolor = vpv->v_rfcolor;
X	vpv->v_bcolor = vpv->v_rbcolor;
X	vpv->v_flag &= ~(VFCHG|VFCOL);	/* clear flag */
}
X
X
colorupdate()
{
struct	VIDEO *vpv ;	/* virtual screen image */
int	row ;
X	
X	for (row=0; row<term.t_nrow; row++) {	/* send the row colors */
X		vpv = vscreen[row] ;
X		if (vpv->v_flag & VFCOL) {
X			newssetrowcolors(row, vpv->v_rfcolor, vpv->v_rbcolor) ;
X			vpv->v_fcolor = vpv->v_rfcolor;
X			vpv->v_bcolor = vpv->v_rbcolor;
X		}
X		vpv->v_flag &= ~VFCOL ;
X	}
X
X	newslocalupdate() ;	/* ask for a screen refresh */
}
X
X
fastupdate()		/* redo the entire screen fast */
{
int	row ;
register char	*cp, *first ;
struct	VIDEO *vpv ;	/* virtual screen image */
struct	VIDEO *vpp ;	/* physical screen image */
X
X	/* send the row colors */
X	for (row=0; row<term.t_nrow; row++) {
X		vpv = vscreen[row] ;
X		if (!colortest(row)) {
X			newssetrowcolors(row, vpv->v_rfcolor, vpv->v_rbcolor) ;
X			vpv->v_fcolor = vpv->v_rfcolor;
X			vpv->v_bcolor = vpv->v_rbcolor;
X		}
X		vpv->v_flag &= ~VFCOL ;
X	}
X
X	/* virtual -> physical buffer */
X	for (row=0; row<term.t_nrow; row++) {
X		vpv = vscreen[row] ; vpp = pscreen[row] ;
X		memcpy(vpp->v_text, vpv->v_text, term.t_ncol);
X		vpp->v_text[term.t_ncol] = 0 ;
X		vpv->v_text[term.t_ncol] = 0 ;
X		vpv->v_flag &= ~VFCHG;
X	}
X	/* send the stuff */
X	newscls() ;
X	for (row=0; row<term.t_nrow; row++) {
X		first = pscreen[row]->v_text ;
X		/* don't send trailing blanks */
X		cp = &first[endofline(first,term.t_ncol)] ;
X		if (cp > first) {
X			*cp = 0 ;
X			newsfastputline(row, first) ;
X			*cp = ' ' ;
X		}
X	}
X	sgarbf = FALSE;
}
X 
X
/* return the index of the first blank of trailing whitespace */
int	endofline(s,n) 
char 	*s ;
{
int	i ;
X	for (i = n - 1; i >= 0; i--)
X		if (s[i] != ' ') return(i+1) ;
X	return(0) ;
}
#else
X
/*
X * Update a single line. This does not know how to use insert or delete
X * character sequences; we are using VT52 functionality. Update the physical
X * row and column variables. It does try an exploit erase to end of line. The
X * RAINBOW version of this routine uses fast video.
X */
#if	MEMMAP
/*	UPDATELINE specific code for the IBM-PC and other compatables */
X
updateline(row, vp1)
X
int row;		/* row of screen to update */
struct VIDEO *vp1;	/* virtual screen image */
X
{
#if	COLOR
X	scwrite(row, vp1->v_text, vp1->v_rfcolor, vp1->v_rbcolor);
X	vp1->v_fcolor = vp1->v_rfcolor;
X	vp1->v_bcolor = vp1->v_rbcolor;
#else
X	if (vp1->v_flag & VFREQ)
X		scwrite(row, vp1->v_text, 0, 7);
X	else
X		scwrite(row, vp1->v_text, 7, 0);
#endif
X	vp1->v_flag &= ~(VFCHG | VFCOL);	/* flag this line as changed */
X
}
X
#else
X
updateline(row, vp1, vp2)
X
int row;		/* row of screen to update */
struct VIDEO *vp1;	/* virtual screen image */
struct VIDEO *vp2;	/* physical screen image */
X
{
#if RAINBOW
/*	UPDATELINE specific code for the DEC rainbow 100 micro	*/
X
X    register char *cp1;
X    register char *cp2;
X    register int nch;
X
X    /* since we don't know how to make the rainbow do this, turn it off */
X    flags &= (~VFREV & ~VFREQ);
X
X    cp1 = &vp1->v_text[0];                    /* Use fast video. */
X    cp2 = &vp2->v_text[0];
X    putline(row+1, 1, cp1);
X    nch = term.t_ncol;
X
X    do
X        {
X        *cp2 = *cp1;
X        ++cp2;
X        ++cp1;
X        }
X    while (--nch);
X    *flags &= ~VFCHG;
#else
/*	UPDATELINE code for all other versions		*/
X
X	register char *cp1;
X	register char *cp2;
X	register char *cp3;
X	register char *cp4;
X	register char *cp5;
X	register int nbflag;	/* non-blanks to the right flag? */
X	int rev;		/* reverse video flag */
X	int req;		/* reverse video request flag */
X
X
X	/* set up pointers to virtual and physical lines */
X	cp1 = &vp1->v_text[0];
X	cp2 = &vp2->v_text[0];
X
#if	COLOR
X	TTforg(vp1->v_rfcolor);
X	TTbacg(vp1->v_rbcolor);
#endif
X
#if	REVSTA | COLOR
X	/* if we need to change the reverse video status of the
X	   current line, we need to re-write the entire line     */
X	rev = (vp1->v_flag & VFREV) == VFREV;
X	req = (vp1->v_flag & VFREQ) == VFREQ;
X	if ((rev != req)
#if	COLOR
X	    || (vp1->v_fcolor != vp1->v_rfcolor) || (vp1->v_bcolor != vp1->v_rbcolor)
#endif
#if	HP150
X	/* the HP150 has some reverse video problems */
X	    || req || rev
#endif
X			) {
X		movecursor(row, 0);	/* Go to start of line. */
X		/* set rev video if needed */
X		if (rev != req)
X			(*term.t_rev)(req);
X
X		/* scan through the line and dump it to the screen and
X		   the virtual screen array				*/
X		cp3 = &vp1->v_text[term.t_ncol];
X		while (cp1 < cp3) {
X			TTputc(*cp1);
X			++ttcol;
X			*cp2++ = *cp1++;
X		}
X		/* turn rev video off */
X		if (rev != req)
X			(*term.t_rev)(FALSE);
X
X		/* update the needed flags */
X		vp1->v_flag &= ~VFCHG;
X		if (req)
X			vp1->v_flag |= VFREV;
X		else
X			vp1->v_flag &= ~VFREV;
#if	COLOR
X		vp1->v_fcolor = vp1->v_rfcolor;
X		vp1->v_bcolor = vp1->v_rbcolor;
#endif
X		return(TRUE);
X	}
#endif
X
X	/* advance past any common chars at the left */
X	while (cp1 != &vp1->v_text[term.t_ncol] && *cp1 == *cp2) {
X		++cp1;
X		++cp2;
X	}
X
/* This can still happen, even though we only call this routine on changed
X * lines. A hard update is always done when a line splits, a massive
X * change is done, or a buffer is displayed twice. This optimizes out most
X * of the excess updating. A lot of computes are used, but these tend to
X * be hard operations that do a lot of update, so I don't really care.
X */
X	/* if both lines are the same, no update needs to be done */
X	if (cp1 == &vp1->v_text[term.t_ncol]) {
X 		vp1->v_flag &= ~VFCHG;		/* flag this line is changed */
X		return(TRUE);
X	}
X
X	/* find out if there is a match on the right */
X	nbflag = FALSE;
X	cp3 = &vp1->v_text[term.t_ncol];
X	cp4 = &vp2->v_text[term.t_ncol];
X
X	while (cp3[-1] == cp4[-1]) {
X		--cp3;
X		--cp4;
X		if (cp3[0] != ' ')		/* Note if any nonblank */
X			nbflag = TRUE;		/* in right match. */
X	}
X
X	cp5 = cp3;
X
X	/* Erase to EOL ? */
X	if (nbflag == FALSE && eolexist == TRUE && (req != TRUE)) {
X		while (cp5!=cp1 && cp5[-1]==' ')
X			--cp5;
X
X		if (cp3-cp5 <= 3)		/* Use only if erase is */
X			cp5 = cp3;		/* fewer characters. */
X	}
X
X	movecursor(row, cp1 - &vp1->v_text[0]);	/* Go to start of line. */
#if	REVSTA
X	TTrev(rev);
#endif
X
X	while (cp1 != cp5) {		/* Ordinary. */
X		TTputc(*cp1);
X		++ttcol;
X		*cp2++ = *cp1++;
X	}
X
X	if (cp5 != cp3) {		/* Erase. */
X		TTeeol();
X		while (cp1 != cp3)
X			*cp2++ = *cp1++;
X	}
#if	REVSTA
X	TTrev(FALSE);
#endif
X	vp1->v_flag &= ~VFCHG;		/* flag this line as updated */
X	return(TRUE);
#endif
}
#endif
X
#endif  /* NeWS */
X
/*
X * Redisplay the mode line for the window pointed to by the "wp". This is the
X * only routine that has any idea of how the modeline is formatted. You can
X * change the modeline format by hacking at this routine. Called by "update"
X * any time there is a dirty window.
X */
modeline(wp)
WINDOW *wp;
{
X	register int n;
X	register BUFFER *bp;
X	register lchar;		/* character to draw line in buffer with */
X
X	n = wp->w_toprow+wp->w_ntrows;      	/* Location. */
X	vscreen[n]->v_flag |= VFCHG | VFREQ | VFCOL;/* Redraw next time. */
X
#if	NeWS
X	vscreen[n]->v_rfcolor = 0;
X	vscreen[n]->v_rbcolor = 7;
X	if (wp == curwp) {			/* mark the current buffer */
X		lchar = '^' ;
X	} else {
X		lchar = ' ' ;
X	}
X	vtmove(n, 0);                      	/* Seek to right line. */
#else
X
#if	COLOR
X	vscreen[n]->v_rfcolor = 0;			/* black on */
X	vscreen[n]->v_rbcolor = 7;			/* white.....*/
#endif
X	vtmove(n, 0);                       	/* Seek to right line. */
X	if (wp == curwp) {				/* mark the current buffer */
X		lchar = '=';
X	} else {
#if	REVSTA
X		if (revexist)
X			lchar = ' ';
X		else
#endif
X			lchar = '-';
#endif
X	}
X	bp = wp->w_bufp;
X
X	vtputc(lchar,FALSE);
X	vtputc(' ',FALSE);
X	vtputsn(bp->b_bname, NBUFN);
X	if (bp->b_mode&MDVIEW)
X		vtputsn(" [view only]", 20);
X	if (bp->b_mode&MDDOS)
X		vtputsn(" [dos-style]", 20);
X	if (bp->b_flag&BFCHG)
X		vtputsn(" [modified]", 20);
X	/* don't print a filename if they're the same, 
X		or the filename is null */
X	if (strcmp(bp->b_fname,bp->b_bname)) {
X		if (bp->b_fname[0] != '\0') {
X			if (isspace(bp->b_fname[0])) {
X				/* some of the internally generated buffers
X					put other info. in filename slot */
X				vtputsn(bp->b_fname, NFILEN);
X			} else {
X				if (ispunct(bp->b_fname[0]))
X					vtputsn(" is \"", 20);
X				else
X					vtputsn(" is file \"", 20);
X				vtputsn(bp->b_fname, NFILEN);
X				vtputsn("\"", 20);
X			}
X		}
X	}
X	vtputc(' ',FALSE);
X
X
X	/* Pad to full width, then go back and overwrite right-end info */
X	n = term.t_ncol;
X	while (vtcol < n)
X		vtputc(lchar,FALSE);
X		
X	{ /* determine if top line, bottom line, or both are visible */
X		LINE *lp = wp->w_linep;
X		int rows = wp->w_ntrows;
X		char *msg = NULL;
X		
X		vtcol = n - 7;  /* strlen(" top ") plus a couple */
X		while (rows--) {
X			lp = lforw(lp);
X			if (lp == wp->w_bufp->b_linep) {
X				msg = " bot ";
X				break;
X			}
X		}
X		if (lback(wp->w_linep) == wp->w_bufp->b_linep) {
X			if (msg) {
X				if (wp->w_linep == wp->w_bufp->b_linep)
X					msg = " emp ";
X				else 
X					msg = " all ";
X			} else {
X				msg = " top ";
X			}
X		}
X		if (!msg)
X			msg = " mid ";
X		vtputsn(msg,20);
X	}
X
X	if (vtgetc(80) == lchar) {
X		vtcol = 80;
X		vtputc('|',FALSE);
X	}
}
X
upmode()	/* update all the mode lines */
{
X	register WINDOW *wp;
X
#if     NeWS            /* tell workstation the current modes */
X        newsreportmodes() ;
#endif
X	wp = wheadp;
X	while (wp != NULL) {
X		wp->w_flag |= WFMODE;
X		wp = wp->w_wndp;
X	}
}
X
/*
X * Send a command to the terminal to move the hardware cursor to row "row"
X * and column "col". The row and column arguments are origin 0. Optimize out
X * random calls. Update "ttrow" and "ttcol".
X */
movecursor(row, col)
{
#if	! NeWS		/* "line buffered" */
X	if (row!=ttrow || col!=ttcol)
#endif
X        {
X	        ttrow = row;
X	        ttcol = col;
X	        TTmove(row, col);
X        }
}
X
X
X
#if	NeWS		/* buffer the message line stuff, newsputc is slow */
#define NEWSBUFSIZ	256
#undef	TTputc
#undef	TTflush
#define TTputc(c)	bufputc(c)
#define TTflush()	bufputc((char)0)
X
bufputc(c)
char	c ;
{
X	static		bufindex = 0 ;
X	static char	outbuf[NEWSBUFSIZ] ;
X
X	if (c == NULL || bufindex >= NEWSBUFSIZ || bufindex >= term.t_ncol) {
X		outbuf[bufindex] = NULL ;
X		newsputline(term.t_nrow, outbuf, 7, 0) ;
X		movecursor(term.t_nrow, strlen(outbuf)) ;
X		newsflush() ;
X		bufindex = 0 ;
X	}
X	else outbuf[bufindex++] = c ;
}
#endif
X
X
/*
X * Erase the message line. This is a special routine because the message line
X * is not considered to be part of the virtual screen. It always works
X * immediately; the terminal buffer is flushed via a call to the flusher.
X */
mlerase()
{
X    int i;
X    
X    if (mpresf == FALSE)
X		return;
X    movecursor(term.t_nrow, 0);
X    if (discmd == FALSE)
X    	return;
X
#if	COLOR
X     TTforg(7);
X     TTbacg(0);
#endif
X    if (eolexist == TRUE)
X	    TTeeol();
X    else {
X        for (i = 0; i < term.t_ncol - 1; i++)
X            TTputc(' ');
X        movecursor(term.t_nrow, 1);	/* force the move! */
X        movecursor(term.t_nrow, 0);
X    }
X    TTflush();
X    mpresf = FALSE;
}
X
X
X
X
#ifndef va_dcl	 /* then try these out */
X
typedef char *va_list;
#define va_dcl int va_alist;
#define va_start(list) list = (char *) &va_alist
#define va_end(list)
#define va_arg(list, mode) ((mode *)(list += sizeof(mode)))[-1]
X
#endif
X
dbgwrite(s,x,y,z)
{
X	mlwrite(s,x,y,z);
X	tgetc();
}
X
/*
X * Write a message into the message line. Keep track of the physical cursor
X * position. A small class of printf like format items is handled.
X * Set the "message line" flag TRUE.
X */
X
/* VARARGS */
mlwrite(fmt, va_alist)
char *fmt;	/* format string for output */
va_dcl
{
X	register int c;		/* current char in format string */
X	register va_list ap;	/* ptr to current data field */
X
X	/* if we are not currently echoing on the command line, abort this */
X	if (dotcmdmode == PLAY || discmd == FALSE) {
X		movecursor(term.t_nrow, 0);
X		return;
X	}
X
#if	COLOR
X	/* set up the proper colors for the command line */
X	TTforg(7);
X	TTbacg(0);
#endif
X
X	/* if we can not erase to end-of-line, do it manually */
X	if (eolexist == FALSE) {
X		mlerase();
X		TTflush();
X	}
X
X	va_start(ap);
X
X	movecursor(term.t_nrow, 0);
X	while ((c = *fmt) != 0 && ttcol < term.t_ncol-1) {
X		if (c != '%') {
X			mlputc(c);
X		} else {
X			c = *++fmt;
X			switch (c) {
X				case '\0':
X					break;
X				case 'c':
X					mlputc(va_arg(ap,int));
X					break;
X
X				case 'd':
X					mlputi(va_arg(ap,int), 10);
X					break;
X
X				case 'o':
X					mlputi(va_arg(ap,int), 8);
X					break;
X
X				case 'x':
X					mlputi(va_arg(ap,int), 16);
X					break;
X
X				case 'D':
X					mlputli(va_arg(ap,long), 10);
X					break;
X
X				case 's':
X					mlputs(va_arg(ap,char *));
X					break;
X
X				case 'S': {
X					int wid = va_arg(ap,int);
X					mlputsn(va_arg(ap,char *),wid);
X					break;
X					}
X
X				case 'f':
X					mlputf(va_arg(ap,int));
X					break;
X
X				default:
X					mlputc(c);
X			}
X		}
X		fmt++;
X	}
X
X	va_end(ap);
X
X	/* if we can, erase to the end of screen */
X	if (eolexist == TRUE)
X		TTeeol();
X	TTflush();
X	mpresf = TRUE;
}
X
/*	Force a string out to the message line regardless of the
X	current $discmd setting. This is needed when $debug is TRUE
X	and for the write-message and clear-message-line commands
*/
X
mlforce(s)
char *s;	/* string to force out */
{
X	register oldcmd;	/* original command display flag */
X
X	oldcmd = discmd;	/* save the discmd value */
X	discmd = TRUE;		/* and turn display on */
X	mlwrite(s);		/* write the string out */
X	discmd = oldcmd;	/* and restore the original setting */
}
X
/*
X * Write out a character. Update the physical cursor position. This assumes that
X * the character has width "1"; if this is not the case
X * things will get screwed up a little.
X */
mlputc(c)
char c;
{
X	if (c == '\r') ttcol = 0;
X	if (ttcol < term.t_ncol-1) {
X	        TTputc(c);
X	        ++ttcol;
X	}
}
X
/*
X * Write out a string. Update the physical cursor position. This assumes that
X * the characters in the string all have width "1"; if this is not the case
X * things will get screwed up a little.
X */
mlputs(s)
char *s;
{
X	register int c;
X
X	while ((c = *s++) != 0) {
X	        mlputc(c);
X	}
}
X
/* as above, but takes a count for s's length */
mlputsn(s,n)
char *s;
{
X	register int c;
X	while ((c = *s++) != 0 && n-- != 0) {
X	        mlputc(c);
X	}
}
X
/*
X * Write out an integer, in the specified radix. Update the physical cursor
X * position.
X */
mlputi(i, r)
{
X    register int q;
X    static char hexdigits[] = "0123456789ABCDEF";
X
X    if (i < 0) {
X        i = -i;
X        mlputc('-');
X    }
X
X    q = i/r;
X
X    if (q != 0)
X        mlputi(q, r);
X
X    mlputc(hexdigits[i%r]);
}
X
/*
X * do the same except as a long integer.
X */
mlputli(l, r)
long l;
{
X    register long q;
X
X    if (l < 0) {
X        l = -l;
X        mlputc('-');
X    }
X
X    q = l/r;
X
X    if (q != 0)
X        mlputli(q, r);
X
X    mlputc((int)(l%r)+'0');
}
X
/*
X *	write out a scaled integer with two decimal places
X */
X
mlputf(s)
int s;	/* scaled integer to output */
{
X	register int i;	/* integer portion of number */
X	register int f;	/* fractional portion of number */
X
X	/* break it up */
X	i = s / 100;
X	f = s % 100;
X
X	/* send out the integer portion */
X	mlputi(i, 10);
X	mlputc('.');
X	mlputc((f / 10) + '0');
X	mlputc((f % 10) + '0');
}	
X
#if RAINBOW
X
putline(row, col, buf)
int row, col;
char buf[];
{
X    int n;
X
X    n = strlen(buf);
X    if (col + n - 1 > term.t_ncol)
X        n = term.t_ncol - col + 1;
X    Put_Data(row, col, n, buf);
}
#endif
X
/* Get terminal size from system.
X   Store number of lines into *heightp and width into *widthp.
X   If zero or a negative number is stored, the value is not valid.  */
X
getscreensize (widthp, heightp)
int *widthp, *heightp;
{
#ifdef TIOCGWINSZ
X	struct winsize size;
X	*widthp = 0;
X	*heightp = 0;
X	if (ioctl (0, TIOCGWINSZ, &size) < 0)
X		return;
X	*widthp = size.ws_col;
X	*heightp = size.ws_row;
#else
X	*widthp = 0;
X	*heightp = 0;
#endif
}
X
#ifdef SIGWINCH
sizesignal ()
{
X	int w, h;
X	extern int errno;
X	int old_errno = errno;
X
X	getscreensize (&w, &h);
X
X	if ((h && h-1 != term.t_nrow) || (w && w != term.t_ncol))
X		newscreensize(h, w);
X
X	signal (SIGWINCH, sizesignal);
X	errno = old_errno;
}
X
newscreensize (h, w)
int h, w;
{
X	/* do the change later */
X	if (displaying) {
X		chg_width = w;
X		chg_height = h;
X		return;
X	}
X	chg_width = chg_height = 0;
X	if (h - 1 < term.t_mrow)
X		newlength(TRUE,h);
X	if (w < term.t_mcol)
X		newwidth(TRUE,w);
X
X	update(TRUE);
X	return TRUE;
}
X
#endif
SHAR_EOF
chmod 0444 display.c ||
echo 'restore of display.c failed'
Wc_c="`wc -c < 'display.c'`"
test 40087 -eq "$Wc_c" ||
	echo 'display.c: original size 40087, current size' "$Wc_c"
# ============= dolock.c ==============
echo 'x - extracting dolock.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'dolock.c' &&
#if	0
/*	dolock:	MDBS specific Unix 4.2BSD file locking mechinism
X		this is not to be distributed generally		*/
X
#include	<mdbs.h>
#include	<mdbsio.h>
#include	<sys/types.h>
#include	<sys/stat.h>
X
/* included by port.h: mdbs.h, mdbsio.h, sys/types.h, sys/stat.h */
X
X
#ifndef bsdunix
char *dolock(){return(NULL);}
char *undolock(){return(NULL);}
#else
X
#include <pwd.h>
#include <errno.h>
X
extern int errno;
X
#define LOCKDIR ".xlk"
X
#define LOCKMSG "LOCK ERROR -- "
#define LOCKMSZ sizeof(LOCKMSG)
#define LOCKERR(s) { strcat(lmsg,s); oldumask = umask(oldumask); return(lmsg); }
X
/**********************
X *
X * dolock -- lock the file fname
X *
X * if successful, returns NULL 
X * if file locked, returns username of person locking the file
X * if other error, returns "LOCK ERROR: explanation"
X *
X * Jon Reid, 2/19/86
X *
X *********************/
X
BOOL parent = FALSE;
BOOL tellall = FALSE;
X
char *gtname(filespec)		/* get name component of unix-style filespec */
char *filespec;
{
X	char *rname, *rindex();
X
X	rname = rindex(filespec,'/');
SHAR_EOF
true || echo 'restore of dolock.c failed'
echo 'End of Vile part 3'
echo 'File dolock.c is continued in part 4'
echo 4 > _shar_seq_.tmp
exit 0
-- 
		paul fox, pgf at cayman.com, (617)494-1999
		Cayman Systems, 26 Landsdowne St., Cambridge, MA 02139



More information about the Alt.sources mailing list