[comp.sources.misc] v08i007: stevie 3.69 - part 5 of 8

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (08/20/89)

Posting-number: Volume 8, Issue 7
Submitted-by: tony@cs.utexas.edu@wldrdg.UUCP (Tony Andrews)
Archive-name: stevie3.68/part05

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	screen.c
#	search.c
#	stevie.h
#	term.c
# This archive created: Sun Aug 13 11:46:06 1989
export PATH; PATH=/bin:$PATH
echo shar: extracting "'screen.c'" '(16083 characters)'
if test -f 'screen.c'
then
	echo shar: will not over-write existing file "'screen.c'"
else
sed 's/^X//' << \HE_HATES_THESE_CANS > 'screen.c'
X/* $Header: /nw/tony/src/stevie/src/RCS/screen.c,v 1.8 89/08/02 09:26:33 tony Exp $
X *
X * Routines to manipulate the screen representations.
X */
X
X#include "stevie.h"
X
X/*
X * This gets set if we ignored an update request while input was pending.
X * We check this when the input is drained to see if the screen should be
X * updated.
X */
Xbool_t	need_redraw = FALSE;
X
X/*
X * The following variable is set (in filetonext) to the number of physical
X * lines taken by the line the cursor is on. We use this to avoid extra
X * calls to plines(). The optimized routines lfiletonext() and lnexttoscreen()
X * make sure that the size of the cursor line hasn't changed. If so, lines
X * below the cursor will move up or down and we need to call the routines
X * filetonext() and nexttoscreen() to examine the entire screen.
X */
Xstatic	int	Cline_size;	/* size (in rows) of the cursor line */
Xstatic	int	Cline_row;	/* starting row of the cursor line */
X
Xstatic	char	*mkline();	/* calculate line string for "number" mode */
X
X/*
X * filetonext()
X *
X * Based on the current value of Topchar, transfer a screenfull of
X * stuff from Filemem to Nextscreen, and update Botchar.
X */
X
Xstatic void
Xfiletonext()
X{
X	register int	row, col;
X	register char	*screenp = Nextscreen;
X	LPTR	memp;
X	LPTR	save;			/* save pos. in case line won't fit */
X	register char	*endscreen;
X	register char	*nextrow;
X	char	extra[16];
X	int	nextra = 0;
X	register int	c;
X	int	n;
X	bool_t	done;		/* if TRUE, we hit the end of the file */
X	bool_t	didline;	/* if TRUE, we finished the last line */
X	int	srow;		/* starting row of the current line */
X	int	lno;		/* number of the line we're doing */
X	int	coff;		/* column offset */
X
X	coff = P(P_NU) ? 8 : 0;
X
X	save = memp = *Topchar;
X
X	if (P(P_NU))
X		lno = cntllines(Filemem, Topchar);
X
X	/*
X	 * The number of rows shown is Rows-1.
X	 * The last line is the status/command line.
X	 */
X	endscreen = &screenp[(Rows-1)*Columns];
X
X	done = didline = FALSE;
X	srow = row = col = 0;
X	/*
X	 * We go one past the end of the screen so we can find out if the
X	 * last line fit on the screen or not.
X	 */
X	while ( screenp <= endscreen && !done) {
X
X
X		if (P(P_NU) && col == 0 && memp.index == 0) {
X			strcpy(extra, mkline(lno++));
X			nextra = 8;
X		}
X
X		/* Get the next character to put on the screen. */
X
X		/* The 'extra' array contains the extra stuff that is */
X		/* inserted to represent special characters (tabs, and */
X		/* other non-printable stuff.  The order in the 'extra' */
X		/* array is reversed. */
X
X		if ( nextra > 0 )
X			c = extra[--nextra];
X		else {
X			c = (unsigned)(0xff & gchar(&memp));
X			if (inc(&memp) == -1)
X				done = 1;
X			/* when getting a character from the file, we */
X			/* may have to turn it into something else on */
X			/* the way to putting it into 'Nextscreen'. */
X			if ( c == TAB && !P(P_LS) ) {
X				strcpy(extra,"        ");
X				/* tab amount depends on current column */
X				nextra = ((P(P_TS)-1) - (col - coff)%P(P_TS));
X				c = ' ';
X			}
X			else if ( c == NUL && P(P_LS) ) {
X				extra[0] = NUL;
X				nextra = 1;
X				c = '$';
X			} else if ( (n = chars[c].ch_size) > 1 ) {
X				char *p;
X				nextra = 0;
X				p = chars[c].ch_str;
X				/* copy 'ch-str'ing into 'extra' in reverse */
X				while ( n > 1 )
X					extra[nextra++] = p[--n];
X				c = p[0];
X			}
X		}
X
X		if (screenp == endscreen) {
X			/*
X			 * We're one past the end of the screen. If the
X			 * current character is null, then we really did
X			 * finish, so set didline = TRUE. In either case,
X			 * break out because we're done.
X			 */
X			dec(&memp);
X			if (memp.index != 0 && c == NUL) {
X				didline = TRUE;
X				inc(&memp);
X			}
X			break;
X		}
X
X		if ( c == NUL ) {
X			srow = ++row;
X			/*
X			 * Save this position in case the next line won't
X			 * fit on the screen completely.
X			 */
X			save = memp;
X			/* get pointer to start of next row */
X			nextrow = &Nextscreen[row*Columns];
X			/* blank out the rest of this row */
X			while ( screenp != nextrow )
X				*screenp++ = ' ';
X			col = 0;
X			continue;
X		}
X		if ( col >= Columns ) {
X			row++;
X			col = 0;
X		}
X		/* store the character in Nextscreen */
X		*screenp++ = c;
X		col++;
X	}
X	/*
X	 * If we didn't hit the end of the file, and we didn't finish
X	 * the last line we were working on, then the line didn't fit.
X	 */
X	if (!done && !didline) {
X		/*
X		 * Clear the rest of the screen and mark the unused lines.
X		 */
X		screenp = &Nextscreen[srow * Columns];
X		while (screenp < endscreen)
X			*screenp++ = ' ';
X		for (; srow < (Rows-1) ;srow++)
X			Nextscreen[srow * Columns] = '@';
X		*Botchar = save;
X		return;
X	}
X	/* make sure the rest of the screen is blank */
X	while ( screenp < endscreen )
X		*screenp++ = ' ';
X	/* put '~'s on rows that aren't part of the file. */
X	if ( col != 0 )
X		row++;
X	while ( row < Rows ) {
X		Nextscreen[row*Columns] = '~';
X		row++;
X	}
X	if (done)	/* we hit the end of the file */
X		*Botchar = *Fileend;
X	else
X		*Botchar = memp;	/* FIX - prev? */
X}
X
X/*
X * nexttoscreen
X *
X * Transfer the contents of Nextscreen to the screen, using Realscreen
X * to avoid unnecessary output.
X */
Xstatic void
Xnexttoscreen()
X{
X	register char	*np = Nextscreen;
X	register char	*rp = Realscreen;
X	register char	*endscreen;
X	register int	row = 0, col = 0;
X	int	gorow = -1, gocol = -1;
X
X	if (anyinput()) {
X		need_redraw = TRUE;
X		return;
X	}
X
X	endscreen = &np[(Rows-1)*Columns];
X
X	outstr(T_CI);		/* disable cursor */
X
X	for ( ; np < endscreen ; np++,rp++ ) {
X		/* If desired screen (contents of Nextscreen) does not */
X		/* match what's really there, put it there. */
X		if ( *np != *rp ) {
X			/* if we are positioned at the right place, */
X			/* we don't have to use windgoto(). */
X			if (gocol != col || gorow != row) {
X				/*
X				 * If we're just off by one, don't send
X				 * an entire esc. seq. (this happens a lot!)
X				 */
X				if (gorow == row && gocol+1 == col) {
X					outchar(*(np-1));
X					gocol++;
X				} else
X					windgoto(gorow=row,gocol=col);
X			}
X			outchar(*rp = *np);
X			gocol++;
X		}
X		if ( ++col >= Columns ) {
X			col = 0;
X			row++;
X		}
X	}
X	outstr(T_CV);		/* enable cursor again */
X}
X
X/*
X * lfiletonext() - like filetonext() but only for cursor line
X *
X * Returns true if the size of the cursor line (in rows) hasn't changed.
X * This determines whether or not we need to call filetonext() to examine
X * the entire screen for changes.
X */
Xstatic bool_t
Xlfiletonext()
X{
X	register int	row, col;
X	register char	*screenp;
X	LPTR	memp;
X	register char	*nextrow;
X	char	extra[16];
X	int	nextra = 0;
X	register int	c;
X	int	n;
X	bool_t	eof;
X	int	lno;		/* number of the line we're doing */
X	int	coff;		/* column offset */
X
X	coff = P(P_NU) ? 8 : 0;
X
X	/*
X	 * This should be done more efficiently.
X	 */
X	if (P(P_NU))
X		lno = cntllines(Filemem, Curschar);
X
X	screenp = Nextscreen + (Cline_row * Columns);
X
X	memp = *Curschar;
X	memp.index = 0;
X
X	eof = FALSE;
X	col = 0;
X	row = Cline_row;
X
X	while (!eof) {
X
X		if (P(P_NU) && col == 0 && memp.index == 0) {
X			strcpy(extra, mkline(lno));
X			nextra = 8;
X		}
X
X		/* Get the next character to put on the screen. */
X
X		/* The 'extra' array contains the extra stuff that is */
X		/* inserted to represent special characters (tabs, and */
X		/* other non-printable stuff.  The order in the 'extra' */
X		/* array is reversed. */
X
X		if ( nextra > 0 )
X			c = extra[--nextra];
X		else {
X			c = (unsigned)(0xff & gchar(&memp));
X			if (inc(&memp) == -1)
X				eof = TRUE;
X			/* when getting a character from the file, we */
X			/* may have to turn it into something else on */
X			/* the way to putting it into 'Nextscreen'. */
X			if ( c == TAB && !P(P_LS) ) {
X				strcpy(extra,"        ");
X				/* tab amount depends on current column */
X				nextra = ((P(P_TS)-1) - (col - coff)%P(P_TS));
X				c = ' ';
X			} else if ( c == NUL && P(P_LS) ) {
X				extra[0] = NUL;
X				nextra = 1;
X				c = '$';
X			} else if ( c != NUL && (n=chars[c].ch_size) > 1 ) {
X				char *p;
X				nextra = 0;
X				p = chars[c].ch_str;
X				/* copy 'ch-str'ing into 'extra' in reverse */
X				while ( n > 1 )
X					extra[nextra++] = p[--n];
X				c = p[0];
X			}
X		}
X
X		if ( c == NUL ) {
X			row++;
X			/* get pointer to start of next row */
X			nextrow = &Nextscreen[row*Columns];
X			/* blank out the rest of this row */
X			while ( screenp != nextrow )
X				*screenp++ = ' ';
X			col = 0;
X			break;
X		}
X
X		if ( col >= Columns ) {
X			row++;
X			col = 0;
X		}
X		/* store the character in Nextscreen */
X		*screenp++ = c;
X		col++;
X	}
X	return ((row - Cline_row) == Cline_size);
X}
X
X/*
X * lnexttoscreen
X *
X * Like nexttoscreen() but only for the cursor line.
X */
Xstatic void
Xlnexttoscreen()
X{
X	register char	*np = Nextscreen + (Cline_row * Columns);
X	register char	*rp = Realscreen + (Cline_row * Columns);
X	register char	*endline;
X	register int	row, col;
X	int	gorow = -1, gocol = -1;
X
X	if (anyinput()) {
X		need_redraw = TRUE;
X		return;
X	}
X
X	endline = np + (Cline_size * Columns);
X
X	row = Cline_row;
X	col = 0;
X
X	outstr(T_CI);		/* disable cursor */
X
X	for ( ; np < endline ; np++,rp++ ) {
X		/* If desired screen (contents of Nextscreen) does not */
X		/* match what's really there, put it there. */
X		if ( *np != *rp ) {
X			/* if we are positioned at the right place, */
X			/* we don't have to use windgoto(). */
X			if (gocol != col || gorow != row) {
X				/*
X				 * If we're just off by one, don't send
X				 * an entire esc. seq. (this happens a lot!)
X				 */
X				if (gorow == row && gocol+1 == col) {
X					outchar(*(np-1));
X					gocol++;
X				} else
X					windgoto(gorow=row,gocol=col);
X			}
X			outchar(*rp = *np);
X			gocol++;
X		}
X		if ( ++col >= Columns ) {
X			col = 0;
X			row++;
X		}
X	}
X	outstr(T_CV);		/* enable cursor again */
X}
X
Xstatic char *
Xmkline(n)
Xregister int	n;
X{
X	static	char	lbuf[9];
X	register int	i = 2;
X
X	strcpy(lbuf, "        ");
X
X	lbuf[i++] = (n % 10) + '0';
X	n /= 10;
X	if (n != 0) {
X		lbuf[i++] = (n % 10) + '0';
X		n /= 10;
X	}
X	if (n != 0) {
X		lbuf[i++] = (n % 10) + '0';
X		n /= 10;
X	}
X	if (n != 0) {
X		lbuf[i++] = (n % 10) + '0';
X		n /= 10;
X	}
X	if (n != 0) {
X		lbuf[i++] = (n % 10) + '0';
X		n /= 10;
X	}
X	return lbuf;
X}
X
X/*
X * updateline() - update the line the cursor is on
X *
X * Updateline() is called after changes that only affect the line that
X * the cursor is on. This improves performance tremendously for normal
X * insert mode operation. The only thing we have to watch for is when
X * the cursor line grows or shrinks around a row boundary. This means
X * we have to repaint other parts of the screen appropriately. If
X * lfiletonext() returns FALSE, the size of the cursor line (in rows)
X * has changed and we have to call updatescreen() to do a complete job.
X */
Xvoid
Xupdateline()
X{
X	if (!lfiletonext())
X		updatescreen();	/* bag it, do the whole screen */
X	else
X		lnexttoscreen();
X}
X
Xvoid
Xupdatescreen()
X{
X	extern	bool_t	interactive;
X
X	if (interactive) {
X		filetonext();
X		nexttoscreen();
X	}
X}
X
X/*
X * prt_line() - print the given line
X */
Xvoid
Xprt_line(s)
Xchar	*s;
X{
X	register int	si = 0;
X	register int	c;
X	register int	col = 0;
X
X	char	extra[16];
X	int	nextra = 0;
X	int	n;
X
X	for (;;) {
X
X		if ( nextra > 0 )
X			c = extra[--nextra];
X		else {
X			c = s[si++];
X			if ( c == TAB && !P(P_LS) ) {
X				strcpy(extra, "        ");
X				/* tab amount depends on current column */
X				nextra = (P(P_TS) - 1) - col%P(P_TS);
X				c = ' ';
X			} else if ( c == NUL && P(P_LS) ) {
X				extra[0] = NUL;
X				nextra = 1;
X				c = '$';
X			} else if ( c != NUL && (n=chars[c].ch_size) > 1 ) {
X				char	*p;
X
X				nextra = 0;
X				p = chars[c].ch_str;
X				/* copy 'ch-str'ing into 'extra' in reverse */
X				while ( n > 1 )
X					extra[nextra++] = p[--n];
X				c = p[0];
X			}
X		}
X
X		if ( c == NUL )
X			break;
X
X		outchar(c);
X		col++;
X	}
X}
X
Xvoid
Xscreenclear()
X{
X	register char	*rp, *np;
X	register char	*end;
X
X	outstr(T_ED);		/* clear the display */
X
X	rp  = Realscreen;
X	end = Realscreen + Rows * Columns;
X	np  = Nextscreen;
X
X	/* blank out the stored screens */
X	while (rp != end)
X		*rp++ = *np++ = ' ';
X}
X
Xvoid
Xcursupdate()
X{
X	register LPTR	*p;
X	register int	icnt, c, nlines;
X	register int	i;
X	int	didinc;
X
X	if (bufempty()) {		/* special case - file is empty */
X		*Topchar  = *Filemem;
X		*Curschar = *Filemem;
X	} else if ( LINEOF(Curschar) < LINEOF(Topchar) ) {
X		nlines = cntllines(Curschar,Topchar);
X		/* if the cursor is above the top of */
X		/* the screen, put it at the top of the screen.. */
X		*Topchar = *Curschar;
X		Topchar->index = 0;
X		/* ... and, if we weren't very close to begin with, */
X		/* we scroll so that the line is close to the middle. */
X		if ( nlines > Rows/3 ) {
X			for (i=0, p = Topchar; i < Rows/3 ;i++, *Topchar = *p)
X				if ((p = prevline(p)) == NULL)
X					break;
X		} else
X			s_ins(0, nlines-1);
X		updatescreen();
X	}
X	else if (LINEOF(Curschar) >= LINEOF(Botchar)) {
X		nlines = cntllines(Botchar,Curschar);
X		/* If the cursor is off the bottom of the screen, */
X		/* put it at the top of the screen.. */
X		/* ... and back up */
X		if ( nlines > Rows/3 ) {
X			p = Curschar;
X			for (i=0; i < (2*Rows)/3 ;i++)
X				if ((p = prevline(p)) == NULL)
X					break;
X			*Topchar = *p;
X		} else {
X			scrollup(nlines);
X		}
X		updatescreen();
X	}
X
X	Cursrow = Curscol = Cursvcol = 0;
X	for ( p=Topchar; p->linep != Curschar->linep ;p = nextline(p) )
X		Cursrow += plines(p);
X
X	Cline_row = Cursrow;
X	Cline_size = plines(p);
X
X	if (P(P_NU))
X		Curscol = 8;
X
X	for (i=0; i <= Curschar->index ;i++) {
X		c = Curschar->linep->s[i];
X		/* A tab gets expanded, depending on the current column */
X		if ( c == TAB && !P(P_LS) )
X			icnt = P(P_TS) - (Cursvcol % P(P_TS));
X		else
X			icnt = chars[(unsigned)(c & 0xff)].ch_size;
X		Curscol += icnt;
X		Cursvcol += icnt;
X		if ( Curscol >= Columns ) {
X			Curscol -= Columns;
X			Cursrow++;
X			didinc = TRUE;
X		}
X		else
X			didinc = FALSE;
X	}
X	if (didinc)
X		Cursrow--;
X
X	if (c == TAB && State == NORMAL && !P(P_LS)) {
X		Curscol--;
X		Cursvcol--;
X	} else {
X		Curscol -= icnt;
X		Cursvcol -= icnt;
X	}
X	if (Curscol < 0)
X		Curscol += Columns;
X
X	if (set_want_col) {
X		Curswant = Cursvcol;
X		set_want_col = FALSE;
X	}
X}
X
X/*
X * The rest of the routines in this file perform screen manipulations.
X * The given operation is performed physically on the screen. The
X * corresponding change is also made to the internal screen image.
X * In this way, the editor anticipates the effect of editing changes
X * on the appearance of the screen. That way, when we call screenupdate
X * a complete redraw isn't usually necessary. Another advantage is that
X * we can keep adding code to anticipate screen changes, and in the
X * meantime, everything still works.
X */
X
X/*
X * s_ins(row, nlines) - insert 'nlines' lines at 'row'
X */
Xvoid
Xs_ins(row, nlines)
Xint	row;
Xint	nlines;
X{
X	register char	*s, *d;		/* src & dest for block copy */
X	register char	*e;		/* end point for copy */
X	register int	i;
X
X	if (T_IL[0] == NUL)		/* can't do it */
X		return;
X
X	/*
X	 * It "looks" better if we do all the inserts at once
X	 */
X	outstr(T_SC);			/* save position */
X	windgoto(row, 0);
X
X	for (i=0; i < nlines ;i++)
X		outstr(T_IL);
X
X	windgoto(Rows-1, 0);	/* delete any garbage that may have */
X	outstr(T_EL);		/* been shifted to the bottom line */
X	outstr(T_RC);		/* restore the cursor position */
X
X	/*
X	 * Now do a block move to update the internal screen image
X	 */
X	d = Realscreen + (Columns * (Rows - 1)) - 1;
X	s = d - (Columns * nlines);
X	e = Realscreen + (Columns * row);
X
X	while (s >= e)
X		*d-- = *s--;
X
X	/*
X	 * Clear the inserted lines
X	 */
X	s = Realscreen + (row * Columns);
X	e = s + (nlines * Columns);
X	while (s < e)
X		*s++ = ' ';
X}
X
X/*
X * s_del(row, nlines) - delete 'nlines' lines at 'row'
X */
Xvoid
Xs_del(row, nlines)
Xint	row;
Xint	nlines;
X{
X	register char	*s, *d, *e;
X	register int	i;
X
X	if (T_DL[0] == NUL)			/* can't do it */
X		return;
X
X	/* delete the lines */
X	outstr(T_SC);				/* save position */
X	windgoto(row, 0);
X
X	for (i=0; i < nlines ;i++) {
X		outstr(T_DL);			/* delete a line */
X		if (i == 0) {
X			windgoto(Rows-2, 0);	/* delete any garbage that */
X			outstr(T_EL);		/* was on the status line */
X			windgoto(row, 0);
X		}
X	}
X	outstr(T_RC);				/* restore position */
X
X	/*
X	 * do a block move to update the internal image
X	 */
X	d = Realscreen + (row * Columns);
X	s = d + (nlines * Columns);
X	e = Realscreen + ((Rows - 1) * Columns);
X
X	while (s < e)
X		*d++ = *s++;
X
X	while (d < e)		/* clear the lines at the bottom */
X		*d++ = ' ';
X}
HE_HATES_THESE_CANS
if test 16083 -ne "`wc -c < 'screen.c'`"
then
	echo shar: error transmitting "'screen.c'" '(should have been 16083 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'search.c'" '(18702 characters)'
if test -f 'search.c'
then
	echo shar: will not over-write existing file "'search.c'"
else
sed 's/^X//' << \HE_HATES_THESE_CANS > 'search.c'
X/* $Header: /nw/tony/src/stevie/src/RCS/search.c,v 1.16 89/08/06 09:50:51 tony Exp $
X *
X * This file contains various searching-related routines. These fall into
X * three groups: string searches (for /, ?, n, and N), character searches
X * within a single line (for f, F, t, T, etc), and "other" kinds of searches
X * like the '%' command, and 'word' searches.
X */
X
X#include "stevie.h"
X#include "regexp.h"	/* Henry Spencer's (modified) reg. exp. routines */
X
X/*
X * String searches
X *
X * The actual searches are done using Henry Spencer's regular expression
X * library.
X */
X
X#define	BEGWORD	"([^a-zA-Z0-9_]|^)"	/* replaces "\<" in search strings */
X#define	ENDWORD	"([^a-zA-Z0-9_]|$)"	/* likewise replaces "\>" */
X
X#define	BEGCHAR(c)	(islower(c) || isupper(c) || isdigit(c) || ((c) == '_'))
X
Xbool_t	begword;	/* does the search include a 'begin word' match */
X
X/*
X * mapstring(s) - map special backslash sequences
X */
Xstatic char *
Xmapstring(s)
Xregister char	*s;
X{
X	static	char	ns[80];
X	register char	*p;
X
X	begword = FALSE;
X
X	for (p = ns; *s ;s++) {
X		if (*s != '\\') {	/* not an escape */
X			*p++ = *s;
X			continue;
X		}
X		switch (*++s) {
X		case '/':
X			*p++ = '/';
X			break;
X
X		case '<':
X			strcpy(p, BEGWORD);
X			p += strlen(BEGWORD);
X			begword = TRUE;
X			break;
X
X		case '>':
X			strcpy(p, ENDWORD);
X			p += strlen(ENDWORD);
X			break;
X
X		default:
X			*p++ = '\\';
X			*p++ = *s;
X			break;
X		}
X	}
X	*p++ = NUL;
X
X	return ns;
X}
X
Xstatic char *laststr = NULL;
Xstatic int lastsdir;
X
Xstatic LPTR *
Xssearch(dir,str)
Xint	dir;	/* FORWARD or BACKWARD */
Xchar	*str;
X{
X	LPTR	*bcksearch(), *fwdsearch();
X	LPTR	*pos;
X	char	*old_ls = laststr;
X
X	reg_ic = P(P_IC);	/* tell the regexp routines how to search */
X
X	laststr = strsave(str);
X	lastsdir = dir;
X
X	if (old_ls != NULL)
X		free(old_ls);
X
X	if (dir == BACKWARD) {
X		smsg("?%s", laststr);
X		pos = bcksearch(mapstring(laststr));
X	} else {
X		smsg("/%s", laststr);
X		pos = fwdsearch(mapstring(laststr));
X	}
X
X	/*
X	 * This is kind of a kludge, but its needed to make
X	 * 'beginning of word' searches land on the right place.
X	 */
X	if (pos != NULL && begword) {
X		if (pos->index != 0 || !BEGCHAR(pos->linep->s[0]))
X			pos->index += 1;
X	}
X	return pos;
X}
X
Xbool_t
Xdosearch(dir,str)
Xint	dir;
Xchar	*str;
X{
X	LPTR	*p;
X
X	if (str == NULL)
X		str = laststr;
X
X	got_int = FALSE;
X
X	if ((p = ssearch(dir,str)) == NULL) {
X		if (got_int)
X			msg("Interrupt");
X		else
X			msg("Pattern not found");
X
X		got_int = FALSE;
X		return FALSE;
X	} else {
X		LPTR savep;
X
X		cursupdate();
X		/*
X		 * if we're backing up, we make sure the line we're on
X		 * is on the screen.
X		 */
X		setpcmark();
X		*Curschar = savep = *p;
X		set_want_col = TRUE;
X		cursupdate();
X
X		return TRUE;
X	}
X}
X
X#define	OTHERDIR(x)	(((x) == FORWARD) ? BACKWARD : FORWARD)
X
Xbool_t
Xrepsearch(flag)
Xint	flag;
X{
X	int	dir = lastsdir;
X	bool_t	found;
X
X	if ( laststr == NULL ) {
X		beep();
X		return FALSE;
X	}
X
X	found = dosearch(flag ? OTHERDIR(lastsdir) : lastsdir, laststr);
X
X	/*
X	 * We have to save and restore 'lastsdir' because it gets munged
X	 * by ssearch() and winds up saving the wrong direction from here
X	 * if 'flag' is true.
X	 */
X	lastsdir = dir;
X
X	return found;
X}
X
X/*
X * regerror - called by regexp routines when errors are detected.
X */
Xvoid
Xregerror(s)
Xchar	*s;
X{
X	emsg(s);
X}
X
Xstatic LPTR *
Xfwdsearch(str)
Xregister char	*str;
X{
X	static LPTR	infile;
X	register LPTR	*p;
X	regexp	*prog;
X
X	register char	*s;
X	register int	i;
X
X	if ((prog = regcomp(str)) == NULL) {
X		emsg("Invalid search string");
X		return NULL;
X	}
X
X	p = Curschar;
X	i = Curschar->index + 1;
X	do {
X		s = p->linep->s + i;
X
X		if (regexec(prog, s, i == 0)) {		/* got a match */
X			infile.linep = p->linep;
X			infile.index = (int) (prog->startp[0] - p->linep->s);
X			free((char *)prog);
X			return (&infile);
X		}
X		i = 0;
X
X		if (got_int)
X			goto fwdfail;
X
X	} while ((p = nextline(p)) != NULL);
X
X	/*
X	 * If wrapscan isn't set, then don't scan from the beginning
X	 * of the file. Just return failure here.
X	 */
X	if (!P(P_WS))
X		goto fwdfail;
X
X	/* search from the beginning of the file to Curschar */
X	for (p = Filemem; p != NULL ;p = nextline(p)) {
X		s = p->linep->s;
X
X		if (regexec(prog, s, TRUE)) {		/* got a match */
X			infile.linep = p->linep;
X			infile.index = (int) (prog->startp[0] - s);
X			free((char *)prog);
X			return (&infile);
X		}
X
X		if (p->linep == Curschar->linep)
X			break;
X
X		if (got_int)
X			goto fwdfail;
X	}
X
Xfwdfail:
X	free((char *)prog);
X	return NULL;
X}
X
Xstatic LPTR *
Xbcksearch(str)
Xchar	*str;
X{
X	static LPTR	infile;
X	register LPTR	*p = &infile;
X	register char	*s;
X	register int	i;
X	register char	*match;
X	regexp	*prog;
X
X	/* make sure str isn't empty */
X	if (str == NULL || *str == NUL)
X		return NULL;
X
X	if ((prog = regcomp(str)) == NULL) {
X		emsg("Invalid search string");
X		return NULL;
X	}
X
X	*p = *Curschar;
X	if (dec(p) == -1) {	/* already at start of file? */
X		*p = *Fileend;
X		p->index = strlen(p->linep->s) - 1;
X	}
X
X	if (begword)		/* so we don't get stuck on one match */
X		dec(p);
X
X	i = p->index;
X
X	do {
X		s = p->linep->s;
X
X		if (regexec(prog, s, TRUE)) {	/* match somewhere on line */
X
X			/*
X			 * Now, if there are multiple matches on this line,
X			 * we have to get the last one. Or the last one
X			 * before the cursor, if we're on that line.
X			 */
X			match = prog->startp[0];
X
X			while (regexec(prog, prog->endp[0], FALSE)) {
X				if ((i >= 0) && ((prog->startp[0] - s) > i))
X					break;
X				match = prog->startp[0];
X			}
X
X			if ((i >= 0) && ((match - s) > i)) {
X				i = -1;
X				continue;
X			}
X
X			infile.linep = p->linep;
X			infile.index = (int) (match - s);
X			free((char *)prog);
X			return (&infile);
X		}
X		i = -1;
X
X		if (got_int)
X			goto bckfail;
X
X	} while ((p = prevline(p)) != NULL);
X
X	/*
X	 * If wrapscan isn't set, bag the search now
X	 */
X	if (!P(P_WS))
X		goto bckfail;
X
X	/* search backward from the end of the file */
X	p = prevline(Fileend);
X	do {
X		s = p->linep->s;
X
X		if (regexec(prog, s, TRUE)) {	/* match somewhere on line */
X
X			/*
X			 * Now, if there are multiple matches on this line,
X			 * we have to get the last one.
X			 */
X			match = prog->startp[0];
X
X			while (regexec(prog, prog->endp[0], FALSE))
X				match = prog->startp[0];
X
X			infile.linep = p->linep;
X			infile.index = (int) (match - s);
X			free((char *)prog);
X			return (&infile);
X		}
X
X		if (p->linep == Curschar->linep)
X			break;
X
X		if (got_int)
X			goto bckfail;
X
X	} while ((p = prevline(p)) != NULL);
X
Xbckfail:
X	free((char *)prog);
X	return NULL;
X}
X
X/*
X * dosub(lp, up, cmd)
X *
X * Perform a substitution from line 'lp' to line 'up' using the
X * command pointed to by 'cmd' which should be of the form:
X *
X * /pattern/substitution/g
X *
X * The trailing 'g' is optional and, if present, indicates that multiple
X * substitutions should be performed on each line, if applicable.
X * The usual escapes are supported as described in the regexp docs.
X */
Xvoid
Xdosub(lp, up, cmd)
XLPTR	*lp, *up;
Xchar	*cmd;
X{
X	LINE	*cp;
X	char	*pat, *sub;
X	regexp	*prog;
X	int	nsubs;
X	bool_t	do_all;		/* do multiple substitutions per line */
X
X	/*
X	 * If no range was given, do the current line. If only one line
X	 * was given, just do that one.
X	 */
X	if (lp->linep == NULL)
X		*up = *lp = *Curschar;
X	else {
X		if (up->linep == NULL)
X			*up = *lp;
X	}
X
X	pat = ++cmd;		/* skip the initial '/' */
X
X	while (*cmd) {
X		if (*cmd == '\\')	/* next char is quoted */
X			cmd += 2;
X		else if (*cmd == '/') {	/* delimiter */
X			*cmd++ = NUL;
X			break;
X		} else
X			cmd++;		/* regular character */
X	}
X
X	if (*pat == NUL) {
X		emsg("NULL pattern specified");
X		return;
X	}
X
X	sub = cmd;
X
X	do_all = FALSE;
X
X	while (*cmd) {
X		if (*cmd == '\\')	/* next char is quoted */
X			cmd += 2;
X		else if (*cmd == '/') {	/* delimiter */
X			do_all = (cmd[1] == 'g');
X			*cmd++ = NUL;
X			break;
X		} else
X			cmd++;		/* regular character */
X	}
X
X	reg_ic = P(P_IC);	/* set "ignore case" flag appropriately */
X
X	if ((prog = regcomp(pat)) == NULL) {
X		emsg("Invalid search string");
X		return;
X	}
X
X	nsubs = 0;
X
X	for (cp = lp->linep; cp != NULL ;cp = cp->next) {
X		if (regexec(prog, cp->s, TRUE)) { /* a match on this line */
X			char	*ns, *sns, *p;
X
X			/*
X			 * Get some space for a temporary buffer
X			 * to do the substitution into.
X			 */
X			sns = ns = alloc(2048);
X			*sns = NUL;
X
X			p = cp->s;
X
X			do {
X				for (ns = sns; *ns ;ns++)
X					;
X				/*
X				 * copy up to the part that matched
X				 */
X				while (p < prog->startp[0])
X					*ns++ = *p++;
X
X				regsub(prog, sub, ns);
X
X				/*
X				 * continue searching after the match
X				 */
X				p = prog->endp[0];
X
X			} while (regexec(prog, p, FALSE) && do_all);
X
X			for (ns = sns; *ns ;ns++)
X				;
X
X			/*
X			 * copy the rest of the line, that didn't match
X			 */
X			while (*p)
X				*ns++ = *p++;
X
X			*ns = NUL;
X
X			free(cp->s);		/* free the original line */
X			cp->s = strsave(sns);	/* and save the modified str */
X			cp->size = strlen(cp->s) + 1;
X			free(sns);		/* free the temp buffer */
X			nsubs++;
X			CHANGED;
X		}
X		if (cp == up->linep)
X			break;
X	}
X
X	if (nsubs) {
X		updatescreen();
X		if (nsubs >= P(P_RP))
X			smsg("%d substitution%c", nsubs, (nsubs>1) ? 's' : ' ');
X	} else
X		msg("No match");
X
X	free((char *)prog);
X}
X
X/*
X * doglob(cmd)
X *
X * Execute a global command of the form:
X *
X * g/pattern/X
X *
X * where 'x' is a command character, currently one of the following:
X *
X * d	Delete all matching lines
X * p	Print all matching lines
X *
X * The command character (as well as the trailing slash) is optional, and
X * is assumed to be 'p' if missing.
X */
Xvoid
Xdoglob(lp, up, cmd)
XLPTR	*lp, *up;
Xchar	*cmd;
X{
X	LINE	*cp;
X	char	*pat;
X	regexp	*prog;
X	int	ndone;
X	char	cmdchar = NUL;	/* what to do with matching lines */
X
X	/*
X	 * If no range was given, do every line. If only one line
X	 * was given, just do that one.
X	 */
X	if (lp->linep == NULL) {
X		*lp = *Filemem;
X		*up = *Fileend;
X	} else {
X		if (up->linep == NULL)
X			*up = *lp;
X	}
X
X	pat = ++cmd;		/* skip the initial '/' */
X
X	while (*cmd) {
X		if (*cmd == '\\')	/* next char is quoted */
X			cmd += 2;
X		else if (*cmd == '/') {	/* delimiter */
X			cmdchar = cmd[1];
X			*cmd++ = NUL;
X			break;
X		} else
X			cmd++;		/* regular character */
X	}
X	if (cmdchar == NUL)
X		cmdchar = 'p';
X
X	reg_ic = P(P_IC);	/* set "ignore case" flag appropriately */
X
X	if (cmdchar != 'd' && cmdchar != 'p') {
X		emsg("Invalid command character");
X		return;
X	}
X
X	if ((prog = regcomp(pat)) == NULL) {
X		emsg("Invalid search string");
X		return;
X	}
X
X	msg("");
X	ndone = 0;
X	got_int = FALSE;
X
X	for (cp = lp->linep; cp != NULL && !got_int ;cp = cp->next) {
X		if (regexec(prog, cp->s, TRUE)) { /* a match on this line */
X			switch (cmdchar) {
X
X			case 'd':		/* delete the line */
X				if (Curschar->linep != cp) {
X					LPTR	savep;
X
X					savep = *Curschar;
X					Curschar->linep = cp;
X					Curschar->index = 0;
X					delline(1, FALSE);
X					*Curschar = savep;
X				} else
X					delline(1, FALSE);
X				break;
X
X			case 'p':		/* print the line */
X				prt_line(cp->s);
X				outstr("\r\n");
X				break;
X			}
X			ndone++;
X		}
X		if (cp == up->linep)
X			break;
X	}
X
X	if (ndone) {
X		switch (cmdchar) {
X
X		case 'd':
X			updatescreen();
X			if (ndone >= P(P_RP) || got_int)
X				smsg("%s%d fewer line%c",
X					got_int ? "Interrupt: " : "",
X					ndone,
X					(ndone > 1) ? 's' : ' ');
X			break;
X
X		case 'p':
X			wait_return();
X			break;
X		}
X	} else {
X		if (got_int)
X			msg("Interrupt");
X		else
X			msg("No match");
X	}
X
X	got_int = FALSE;
X	free((char *)prog);
X}
X
X/*
X * Character Searches
X */
X
Xstatic char lastc = NUL;	/* last character searched for */
Xstatic int  lastcdir;		/* last direction of character search */
Xstatic int  lastctype;		/* last type of search ("find" or "to") */
X
X/*
X * searchc(c, dir, type)
X *
X * Search for character 'c', in direction 'dir'. If type is 0, move to
X * the position of the character, otherwise move to just before the char.
X */
Xbool_t
Xsearchc(c, dir, type)
Xchar	c;
Xint	dir;
Xint	type;
X{
X	LPTR	save;
X
X	save = *Curschar;	/* save position in case we fail */
X	lastc = c;
X	lastcdir = dir;
X	lastctype = type;
X
X	/*
X	 * On 'to' searches, skip one to start with so we can repeat
X	 * searches in the same direction and have it work right.
X	 */
X	if (type)
X		(dir == FORWARD) ? oneright() : oneleft();
X
X	while ( (dir == FORWARD) ? oneright() : oneleft() ) {
X		if (gchar(Curschar) == c) {
X			if (type)
X				(dir == FORWARD) ? oneleft() : oneright();
X			return TRUE;
X		}
X	}
X	*Curschar = save;
X	return FALSE;
X}
X
Xbool_t
Xcrepsearch(flag)
Xint	flag;
X{
X	int	dir = lastcdir;
X	int	rval;
X
X	if (lastc == NUL)
X		return FALSE;
X
X	rval = searchc(lastc, flag ? OTHERDIR(lastcdir) : lastcdir, lastctype);
X
X	lastcdir = dir;		/* restore dir., since it may have changed */
X
X	return rval;
X}
X
X/*
X * "Other" Searches
X */
X
X/*
X * showmatch - move the cursor to the matching paren or brace
X */
XLPTR *
Xshowmatch()
X{
X	static	LPTR	pos;
X	int	(*move)(), inc(), dec();
X	char	initc = gchar(Curschar);	/* initial char */
X	char	findc;				/* terminating char */
X	char	c;
X	int	count = 0;
X
X	pos = *Curschar;		/* set starting point */
X
X	switch (initc) {
X
X	case '(':
X		findc = ')';
X		move = inc;
X		break;
X	case ')':
X		findc = '(';
X		move = dec;
X		break;
X	case '{':
X		findc = '}';
X		move = inc;
X		break;
X	case '}':
X		findc = '{';
X		move = dec;
X		break;
X	case '[':
X		findc = ']';
X		move = inc;
X		break;
X	case ']':
X		findc = '[';
X		move = dec;
X		break;
X	default:
X		return (LPTR *) NULL;
X	}
X
X	while ((*move)(&pos) != -1) {		/* until end of file */
X		c = gchar(&pos);
X		if (c == initc)
X			count++;
X		else if (c == findc) {
X			if (count == 0)
X				return &pos;
X			count--;
X		}
X	}
X	return (LPTR *) NULL;			/* never found it */
X}
X
X/*
X * findfunc(dir) - Find the next function in direction 'dir'
X *
X * Return TRUE if a function was found.
X */
Xbool_t
Xfindfunc(dir)
Xint	dir;
X{
X	LPTR	*curr;
X
X	curr = Curschar;
X
X	do {
X		curr = (dir == FORWARD) ? nextline(curr) : prevline(curr);
X
X		if (curr != NULL && curr->linep->s[0] == '{') {
X			setpcmark();
X			*Curschar = *curr;
X			return TRUE;
X		}
X	} while (curr != NULL);
X
X	return FALSE;
X}
X
X/*
X * The following routines do the word searches performed by the
X * 'w', 'W', 'b', 'B', 'e', and 'E' commands.
X */
X
X/*
X * To perform these searches, characters are placed into one of three
X * classes, and transitions between classes determine word boundaries.
X *
X * The classes are:
X *
X * 0 - white space
X * 1 - letters, digits, and underscore
X * 2 - everything else
X */
X
Xstatic	int	stype;		/* type of the word motion being performed */
X
X#define	C0(c)	(((c) == ' ') || ((c) == '\t') || ((c) == NUL))
X#define	C1(c)	(isalpha(c) || isdigit(c) || ((c) == '_'))
X
X/*
X * cls(c) - returns the class of character 'c'
X *
X * The 'type' of the current search modifies the classes of characters
X * if a 'W', 'B', or 'E' motion is being done. In this case, chars. from
X * class 2 are reported as class 1 since only white space boundaries are
X * of interest.
X */
Xstatic	int
Xcls(c)
Xchar	c;
X{
X	if (C0(c))
X		return 0;
X
X	if (C1(c))
X		return 1;
X
X	/*
X	 * If stype is non-zero, report these as class 1.
X	 */
X	return (stype == 0) ? 2 : 1;
X}
X
X
X/*
X * fwd_word(pos, type) - move forward one word
X *
X * Returns the resulting position, or NULL if EOF was reached.
X */
XLPTR *
Xfwd_word(p, type)
XLPTR	*p;
Xint	type;
X{
X	static	LPTR	pos;
X	int	sclass = cls(gchar(p));		/* starting class */
X
X	pos = *p;
X
X	stype = type;
X
X	/*
X	 * We always move at least one character.
X	 */
X	if (inc(&pos) == -1)
X		return NULL;
X
X	if (sclass != 0) {
X		while (cls(gchar(&pos)) == sclass) {
X			if (inc(&pos) == -1)
X				return NULL;
X		}
X		/*
X		 * If we went from 1 -> 2 or 2 -> 1, return here.
X		 */
X		if (cls(gchar(&pos)) != 0)
X			return &pos;
X	}
X
X	/* We're in white space; go to next non-white */
X
X	while (cls(gchar(&pos)) == 0) {
X		/*
X		 * We'll stop if we land on a blank line
X		 */
X		if (pos.index == 0 && pos.linep->s[0] == NUL)
X			break;
X
X		if (inc(&pos) == -1)
X			return NULL;
X	}
X
X	return &pos;
X}
X
X/*
X * bck_word(pos, type) - move backward one word
X *
X * Returns the resulting position, or NULL if EOF was reached.
X */
XLPTR *
Xbck_word(p, type)
XLPTR	*p;
Xint	type;
X{
X	static	LPTR	pos;
X	int	sclass = cls(gchar(p));		/* starting class */
X
X	pos = *p;
X
X	stype = type;
X
X	if (dec(&pos) == -1)
X		return NULL;
X
X	/*
X	 * If we're in the middle of a word, we just have to
X	 * back up to the start of it.
X	 */
X	if (cls(gchar(&pos)) == sclass && sclass != 0) {
X		/*
X		 * Move backward to start of the current word
X		 */
X		while (cls(gchar(&pos)) == sclass) {
X			if (dec(&pos) == -1)
X				return NULL;
X		}
X		inc(&pos);			/* overshot - forward one */
X		return &pos;
X	}
X
X	/*
X	 * We were at the start of a word. Go back to the start
X	 * of the prior word.
X	 */
X
X	while (cls(gchar(&pos)) == 0) {		/* skip any white space */
X		/*
X		 * We'll stop if we land on a blank line
X		 */
X		if (pos.index == 0 && pos.linep->s[0] == NUL)
X			return &pos;
X
X		if (dec(&pos) == -1)
X			return NULL;
X	}
X
X	sclass = cls(gchar(&pos));
X
X	/*
X	 * Move backward to start of this word.
X	 */
X	while (cls(gchar(&pos)) == sclass) {
X		if (dec(&pos) == -1)
X			return NULL;
X	}
X	inc(&pos);			/* overshot - forward one */
X
X	return &pos;
X}
X
X/*
X * end_word(pos, type, in_change) - move to the end of the word
X *
X * There is an apparent bug in the 'e' motion of the real vi. At least
X * on the System V Release 3 version for the 80386. Unlike 'b' and 'w',
X * the 'e' motion crosses blank lines. When the real vi crosses a blank
X * line in an 'e' motion, the cursor is placed on the FIRST character
X * of the next non-blank line. The 'E' command, however, works correctly.
X * Since this appears to be a bug, I have not duplicated it here.
X *
X * There's a strange special case here that the 'in_change' parameter
X * helps us deal with. Vi effectively turns 'cw' into 'ce'. If we're on
X * a word with only one character, we need to stick at the current
X * position so we don't change two words.
X *
X * Returns the resulting position, or NULL if EOF was reached.
X */
XLPTR *
Xend_word(p, type, in_change)
XLPTR	*p;
Xint	type;
Xbool_t	in_change;
X{
X	static	LPTR	pos;
X	int	sclass = cls(gchar(p));		/* starting class */
X
X	pos = *p;
X
X	stype = type;
X
X	if (inc(&pos) == -1)
X		return NULL;
X
X	/*
X	 * If we're in the middle of a word, we just have to
X	 * move to the end of it.
X	 */
X	if (cls(gchar(&pos)) == sclass && sclass != 0) {
X		/*
X		 * Move forward to end of the current word
X		 */
X		while (cls(gchar(&pos)) == sclass) {
X			if (inc(&pos) == -1)
X				return NULL;
X		}
X		dec(&pos);			/* overshot - forward one */
X		return &pos;
X	}
X
X	/*
X	 * We were at the end of a word. Go to the end of the next
X	 * word, unless we're doing a change. In that case we stick
X	 * at the end of the current word.
X	 */
X	if (in_change)
X		return p;
X
X	while (cls(gchar(&pos)) == 0) {		/* skip any white space */
X		if (inc(&pos) == -1)
X			return NULL;
X	}
X
X	sclass = cls(gchar(&pos));
X
X	/*
X	 * Move forward to end of this word.
X	 */
X	while (cls(gchar(&pos)) == sclass) {
X		if (inc(&pos) == -1)
X			return NULL;
X	}
X	dec(&pos);			/* overshot - forward one */
X
X	return &pos;
X}
HE_HATES_THESE_CANS
if test 18702 -ne "`wc -c < 'search.c'`"
then
	echo shar: error transmitting "'search.c'" '(should have been 18702 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'stevie.h'" '(4232 characters)'
if test -f 'stevie.h'
then
	echo shar: will not over-write existing file "'stevie.h'"
else
sed 's/^X//' << \HE_HATES_THESE_CANS > 'stevie.h'
X/*
X * $Header: /nw/tony/src/stevie/src/RCS/stevie.h,v 1.19 89/07/12 21:33:32 tony Exp $
X *
X * Main header file included by all source files.
X */
X
X#include "env.h"	/* defines to establish the compile-time environment */
X
X#include <stdio.h>
X#include <ctype.h>
X
X#ifdef	BSD
X
X#include <strings.h>
X#define strchr index
X
X#else
X
X#ifdef	MINIX
X
Xextern	char	*strchr();
Xextern	char	*strrchr();
Xextern	char	*strcpy();
Xextern	char	*strcat();
Xextern	int	strlen();
X
X#else
X#include <string.h>
X#endif
X
X#endif
X
X#include "ascii.h"
X#include "keymap.h"
X#include "param.h"
X#include "term.h"
X
Xextern	char	*strchr();
X
X#define NORMAL 0
X#define CMDLINE 1
X#define INSERT 2
X#define REPLACE 3
X#define FORWARD 4
X#define BACKWARD 5
X
X/*
X * Boolean type definition and constants
X */
Xtypedef	short	bool_t;
X
X#ifndef	TRUE
X#define	FALSE	(0)
X#define	TRUE	(1)
X#endif
X
X/*
X * SLOP is the amount of extra space we get for text on a line during
X * editing operations that need more space. This keeps us from calling
X * malloc every time we get a character during insert mode. No extra
X * space is allocated when the file is initially read.
X */
X#define	SLOP	10
X
X/*
X * LINEINC is the gap we leave between the artificial line numbers. This
X * helps to avoid renumbering all the lines every time a new line is
X * inserted.
X */
X#define	LINEINC	10
X
X#define CHANGED		Changed=TRUE
X#define UNCHANGED	Changed=FALSE
X
Xstruct	line {
X	struct	line	*prev, *next;	/* previous and next lines */
X	char	*s;			/* text for this line */
X	int	size;			/* actual size of space at 's' */
X	unsigned long	num;		/* line "number" */
X};
X
X#define	LINEOF(x)	((x)->linep->num)
X
Xstruct	lptr {
X	struct	line	*linep;		/* line we're referencing */
X	int	index;			/* position within that line */
X};
X
Xtypedef	struct line	LINE;
Xtypedef	struct lptr	LPTR;
X
Xstruct charinfo {
X	char ch_size;
X	char *ch_str;
X};
X
Xextern struct charinfo chars[];
X
Xextern	int	State;
Xextern	int	Rows;
Xextern	int	Columns;
Xextern	char	*Realscreen;
Xextern	char	*Nextscreen;
Xextern	char	*Filename;
Xextern	LPTR	*Filemem;
Xextern	LPTR	*Filetop;
Xextern	LPTR	*Fileend;
Xextern	LPTR	*Topchar;
Xextern	LPTR	*Botchar;
Xextern	LPTR	*Curschar;
Xextern	LPTR	*Insstart;
Xextern	int	Cursrow, Curscol, Cursvcol, Curswant;
Xextern	bool_t	set_want_col;
Xextern	int	Prenum;
Xextern	bool_t	Changed;
Xextern	char	Redobuff[], Insbuff[];
Xextern	char	*Insptr;
Xextern	int	Ninsert;
Xextern	bool_t	got_int;
X
Xextern	char	*malloc(), *strcpy();
X
X/*
X * alloc.c
X */
Xchar	*alloc(), *strsave(), *mkstr();
Xvoid	screenalloc(), filealloc(), freeall();
XLINE	*newline();
Xbool_t	bufempty(), buf1line(), lineempty(), endofline(), canincrease();
X
X/*
X * cmdline.c
X */
Xvoid	docmdln(), dotag(), msg(), emsg(), smsg(), gotocmd(), wait_return();
Xchar	*getcmdln();
X
X/*
X * edit.c
X */
Xvoid	edit(), insertchar(), getout(), scrollup(), scrolldown(), beginline();
Xbool_t	oneright(), oneleft(), oneup(), onedown();
X
X/*
X * fileio.c
X */
Xvoid	filemess(), renum();
Xbool_t	readfile(), writeit();
X
X/*
X * help.c
X */
Xbool_t	help();
X
X/*
X * linefunc.c
X */
XLPTR	*nextline(), *prevline(), *coladvance();
X
X/*
X * main.c
X */
Xvoid	stuffin(), stuffnum();
Xvoid	do_mlines();
Xint	vgetc();
Xbool_t	anyinput();
X
X/*
X * mark.c
X */
Xvoid	setpcmark(), clrall(), clrmark();
Xbool_t	setmark();
XLPTR	*getmark();
X
X/*
X * misccmds.c
X */
Xvoid	opencmd(), fileinfo(), inschar(), delline();
Xbool_t	delchar();
Xint	cntllines(), plines();
XLPTR	*gotoline();
X
X/*
X * normal.c
X */
Xvoid	normal();
X
X/*
X * param.c
X */
Xvoid	doset();
X
X/*
X * ptrfunc.c
X */
Xint	inc(), dec();
Xint	gchar();
Xvoid	pchar(), pswap();
Xbool_t	lt(), equal(), ltoreq();
X#if 0
X/* not currently used */
Xbool_t	gtoreq(), gt();
X#endif
X
X/*
X * screen.c
X */
Xvoid	updatescreen(), updateline();
Xvoid	screenclear(), cursupdate();
Xvoid	s_ins(), s_del();
Xvoid	prt_line();
X
X/*
X * search.c
X */
Xvoid	dosub(), doglob();
Xbool_t	searchc(), crepsearch(), findfunc(), dosearch(), repsearch();
XLPTR	*showmatch();
XLPTR	*fwd_word(), *bck_word(), *end_word();
X
X/*
X * undo.c
X */
Xvoid	u_save(), u_saveline(), u_clear();
Xvoid	u_lcheck(), u_lundo();
Xvoid	u_undo();
X
X/*
X * Machine-dependent routines.
X */
Xint	inchar();
Xvoid	flushbuf();
Xvoid	outchar(), outstr(), beep();
Xchar	*fixname();
X#ifndef	OS2
X#ifndef	DOS
Xvoid	remove(), rename();
X#endif
X#endif
Xvoid	windinit(), windexit(), windgoto();
Xvoid	delay();
Xvoid	doshell();
HE_HATES_THESE_CANS
if test 4232 -ne "`wc -c < 'stevie.h'`"
then
	echo shar: error transmitting "'stevie.h'" '(should have been 4232 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'term.c'" '(1685 characters)'
if test -f 'term.c'
then
	echo shar: will not over-write existing file "'term.c'"
else
sed 's/^X//' << \HE_HATES_THESE_CANS > 'term.c'
X/* $Header: /nw/tony/src/stevie/src/RCS/term.c,v 1.4 89/03/11 22:43:55 tony Exp $
X *
X * Termcap initialization (optional).
X */
X
X#include <stdio.h>
X#include "stevie.h"
X
X#ifdef	TERMCAP
X
Xstatic	char	buf[1024];	/* termcap entry read here */
Xstatic	char	cap[256];	/* capability strings go in here */
X
Xchar	*T_EL;		/* erase the entire current line */
Xchar	*T_IL;		/* insert one line */
Xchar	*T_DL;		/* delete one line */
Xchar	*T_SC;		/* save the cursor position */
Xchar	*T_ED;		/* erase display (may optionally home cursor) */
Xchar	*T_RC;		/* restore the cursor position */
Xchar	*T_CI;		/* invisible cursor (very optional) */
Xchar	*T_CV;		/* visible cursor (very optional) */
X
Xchar	*T_CM;		/* cursor motion string */
X
Xextern	int	tgetent(), tgetnum();
Xextern	char	*tgetstr();
Xextern	char	*getenv();
X
Xint
Xt_init()
X{
X	char	*term;
X	int	n;
X	char	*cp = cap;
X
X	if ((term = getenv("TERM")) == NULL)
X		return 0;
X
X	if (tgetent(buf, term) != 1)
X		return 0;
X
X	if ((n = tgetnum("li")) == -1)
X		return 0;
X	else
X		P(P_LI) = Rows = n;
X
X	if ((n = tgetnum("co")) == -1)
X		return 0;
X	else
X		Columns = n;
X
X	/*
X	 * Get mandatory capability strings.
X	 */
X	if ((T_CM = tgetstr("cm", &cp)) == NULL)
X		return 0;
X
X	if ((T_EL = tgetstr("ce", &cp)) == NULL)
X		return 0;
X
X	if ((T_ED = tgetstr("cl", &cp)) == NULL)
X		return 0;
X
X	/*
X	 * Optional capabilities.
X	 */
X	if ((T_IL = tgetstr("al", &cp)) == NULL)
X		T_IL = "";
X
X	if ((T_DL = tgetstr("dl", &cp)) == NULL)
X		T_DL = "";
X
X	if ((T_SC = tgetstr("sc", &cp)) == NULL)
X		T_SC = "";
X
X	if ((T_RC = tgetstr("rc", &cp)) == NULL)
X		T_RC = "";
X
X	if ((T_CI = tgetstr("vi", &cp)) == NULL)
X		T_CI = "";
X
X	if ((T_CV = tgetstr("ve", &cp)) == NULL)
X		T_CV = "";
X
X	return 1;
X}
X
X#endif
HE_HATES_THESE_CANS
if test 1685 -ne "`wc -c < 'term.c'`"
then
	echo shar: error transmitting "'term.c'" '(should have been 1685 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0
--