
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by tralfaz!ove on Wed Jan 13 14:07:00 PST 1988
# Contents:  region.c search.c spawn.c st520.c
 
echo x - region.c
sed 's/^@//' > "region.c" <<'@//E*O*F region.c//'

/*

 * The routines in this file

 * deal with the region, that magic space

 * between "." and mark. Some functions are

 * commands. Some functions are just for

 * internal use.

 */

#include	<stdio.h>

#include	"estruc.h"

#include	"edef.h"



#if	MEGAMAX & ST520

overlay "region"

#endif



/*

 * Kill the region. Ask "getregion"

 * to figure out the bounds of the region.

 * Move "." to the start, and kill the characters.

 * Bound to "C-W".

 */

killregion(f, n)

{

	register int	s;

	REGION		region;



        if (curbp->b_mode&MDVIEW)       /* don't allow this command if	*/

		return(rdonly());	/* we are in read only mode	*/

	if ((s=getregion(&region)) != TRUE)

		return (s);

	if ((lastflag&CFKILL) == 0)		/* This is a kill type	*/

		kdelete();			/* command, so do magic */

	thisflag |= CFKILL;			/* kill buffer stuff.	*/

	curwp->w_dotp = region.r_linep;

	curwp->w_doto = region.r_offset;

	return (ldelete(region.r_size, TRUE));

}



/*

 * Copy all of the characters in the

 * region to the kill buffer. Don't move dot

 * at all. This is a bit like a kill region followed

 * by a yank. Bound to "M-W".

 */

copyregion(f, n)

{

	register LINE	*linep;

	register int	loffs;

	register int	s;

	REGION		region;



	if ((s=getregion(&region)) != TRUE)

		return (s);

	if ((lastflag&CFKILL) == 0)		/* Kill type command.	*/

		kdelete();

	thisflag |= CFKILL;

	linep = region.r_linep; 		/* Current line.	*/

	loffs = region.r_offset;		/* Current offset.	*/

	while (region.r_size--) {

		if (loffs == llength(linep)) {	/* End of line. 	*/

			if ((s=kinsert('\n')) != TRUE)

				return (s);

			linep = lforw(linep);

			loffs = 0;

		} else {			/* Middle of line.	*/

			if ((s=kinsert(lgetc(linep, loffs))) != TRUE)

				return (s);

			++loffs;

		}

	}

	return (TRUE);

}



/*

 * Lower case region. Zap all of the upper

 * case characters in the region to lower case. Use

 * the region code to set the limits. Scan the buffer,

 * doing the changes. Call "lchange" to ensure that

 * redisplay is done in all buffers. Bound to

 * "C-X C-L".

 */

lowerregion(f, n)

{

	register LINE	*linep;

	register int	loffs;

	register int	c;

	register int	s;

	REGION		region;



        if (curbp->b_mode&MDVIEW)       /* don't allow this command if	*/

		return(rdonly());	/* we are in read only mode	*/

	if ((s=getregion(&region)) != TRUE)

		return (s);

	lchange(WFHARD);

	linep = region.r_linep;

	loffs = region.r_offset;

	while (region.r_size--) {

		if (loffs == llength(linep)) {

			linep = lforw(linep);

			loffs = 0;

		} else {

			c = lgetc(linep, loffs);

			if (c>='A' && c<='Z')

				lputc(linep, loffs, c+'a'-'A');

			++loffs;

		}

	}

	return (TRUE);

}



/*

 * Upper case region. Zap all of the lower

 * case characters in the region to upper case. Use

 * the region code to set the limits. Scan the buffer,

 * doing the changes. Call "lchange" to ensure that

 * redisplay is done in all buffers. Bound to

 * "C-X C-L".

 */

upperregion(f, n)

{

	register LINE	*linep;

	register int	loffs;

	register int	c;

	register int	s;

	REGION		region;



        if (curbp->b_mode&MDVIEW)       /* don't allow this command if	*/

		return(rdonly());	/* we are in read only mode	*/

	if ((s=getregion(&region)) != TRUE)

		return (s);

	lchange(WFHARD);

	linep = region.r_linep;

	loffs = region.r_offset;

	while (region.r_size--) {

		if (loffs == llength(linep)) {

			linep = lforw(linep);

			loffs = 0;

		} else {

			c = lgetc(linep, loffs);

			if (c>='a' && c<='z')

				lputc(linep, loffs, c-'a'+'A');

			++loffs;

		}

	}

	return (TRUE);

}



/*

 * This routine figures out the

 * bounds of the region in the current window, and

 * fills in the fields of the "REGION" structure pointed

 * to by "rp". Because the dot and mark are usually very

 * close together, we scan outward from dot looking for

 * mark. This should save time. Return a standard code.

 * Callers of this routine should be prepared to get

 * an "ABORT" status; we might make this have the

 * conform thing later.

 */

getregion(rp)

register REGION *rp;

{

	register LINE	*flp;

	register LINE	*blp;

	long fsize;

	long bsize;



	if (curwp->w_markp == NULL) {

		mlwrite("No mark set in this window");

		return (FALSE);

	}

	if (curwp->w_dotp == curwp->w_markp) {

		rp->r_linep = curwp->w_dotp;

		if (curwp->w_doto < curwp->w_marko) {

			rp->r_offset = curwp->w_doto;

			rp->r_size = (long)(curwp->w_marko-curwp->w_doto);

		} else {

			rp->r_offset = curwp->w_marko;

			rp->r_size = (long)(curwp->w_doto-curwp->w_marko);

		}

		return (TRUE);

	}

	blp = curwp->w_dotp;

	bsize = (long)curwp->w_doto;

	flp = curwp->w_dotp;

	fsize = (long)(llength(flp)-curwp->w_doto+1);

	while (flp!=curbp->b_linep || lback(blp)!=curbp->b_linep) {

		if (flp != curbp->b_linep) {

			flp = lforw(flp);

			if (flp == curwp->w_markp) {

				rp->r_linep = curwp->w_dotp;

				rp->r_offset = curwp->w_doto;

				rp->r_size = fsize+curwp->w_marko;

				return (TRUE);

			}

			fsize += llength(flp)+1;

		}

		if (lback(blp) != curbp->b_linep) {

			blp = lback(blp);

			bsize += llength(blp)+1;

			if (blp == curwp->w_markp) {

				rp->r_linep = blp;

				rp->r_offset = curwp->w_marko;

				rp->r_size = bsize - curwp->w_marko;

				return (TRUE);

			}

		}

	}

	mlwrite("Bug: lost mark");

	return (FALSE);

}

@//E*O*F region.c//
chmod u=rw,g=r,o=r region.c
 
echo x - search.c
sed 's/^@//' > "search.c" <<'@//E*O*F search.c//'
/*
 * The functions in this file implement commands that search in the forward
 * and backward directions.  There are no special characters in the search
 * strings.  Probably should have a regular expression search, or something
 * like that.
 *
 * Aug. 1986 John M. Gamble:
 *	Made forward and reverse search use the same scan routine.
 *
 *	Added a limited number of regular expressions - 'any',
 *	'character class', 'closure', 'beginning of line', and
 *	'end of line'.
 *
 *	Replacement metacharacters will have to wait for a re-write of
 *	the replaces function, and a new variation of ldelete().
 *
 *	For those curious as to my references, i made use of
 *	Kernighan & Plauger's "Software Tools."
 *	I deliberately did not look at any published grep or editor
 *	source (aside from this one) for inspiration.  I did make use of
 *	Allen Hollub's bitmap routines as published in Doctor Dobb's Journal,
 *	June, 1985 and modified them for the limited needs of character class
 *	matching.  Any inefficiences, bugs, stupid coding examples, etc.,
 *	are therefore my own responsibility.
 */

#include        <stdio.h>
#include	"estruc.h"
#include        "edef.h"
#include	"esearc.h"

/*
 * Reversed pattern array.
 */
char	tap[NPAT];

#if	MAGIC
/*
 * The variable magical determines if there are actual
 * metacharacters in the string - if not, then we don't
 * have to use the slower MAGIC mode search functions.
 *
 * The variable mclen holds the length of the matched
 * string - used by the replace functions.
 *
 * The arrays mcpat and tapcm hold the MC and reversed
 * MC search structures.
 */
short int	magical = FALSE;
int		mclen = 0;
MC		mcpat[NPAT];
MC		tapcm[NPAT];
#endif

/*
 * forwsearch -- Search forward.  Get a search string from the user, and
 *	search, beginning at ".", for the string.  If found, reset the "."
 *	to be just after the match string, and (perhaps) repaint the display.
 */

forwsearch(f, n)
{
	register int status = TRUE;

	/* Resolve the repeat count.
	 */
	if (n == 0)
		n = 1;

	/* If n is negative, search backwards.
	 * Otherwise proceed by asking for the search string.
	 */
	if (n < 0)
		status = backsearch(f, -n);

	/* Ask the user for the text of a pattern.  If the
	 * response is TRUE (responses other than FALSE are
	 * possible), search for the pattern.
	 */
	else if ((status = readpattern("Search", &pat[0], TRUE)) == TRUE)
	{
		do
		{
#if	MAGIC
			if ((magical && curwp->w_bufp->b_mode & MDMAGIC) != 0)
				status = mcscanner(&mcpat[0], FORWARD, PTEND);
			else
#endif
				status = scanner(&pat[0], FORWARD, PTEND);
		} while ((--n > 0) && status);

		/* ...and complain if not there.
		 */
		if (status == FALSE)
			mlwrite("Not found");
	}
	return(status);
}

/*
 * forwhunt -- Search forward for a previously acquired search string,
 *	beginning at ".".  If found, reset the "." to be just after
 *	the match string, and (perhaps) repaint the display.
 */

forwhunt(f, n)
{
	register int status = TRUE;

	/* Resolve the repeat count.
	 */
	if (n == 0)
		n = 1;
	else if (n < 0)		/* search backwards */
		return(backhunt(f, -n));

	/* Make sure a pattern exists, or that we didn't switch
	 * into MAGIC mode until after we entered the pattern.
	 */
	if (pat[0] == '\0')
	{
		mlwrite("No pattern set");
		return FALSE;
	}
#if	MAGIC
	if ((curwp->w_bufp->b_mode & MDMAGIC) != 0 &&
		 mcpat[0].mc_type == MCNIL)
	{
		if (!mcstr())
			return FALSE;
	}
#endif

	/* Search for the pattern...
	 */
	do
	{
#if	MAGIC
		if ((magical && curwp->w_bufp->b_mode & MDMAGIC) != 0)
			status = mcscanner(&mcpat[0], FORWARD, PTEND);
		else
#endif
			status = scanner(&pat[0], FORWARD, PTEND);
	} while ((--n > 0) && status);

	/* ...and complain if not there.
	 */
	if (status == FALSE)
		mlwrite("Not found");

	return(status);
}

/*
 * backsearch -- Reverse search.  Get a search string from the user, and
 *	search, starting at "." and proceeding toward the front of the buffer.
 *	If found "." is left pointing at the first character of the pattern
 *	(the last character that was matched).
 */
backsearch(f, n)
{
	register int status = TRUE;

	/* Resolve null and negative arguments.
	 */
	if (n == 0)
		n = 1;

	/* If n is negative, search forwards.
	 * Otherwise proceed by asking for the search string.
	 */
	if (n < 0)
		status = forwsearch(f, -n);

	/* Ask the user for the text of a pattern.  If the
	 * response is TRUE (responses other than FALSE are
	 * possible), search for the pattern.
	 */
	else if ((status = readpattern("Reverse search", &pat[0], TRUE)) == TRUE)
	{
		do
		{
#if	MAGIC
			if ((magical && curwp->w_bufp->b_mode & MDMAGIC) != 0)
				status = mcscanner(&tapcm[0], REVERSE, PTBEG);
			else
#endif
				status = scanner(&tap[0], REVERSE, PTBEG);
		} while ((--n > 0) && status);

		/* ...and complain if not there.
		 */
		if (status == FALSE)
			mlwrite("Not found");
	}
	return(status);
}

/*
 * backhunt -- Reverse search for a previously acquired search string,
 *	starting at "." and proceeding toward the front of the buffer.
 *	If found "." is left pointing at the first character of the pattern
 *	(the last character that was matched).
 */
backhunt(f, n)
{
	register int	status = TRUE;

	/* Resolve null and negative arguments.
	 */
	if (n == 0)
		n = 1;
	else if (n < 0)
		return(forwhunt(f, -n));

	/* Make sure a pattern exists, or that we didn't switch
	 * into MAGIC mode until after we entered the pattern.
	 */
	if (tap[0] == '\0')
	{
		mlwrite("No pattern set");
		return FALSE;
	}
#if	MAGIC
	if ((curwp->w_bufp->b_mode & MDMAGIC) != 0 &&
		 tapcm[0].mc_type == MCNIL)
	{
		if (!mcstr())
			return FALSE;
	}
#endif

	/* Go search for it...
	 */
	do
	{
#if	MAGIC
		if ((magical && curwp->w_bufp->b_mode & MDMAGIC) != 0)
			status = mcscanner(&tapcm[0], REVERSE, PTBEG);
		else
#endif
			status = scanner(&tap[0], REVERSE, PTBEG);
	} while ((--n > 0) && status);

	/* ...and complain if not there.
	 */
	if (status == FALSE)
		mlwrite("Not found");

	return(status);
}

#if	MAGIC
/*
 * mcscanner -- Search for a meta-pattern in either direction.
 */
int	mcscanner(mcpatrn, direct, beg_or_end)
MC	*mcpatrn;		/* pointer into pattern */
int	direct;		/* which way to go.*/
int	beg_or_end;	/* put point at beginning or end of pattern.*/
{
	register LINE *lastline;	/* last line position during scan */
	register int lastoff;		/* position within last line */
	LINE *curline;			/* current line during scan */
	int curoff;			/* position within current line */
	int c;				/* (dummy) char at current position */

	/* If we are going in reverse, then the 'end' is actually
	 * the beginning of the pattern.  Toggle it.
	 */
	beg_or_end ^= direct;

	/* Setup local scan pointers to global ".".
	 */
	curline = curwp->w_dotp;
	curoff  = curwp->w_doto;

	/* Scan each character until we hit the head link record.
	 */
	while (!boundry(curline, curoff, direct))
	{
		/* Save the current position in case we need to
		 * restore it on a match, and initialize mclen to
		 * zero in case we are doing a search for replacement.
		 */
		lastline = curline;
		lastoff = curoff;
		mclen = 0;

		if (amatch(mcpatrn, direct, &curline, &curoff))
		{
			/* A SUCCESSFULL MATCH!!!
			 * reset the global "." pointers.
			 */
			if (beg_or_end == PTEND)	/* at end of string */
			{
				curwp->w_dotp = curline;
				curwp->w_doto = curoff;
			}
			else		/* at beginning of string */
			{
				curwp->w_dotp = lastline;
				curwp->w_doto = lastoff;
			}

			curwp->w_flag |= WFMOVE; /* flag that we have moved */
			return TRUE;
		}

		/* Advance the cursor.
		 */
		c = nextch(&curline, &curoff, direct);
	}

	return FALSE;	/* We could not find a match.*/
}

/*
 * amatch -- Search for a meta-pattern in either direction.  Based on the
 *	recursive routine amatch() (for "anchored match") in
 *	Kernighan & Plauger's "Software Tools".
 */
int	amatch(mcptr, direct, pcwline, pcwoff)
register MC	*mcptr;	/* string to scan for */
int		direct;		/* which way to go.*/
LINE		**pcwline;	/* current line during scan */
int		*pcwoff;	/* position within current line */
{
	register int c;			/* character at current position */
	LINE *curline;			/* current line during scan */
	int curoff;			/* position within current line */
	int nchars;

	/* Set up local scan pointers to ".", and get
	 * the current character.  Then loop around
	 * the pattern pointer until success or failure.
	 */
	curline = *pcwline;
	curoff = *pcwoff;

	/* The beginning-of-line and end-of-line metacharacters
	 * do not compare against characters, they compare
	 * against positions.
	 * BOL is guaranteed to be at the start of the pattern
	 * for forward searches, and at the end of the pattern
	 * for reverse searches.  The reverse is true for EOL.
	 * So, for a start, we check for them on entry.
	 */
	if (mcptr->mc_type == BOL)
	{
		if (curoff != 0)
			return FALSE;
		mcptr++;
	}

	if (mcptr->mc_type == EOL)
	{
		if (curoff != llength(curline))
			return FALSE;
		mcptr++;
	}

	while (mcptr->mc_type != MCNIL)
	{
		c = nextch(&curline, &curoff, direct);

		if (mcptr->mc_type & CLOSURE)
		{
			/* Try to match as many characters as possible
			 * against the current meta-character.  A
			 * newline never matches a closure.
			 */
			nchars = 0;
			while (c != '\n' && mceq(c, mcptr))
			{
				c = nextch(&curline, &curoff, direct);
				nchars++;
			}

			/* We are now at the character that made us
			 * fail.  Try to match the rest of the pattern.
			 * Shrink the closure by one for each failure.
			 * Since closure matches *zero* or more occurences
			 * of a pattern, a match may start even if the
			 * previous loop matched no characters.
			 */
			mcptr++;

			for (;;)
			{
				c = nextch(&curline, &curoff, direct ^ REVERSE);

				if (amatch(mcptr, direct, &curline, &curoff))
				{
					mclen += nchars;
					goto success;
				}

				if (nchars-- == 0)
					return FALSE;
			}
		}
		else			/* Not closure.*/
		{
			/* The only way we'd get a BOL metacharacter
			 * at this point is at the end of the reversed pattern.
			 * The only way we'd get an EOL metacharacter
			 * here is at the end of a regular pattern.
			 * So if we match one or the other, and are at
			 * the appropriate position, we are guaranteed success
			 * (since the next pattern character has to be MCNIL).
			 * Before we report success, however, we back up by
			 * one character, so as to leave the cursor in the
			 * correct position.  For example, a search for ")$"
			 * will leave the cursor at the end of the line, while
			 * a search for ")<NL>" will leave the cursor at the
			 * beginning of the next line.  This follows the
			 * notion that the meta-character '$' (and likewise
			 * '^') match positions, not characters.
			 */
			if (mcptr->mc_type == BOL)
				if (curoff == llength(curline))
				{
					c = nextch(&curline, &curoff,
						   direct ^ REVERSE);
					goto success;
				}
				else
					return FALSE;

			if (mcptr->mc_type == EOL)
				if (curoff == 0)
				{
					c = nextch(&curline, &curoff,
						   direct ^ REVERSE);
					goto success;
				}
				else
					return FALSE;

			/* Neither BOL nor EOL, so go through
			 * the meta-character equal function.
			 */
			if (!mceq(c, mcptr))
				return FALSE;
		}

		/* Increment the length counter and
		 * advance the pattern pointer.
		 */
		mclen++;
		mcptr++;
	}			/* End of mcptr loop.*/

	/* A SUCCESSFULL MATCH!!!
	 * Reset the "." pointers.
	 */
success:
	*pcwline = curline;
	*pcwoff  = curoff;

	return TRUE;
}
#endif

/*
 * scanner -- Search for a pattern in either direction.
 */
int	scanner(patrn, direct, beg_or_end)
char	*patrn;		/* string to scan for */
int	direct;		/* which way to go.*/
int	beg_or_end;	/* put point at beginning or end of pattern.*/
{
	register int c;			/* character at current position */
	register char *patptr;		/* pointer into pattern */
	register LINE *lastline;	/* last line position during scan */
	register int lastoff;		/* position within last line */
	LINE *curline;			/* current line during scan */
	int curoff;			/* position within current line */
	LINE *matchline;		/* current line during matching */
	int matchoff;			/* position in matching line */

	/* If we are going in reverse, then the 'end' is actually
	 * the beginning of the pattern.  Toggle it.
	 */
	beg_or_end ^= direct;

	/* Setup local scan pointers to global ".".
	 */
	curline = curwp->w_dotp;
	curoff = curwp->w_doto;

	/* Scan each character until we hit the head link record.
	 */
	while (!boundry(curline, curoff, direct))
	{
		/* Save the current position in case we need to
		 * restore it on a match.
		 */
		lastline = curline;
		lastoff = curoff;

		/* Get the character resolving newlines, and
		 * test it against first char in pattern.
		 */
		c = nextch(&curline, &curoff, direct);

		if (eq(c, patrn[0]))	/* if we find it..*/
		{
			/* Setup match pointers.
			 */
			matchline = curline;
			matchoff = curoff;
			patptr = &patrn[0];

			/* Scan through the pattern for a match.
			 */
			while (*++patptr != '\0')
			{
				c = nextch(&matchline, &matchoff, direct);

				if (!eq(c, *patptr))
					goto fail;
			}

			/* A SUCCESSFULL MATCH!!!
			 * reset the global "." pointers
			 */
			if (beg_or_end == PTEND)	/* at end of string */
			{
				curwp->w_dotp = matchline;
				curwp->w_doto = matchoff;
			}
			else		/* at beginning of string */
			{
				curwp->w_dotp = lastline;
				curwp->w_doto = lastoff;
			}

			curwp->w_flag |= WFMOVE; /* Flag that we have moved.*/
			return TRUE;

		}
fail:;			/* continue to search */
	}

	return FALSE;	/* We could not find a match */
}

/*
 * eq -- Compare two characters.  The "bc" comes from the buffer, "pc"
 *	from the pattern.  If we are not in EXACT mode, fold out the case.
 */
int	eq(bc, pc)
register int	bc;
register int	pc;
{
	if ((curwp->w_bufp->b_mode & MDEXACT) == 0)
	{
		if (islower(bc))
			bc ^= DIFCASE;

		if (islower(pc))
			pc ^= DIFCASE;
	}

	return (bc == pc);
}

/*
 * readpattern -- Read a pattern.  Stash it in apat.  If it is the
 *	search string, create the reverse pattern and the magic
 *	pattern, assuming we are in MAGIC mode (and defined that way).
 *	Apat is not updated if the user types in an empty line.  If
 *	the user typed an empty line, and there is no old pattern, it is
 *	an error.  Display the old pattern, in the style of Jeff Lomicka.
 *	There is some do-it-yourself control expansion.  Change to using
 *	<META> to delimit the end-of-pattern to allow <NL>s in the search
 *	string. 
 */
int	readpattern(prompt, apat, srch)
char	*prompt;
char	apat[];
int	srch;
{
	int status;
	char tpat[NPAT+20];

	strcpy(tpat, prompt);	/* copy prompt to output string */
	strcat(tpat, " [");	/* build new prompt string */
	expandp(&apat[0], &tpat[strlen(tpat)], NPAT/2);	/* add old pattern */
	strcat(tpat, "]<META>: ");

	/* Read a pattern.  Either we get one,
	 * or we just get the META charater, and use the previous pattern.
	 * Then, if it's the search string, make a reversed pattern.
	 * *Then*, make the meta-pattern, if we are defined that way.
	 */
	if ((status = mlreplyt(tpat, tpat, NPAT, metac)) == TRUE)
	{
		strcpy(apat, tpat);
		if (srch)	/* If we are doing the search string.*/
		{
			/* Reverse string copy.
			 */
			rvstrcpy(tap, apat);
#if	MAGIC
			/* Only make the meta-pattern if in magic mode,
			 * since the pattern in question might have an
			 * invalid meta combination.
			 */
			if ((curwp->w_bufp->b_mode & MDMAGIC) == 0)
				mcpat[0].mc_type = tapcm[0].mc_type = MCNIL;
			else
				status = mcstr();
#endif
		}
	}
	else if (status == FALSE && apat[0] != 0)	/* Old one */
		status = TRUE;

	return(status);
}

/*
 * rvstrcpy -- Reverse string copy.
 */
rvstrcpy(rvstr, str)
register char	*rvstr, *str;
{
	register int i;

	str += (i = strlen(str));

	while (i-- > 0)
		*rvstr++ = *--str;

	*rvstr = '\0';
}

/*
 * sreplace -- Search and replace.
 */
sreplace(f, n)
int f;		/* default flag */
int n;		/* # of repetitions wanted */
{
	return(replaces(FALSE, f, n));
}

/*
 * qreplace -- search and replace with query.
 */
qreplace(f, n)
int f;		/* default flag */
int n;		/* # of repetitions wanted */
{
#if	CRAY	/* user must not buffer output */
int fl ;
	fl = replaces(TRUE, f, n);
	sends("\\(i)") ;	/* immediate off */
	return(fl) ;
#else
	return(replaces(TRUE, f, n));
#endif
}

/*
 * replaces -- Search for a string and replace it with another
 *	string.  Query might be enabled (according to kind).
 */
int	replaces(kind, f, n)
int	kind;	/* Query enabled flag */
int	f;	/* default flag */
int	n;	/* # of repetitions wanted */
{
	register int i;		/* loop index */
	register int status;	/* success flag on pattern inputs */
	register int slength,
		     rlength;	/* length of search and replace strings */
	register int numsub;	/* number of substitutions */
	register int nummatch;	/* number of found matches */
	int nlflag;		/* last char of search string a <NL>? */
	int nlrepl;		/* was a replace done on the last line? */
	char tmpc;		/* temporary character */
	char c;			/* input char for query */
	char tpat[NPAT];	/* temporary to hold search pattern */
	LINE *origline;		/* original "." position */
	int origoff;		/* and offset (for . query option) */
	LINE *lastline;		/* position of last replace and */
	int lastoff;		/* offset (for 'u' query option) */

	if (curbp->b_mode & MDVIEW)	/* don't allow this command if	*/
		return(rdonly());	/* we are in read only mode	*/

	/* Check for negative repetitions.
	 */
	if (f && n < 0)
		return(FALSE);

	/* Ask the user for the text of a pattern.
	 */
	if ((status = readpattern(
	    (kind == FALSE ? "Replace" : "Query replace"), &pat[0], TRUE))
								!= TRUE)
		return(status);

	/* Ask for the replacement string.
	 */
	if ((status = readpattern("with", &rpat[0], FALSE)) == ABORT)
		return(status);

	/* Find the lengths of the strings.
	 */
	slength = strlen(&pat[0]);
	rlength = strlen(&rpat[0]);

	/* Set up flags so we can make sure not to do a recursive
	 * replace on the last line.
	 */
	nlflag = (pat[slength - 1] == '\n');
	nlrepl = FALSE;

	if (kind)
	{
		/* Build query replace question string.
		 */
		strcpy(tpat, "Replace '");
		expandp(&pat[0], &tpat[strlen(tpat)], NPAT/3);
		strcat(tpat, "' with '");
		expandp(&rpat[0], &tpat[strlen(tpat)], NPAT/3);
		strcat(tpat, "'? ");

		/* Initialize last replaced pointers.
		 */
		lastline = NULL;
		lastoff = 0;
#if	CRAY
		sends("\\(I)") ;	/* immediate on */
#endif
	}

	/* Save original . position, init the number of matches and
	 * substitutions, and scan through the file.
	 */
	origline = curwp->w_dotp;
	origoff = curwp->w_doto;
	numsub = 0;
	nummatch = 0;

	while ( (f == FALSE || n > nummatch) &&
		(nlflag == FALSE || nlrepl == FALSE) )
	{
		/* Search for the pattern.
		 * If we search with a regular expression, also save
		 * the true length of matched string.
		 */
#if	MAGIC
		if ((magical && curwp->w_bufp->b_mode & MDMAGIC) != 0)
		{
			if (!mcscanner(&mcpat[0], FORWARD, PTBEG))
				break;
			slength = mclen;
		}
		else
#endif
			if (!scanner(&pat[0], FORWARD, PTBEG))
				break;		/* all done */

		++nummatch;	/* Increment # of matches */

		/* Check if we are on the last line.
		 */
		nlrepl = (lforw(curwp->w_dotp) == curwp->w_bufp->b_linep);

		/* Check for query.
		 */
		if (kind)
		{
			/* Get the query.
			 */
pprompt:		mlwrite(&tpat[0], &pat[0], &rpat[0]);
qprompt:
			update();  /* show the proposed place to change */
			c = tgetc();			/* and input */
			mlwrite("");			/* and clear it */

			/* And respond appropriately.
			 */
			switch (c)
			{
				case 'y':	/* yes, substitute */
				case ' ':
					break;

				case 'n':	/* no, onword */
					forwchar(FALSE, 1);
					continue;

				case '!':	/* yes/stop asking */
					kind = FALSE;
					break;

				case 'u':	/* undo last and re-prompt */

					/* Restore old position.
					 */
					if (lastline == NULL)
					{
						/* There is nothing to undo.
						 */
						TTbeep();
						goto qprompt;
					}
					curwp->w_dotp = lastline;
					curwp->w_doto = lastoff;
					lastline = NULL;
					lastoff = 0;

					/* Delete the new string.
					 */
					backchar(FALSE, rlength);
					if (!ldelete(rlength, FALSE))
					{
						mlwrite("%%ERROR while deleting");
						return(FALSE);
					}

					/* And put in the old one.
					 */
					for (i = 0; i < slength; i++)
					{
						tmpc = pat[i];
						status = (tmpc == '\n'?
							lnewline():
							linsert(1, tmpc));

						/* Insertion error?
						 */
						if (!status)
						{
							mlwrite("%%Out of memory while inserting");
							return(FALSE);
						}
					}

					/* Record one less substitution,
					 * backup, and reprompt.
					 */
					--numsub;
					backchar(FALSE, slength);
					goto pprompt;

				case '.':	/* abort! and return */
					/* restore old position */
					curwp->w_dotp = origline;
					curwp->w_doto = origoff;
					curwp->w_flag |= WFMOVE;

				case BELL:	/* abort! and stay */
					mlwrite("Aborted!");
					return(FALSE);

				default:	/* bitch and beep */
					TTbeep();

				case '?':	/* help me */
					mlwrite(
"(Y)es, (N)o, (!)Do rest, (U)ndo last, (^G)Abort, (.)Abort back, (?)Help: ");
					goto qprompt;

			}	/* end of switch */
		}	/* end of "if kind" */

		/*
		 * Delete the sucker.
		 */
		if (!ldelete(slength, FALSE))
		{
			mlwrite("%%ERROR while deleteing");
			return(FALSE);
		}

		/* And insert its replacement.
		 */
		for (i = 0; i < rlength; i++)
		{
			tmpc = rpat[i];
			status = (tmpc == '\n'? lnewline(): linsert(1, tmpc));

			/* Insertion error?
			 */
			if (!status)
			{
				mlwrite("%%Out of memory while inserting");
				return(FALSE);
			}
		}

		/* Save where we are if we might undo this....
		 */
		if (kind)
		{
			lastline = curwp->w_dotp;
			lastoff = curwp->w_doto;
		}

		numsub++;	/* increment # of substitutions */
	}

	/* And report the results.
	 */
	mlwrite("%d substitutions", numsub);
	return(TRUE);
}

/*
 * expandp -- Expand control key sequences for output.
 */
expandp(srcstr, deststr, maxlength)
char *srcstr;	/* string to expand */
char *deststr;	/* destination of expanded string */
int maxlength;	/* maximum chars in destination */
{
	char c;		/* current char to translate */

	/* Scan through the string.
	 */
	while ((c = *srcstr++) != 0)
	{
		if (c == '\n')		/* it's a newline */
		{
			*deststr++ = '<';
			*deststr++ = 'N';
			*deststr++ = 'L';
			*deststr++ = '>';
			maxlength -= 4;
		}
		else if (c < 0x20 || c == 0x7f)	/* control character */
		{
			*deststr++ = '^';
			*deststr++ = c ^ 0x40;
			maxlength -= 2;
		}
		else if (c == '%')
		{
			*deststr++ = '%';
			*deststr++ = '%';
			maxlength -= 2;
		}
		else			/* any other character */
		{
			*deststr++ = c;
			maxlength--;
		}

		/* check for maxlength */
		if (maxlength < 4)
		{
			*deststr++ = '$';
			*deststr = '\0';
			return(FALSE);
		}
	}
	*deststr = '\0';
	return(TRUE);
}

/*
 * boundry -- Return information depending on whether we may search no
 *	further.  Beginning of file and end of file are the obvious
 *	cases, but we may want to add further optional boundry restrictions
 *	in future, a' la VMS EDT.  At the moment, just return TRUE or
 *	FALSE depending on if a boundry is hit (ouch).
 */
int	boundry(curline, curoff, dir)
LINE	*curline;
int	curoff, dir;
{
	register int	border;

	if (dir == FORWARD)
	{
		border = (curoff == llength(curline)) &&
			 (lforw(curline) == curbp->b_linep);
	}
	else
	{
		border = (curoff == 0) &&
			 (lback(curline) == curbp->b_linep);
	}
	return (border);
}

/*
 * nextch -- retrieve the next/previous character in the buffer,
 *	and advance/retreat the point.
 *	The order in which this is done is significant, and depends
 *	upon the direction of the search.  Forward searches look at
 *	the current character and move, reverse searches move and
 *	look at the character.
 */
int	nextch(pcurline, pcuroff, dir)
LINE	**pcurline;
int	*pcuroff;
int	dir;
{
	register LINE	*curline;
	register int	curoff;
	register int	c;

	curline = *pcurline;
	curoff = *pcuroff;

	if (dir == FORWARD)
	{
		if (curoff == llength(curline))		/* if at EOL */
		{
			curline = lforw(curline);	/* skip to next line */
			curoff = 0;
			c = '\n';			/* and return a <NL> */
		}
		else
			c = lgetc(curline, curoff++);	/* get the char */
	}
	else			/* Reverse.*/
	{
		if (curoff == 0)
		{
			curline = lback(curline);
			curoff = llength(curline);
			c = '\n';
		}
		else
			c = lgetc(curline, --curoff);

	}
	*pcurline = curline;
	*pcuroff = curoff;

	return (c);
}

#if	MAGIC
/*
 * mcstr -- Set up the 'magic' array.  The closure symbol is taken as
 *	a literal character when (1) it is the first character in the
 *	pattern, and (2) when preceded by a symbol that does not allow
 *	closure, such as a newline, beginning of line symbol, or another
 *	closure symbol.
 *
 *	Coding comment (jmg):  yes, i know i have gotos that are, strictly
 *	speaking, unnecessary.  But right now we are so cramped for
 *	code space that i will grab what i can in order to remain
 *	within the 64K limit.  C compilers actually do very little
 *	in the way of optimizing - they expect you to do that.
 */
int	mcstr()
{
	MC	*mcptr, *rtpcm;
	char	*patptr;
 	int	mj;
 	int	pchr;
 	int	status = TRUE;
 	int	does_closure = FALSE;

	/* If we had metacharacters in the MC array previously,
	 * free up any bitmaps that may have been allocated.
	 */
	if (magical)
		freebits();

	magical = FALSE;
	mj = 0;
	mcptr = &mcpat[0];
	patptr = &pat[0];

	while ((pchr = *patptr) && status)
	{
		switch (pchr)
		{
			case MC_CCL:
				status = cclmake(&patptr, mcptr);
				magical = TRUE;
				does_closure = TRUE;
				break;
			case MC_BOL:
				if (mj != 0)
					goto litcase;

				mcptr->mc_type = BOL;
				magical = TRUE;
				does_closure = FALSE;
				break;
			case MC_EOL:
				if (*(patptr + 1) != '\0')
					goto litcase;

				mcptr->mc_type = EOL;
				magical = TRUE;
				does_closure = FALSE;
				break;
			case MC_ANY:
				mcptr->mc_type = ANY;
				magical = TRUE;
				does_closure = TRUE;
				break;
			case MC_CLOSURE:
				/* Does the closure symbol mean closure here?
				 * If so, back up to the previous element
				 * and indicate it is enclosed.
				 */
				if (!does_closure)
					goto litcase;
				mj--;
				mcptr--;
				mcptr->mc_type |= CLOSURE;
				magical = TRUE;
				does_closure = FALSE;
				break;

			/* Note: no break between MC_ESC case and the default.
			 */
			case MC_ESC:
				if (*(patptr + 1) != '\0')
				{
					pchr = *++patptr;
					magical = TRUE;
				}
			default:
litcase:			mcptr->mc_type = LITCHAR;
				mcptr->u.lchar = pchr;
				does_closure = (pchr != '\n');
				break;
		}		/* End of switch.*/
		mcptr++;
		patptr++;
		mj++;
	}		/* End of while.*/

	/* Close off the meta-string.
	 */
	mcptr->mc_type = MCNIL;

	/* Set up the reverse array, if the status is good.  Please note the
	 * structure assignment - your compiler may not like that.
	 * If the status is not good, nil out the meta-pattern.
	 * The only way the status would be bad is from the cclmake()
	 * routine, and the bitmap for that member is guarenteed to be
	 * freed.  So we stomp a MCNIL value there, call freebits() to
	 * free any other bitmaps, and set the zeroth array to MCNIL.
	 */
	if (status)
	{
		rtpcm = &tapcm[0];
		while (--mj >= 0)
		{
#if	LATTICE
			movmem(--mcptr, rtpcm++, sizeof (MC));
#endif

#if	MWC86 | AZTEC | MSC | VMS | USG | BSD | V7
			*rtpcm++ = *--mcptr;
#endif
		}
		rtpcm->mc_type = MCNIL;
	}
	else
	{
		(--mcptr)->mc_type = MCNIL;
		freebits();
		mcpat[0].mc_type = tapcm[0].mc_type = MCNIL;
	}

	return(status);
}

/*
 * mceq -- meta-character equality with a character.  In Kernighan & Plauger's
 *	Software Tools, this is the function omatch(), but i felt there
 *	were too many functions with the 'match' name already.
 */
int	mceq(bc, mt)
int	bc;
MC	*mt;
{
	register int result;

	switch (mt->mc_type & MASKCL)
	{
		case LITCHAR:
			result = eq(bc, mt->u.lchar);
			break;

		case ANY:
			result = (bc != '\n');
			break;

		case CCL:
			if (!(result = biteq(bc, mt->u.cclmap)))
			{
				if ((curwp->w_bufp->b_mode & MDEXACT) == 0 &&
				    (isletter(bc)))
				{
					result = biteq(CHCASE(bc), mt->u.cclmap);
				}
			}
			break;

		case NCCL:
			result = !biteq(bc, mt->u.cclmap);

			if ((curwp->w_bufp->b_mode & MDEXACT) == 0 &&
			    (isletter(bc)))
			{
				result &= !biteq(CHCASE(bc), mt->u.cclmap);
			}
			break;

		default:
			mlwrite("mceq: what is %d?", mt->mc_type);
			result = FALSE;
			break;

	}	/* End of switch.*/

	return (result);
}

/*
 * cclmake -- create the bitmap for the character class.
 *	ppatptr is left pointing to the end-of-character-class character,
 *	so that a loop may automatically increment with safety.
 */
int	cclmake(ppatptr, mcptr)
char	**ppatptr;
MC	*mcptr;
{
	BITMAP		clearbits();
	BITMAP		bmap;
	register char	*patptr;
	register int	pchr, ochr;

	if ((bmap = clearbits()) == NULL)
	{
		mlwrite("%%Out of memory");
		return FALSE;
	}

	mcptr->u.cclmap = bmap;
	patptr = *ppatptr;

	/*
	 * Test the initial character(s) in ccl for
	 * special cases - negate ccl, or an end ccl
	 * character as a first character.  Anything
	 * else gets set in the bitmap.
	 */
	if (*++patptr == MC_NCCL)
	{
		patptr++;
		mcptr->mc_type = NCCL;
	}
	else
		mcptr->mc_type = CCL;

	if ((ochr = *patptr) == MC_ECCL)
	{
		mlwrite("%%No characters in character class");
		return (FALSE);
	}
	else
	{
		if (ochr == MC_ESC)
			ochr = *++patptr;

		setbit(ochr, bmap);
		patptr++;
	}

	while (ochr != '\0' && (pchr = *patptr) != MC_ECCL)
	{
		switch (pchr)
		{
			/* Range character loses its meaning
			 * if it is the last character in
			 * the class.
			 */
			case MC_RCCL:
				if (*(patptr + 1) == MC_ECCL)
					setbit(pchr, bmap);
				else
				{
					pchr = *++patptr;
					while (++ochr <= pchr)
						setbit(ochr, bmap);
				}
				break;

			/* Note: no break between case MC_ESC and the default.
			 */
			case MC_ESC:
				pchr = *++patptr;
			default:
				setbit(pchr, bmap);
				break;
		}
		patptr++;
		ochr = pchr;
	}

	*ppatptr = patptr;

	if (ochr == '\0')
	{
		mlwrite("%%Character class not ended");
		free(bmap);
		return FALSE;
	}
	return TRUE;
}

/*
 * biteq -- is the character in the bitmap?
 */
int	biteq(bc, cclmap)
int	bc;
BITMAP	cclmap;
{
	if (bc >= HICHAR)
		return FALSE;

	return( (*(cclmap + (bc >> 3)) & BIT(bc & 7))? TRUE: FALSE );
}

/*
 * clearbits -- Allocate and zero out a CCL bitmap.
 */
BITMAP clearbits()
{
	char		*malloc();

	BITMAP		cclstart, cclmap;
	register int	j;

	if ((cclmap = cclstart = (BITMAP) malloc(HIBYTE)) != NULL)
		for (j = 0; j < HIBYTE; j++)
			*cclmap++ = 0;

	return (cclstart);
}

/*
 * freebits -- Free up any CCL bitmaps.
 */
freebits()
{
	register MC	*mcptr;

	mcptr = &mcpat[0];

	while (mcptr->mc_type != MCNIL)
	{
		if ((mcptr->mc_type & MASKCL) == CCL ||
		    (mcptr->mc_type & MASKCL) == NCCL)
			free(mcptr->u.cclmap);
		mcptr++;
	}
}

/*
 * setbit -- Set a bit (ON only) in the bitmap.
 */
setbit(bc, cclmap)
int	bc;
BITMAP	cclmap;
{
	if (bc < HICHAR)
		*(cclmap + (bc >> 3)) |= BIT(bc & 7);
}
#endif
@//E*O*F search.c//
chmod u=rw,g=r,o=r search.c
 
echo x - spawn.c
sed 's/^@//' > "spawn.c" <<'@//E*O*F spawn.c//'
/*	Spawn:	various DOS access commands
		for MicroEMACS
*/

#include	<stdio.h>
#include	"estruc.h"
#include	"edef.h"

/* not supported by Cray CTSS C v1.0, make the routines no-ops */
#if CRAY
#undef USG
#endif

#if	AMIGA
#define  NEW   1006
#endif

#if		ST520
#include <osbind.h>
#include <string.h>
#define LOAD_EXEC 0	/* load and execute the program */
char	*STcmd, 	/* the command filename & path	*/
	*STargs,	/* command args (if any)	*/
	*STenv, 	/* environment			*/
	*STwork;	/* work area			*/
#endif

#if	VMS
#define EFN	0				/* Event flag.		*/

#include	<ssdef.h>			/* Random headers.	*/
#include	<stsdef.h>
#include	<descrip.h>
#include	<iodef.h>

extern	int	oldmode[3];			/* In "termio.c"	*/
extern	int	newmode[3];			/* In "termio.c"	*/
extern	short	iochan; 			/* In "termio.c"	*/
#endif

#if	V7 | USG | BSD
#include	<signal.h>
extern int vttidy();
#endif

#if	MSDOS & MSC
#include	<process.h>
#define system(a)	spawnlp(P_WAIT, a, NULL)
#endif

/*
 * Create a subjob with a copy of the command intrepreter in it. When the
 * command interpreter exits, mark the screen as garbage so that you do a full
 * repaint. Bound to "^X C". The message at the start in VMS puts out a
 * newline. Under some (unknown) condition, you don't get one free when DCL
 * starts up.
 */
spawncli(f, n)
{
#if	AMIGA
	long newcli;
#endif

#if	V7 | USG | BSD
	register char *cp;
	char	*getenv();
#endif

        /* don't allow this command if restricted */
	if (restflag)
		return(resterr());

#if	AMIGA
	newcli = Open("CON:1/1/639/199/MicroEmacs Subprocess", NEW);
	mlwrite("[Starting new CLI]");
	sgarbf = TRUE;
	Execute("", newcli, 0);
	Close(newcli);
	return(TRUE);
#endif

#if	VMS
	movecursor(term.t_nrow, 0);		/* In last line.	*/
	mlputs("[Starting DCL]\r\n");
	TTflush();			     /* Ignore "ttcol".      */
	sgarbf = TRUE;
	return (sys(NULL));			/* NULL => DCL. 	*/
#endif
#if	CPM
	mlwrite("Not in CP/M-86");
#endif
#if	ST520
	mlwrite("Not in TOS");
#endif
#if	MSDOS & AZTEC
	movecursor(term.t_nrow, 0);		/* Seek to last line.	*/
	TTflush();
	TTkclose();
	system("command.com");
	TTkopen();
	sgarbf = TRUE;
	return(TRUE);
#endif
#if	MSDOS & LATTICE
	movecursor(term.t_nrow, 0);		/* Seek to last line.	*/
	TTflush();
	TTkclose();
	sys("\\command.com", "");		/* Run CLI.		*/
	TTkopen();
	sgarbf = TRUE;
	return(TRUE);
#endif
#if	V7 | USG | BSD
	movecursor(term.t_nrow, 0);		/* Seek to last line.	*/
	TTflush();
	TTclose();				/* stty to old settings */
	if ((cp = getenv("SHELL")) != NULL && *cp != '\0')
		system(cp);
	else
#if	BSD
		system("exec /bin/csh");
#else
		system("exec /bin/sh");
#endif
	sgarbf = TRUE;
	sleep(2);
	TTopen();
	return(TRUE);
#endif
}

#if	BSD

bktoshell()		/* suspend MicroEMACS and wait to wake up */
{
	int pid;

	vttidy();
	pid = getpid();
	kill(pid,SIGTSTP);
}

rtfrmshell()
{
	TTopen();
	curwp->w_flag = WFHARD;
	sgarbf = TRUE;
}
#endif

/*
 * Run a one-liner in a subjob. When the command returns, wait for a single
 * character to be typed, then mark the screen as garbage so a full repaint is
 * done. Bound to "C-X !".
 */
spawn(f, n)
{
	register int	s;
	char		line[NLINE];

#if	ST520
	int i,j,k;
	char *sptr,*tptr;
#endif

#if	AMIGA
	long newcli;
#endif

        /* don't allow this command if restricted */
	if (restflag)
		return(resterr());

#if	AMIGA
	if ((s=mlreply("!", line, NLINE)) != TRUE)
		return (s);
	newcli = Open("CON:1/1/639/199/MicroEmacs Subprocess", NEW);
	Execute(line,0,newcli);
	Close(newcli);
	tgetc();     /* Pause.		     */
	sgarbf = TRUE;
	return(TRUE);
#endif
#if	ST520
	if ((s=mlreply("!", line, NLINE)) != TRUE)
		return(s);
	movecursor(term.t_nrow - 1, 0);
	TTclose();
/*
 * break the line into the command and its args
 * be cute about it, if there is no '.' in the filename, try
 * to find .prg, .tos or .ttp in that order
 * in any case check to see that the file exists before we run 
 * amok
 */
	STenv = NULL;
	if((tptr = index(&line[0],' ')) == NULL) { /* no args */
		STcmd = (char *)malloc(strlen(line) + 1);
		strcpy(STcmd,line);
		STargs = NULL;
	}
	else {	/* seperate out the args from the command */
		/* resist the temptation to do ptr arithmetic */
		STcmd = (char *)malloc(strlen(line) + 1);
		for(i = 0,sptr = &line[0]; sptr != tptr; sptr++,i++)
			STcmd[i] = *sptr;
		STcmd[i] = '\0';
		for(; *tptr == ' ' || *tptr == '\t'; tptr++);
		if(*tptr == '\0')
			STargs = NULL;
		else {
			STargs = (char *)malloc(strlen(tptr) + 2);
/* first byte of STargs is the length of the string */
			STargs[0] = strlen(tptr);
			STargs[1] = NULL; /* fake it for strcat */
			strcat(STargs,tptr);
		}
	}
/*
 * before we issue the command look for the '.', if it's not there
 * try adding .prg, .tos and .ttp to see if they exist, if not
 * issue the command as is
 */
	if((tptr = index(STcmd,'.')) == NULL) {
		STwork = (char *)malloc(strlen(STcmd) + 4);
		strcpy(STwork,STcmd);
		strcat(STwork,".prg");
		tptr = index(STwork,'.');
		if(Fsfirst(1,STwork) != 0) { /* try .tos */
			strcpy(tptr,".tos");
			if(Fsfirst(1,STwork) != 0) { /* try .ttp */
				strcpy(tptr,".ttp");
				if(Fsfirst(1,STwork) != 0) /* never mind */
					*STwork = NULL;
				}
			}
	}
	if(*STwork != NULL)
		Pexec(LOAD_EXEC,STwork,STargs,STenv);		
	else
		Pexec(LOAD_EXEC,STcmd,STargs,STenv);
	TTopen();
	mlputs("\r\n\n[End]");			/* Pause.		*/
	TTgetc();			     /* Pause.		     */
	sgarbf = TRUE;
	return (TRUE);
#endif
#if	VMS
	if ((s=mlreply("!", line, NLINE)) != TRUE)
		return (s);
	TTputc('\n');		     /* Already have '\r'    */
	TTflush();
	s = sys(line);				/* Run the command.	*/
	mlputs("\r\n\n[End]");			/* Pause.		*/
	TTflush();
	tgetc();
	sgarbf = TRUE;
	return (s);
#endif
#if	CPM
	mlwrite("Not in CP/M-86");
	return (FALSE);
#endif
#if	MSDOS
	if ((s=mlreply("!", line, NLINE)) != TRUE)
		return(s);
	movecursor(term.t_nrow - 1, 0);
	TTkclose();
	system(line);
	TTkopen();
	/* if we are interactive, pause here */
	if (clexec == FALSE) {
		mlputs("\r\n\n[End]");
		tgetc();
	}
	sgarbf = TRUE;
	return (TRUE);
#endif
#if	V7 | USG | BSD
	if ((s=mlreply("!", line, NLINE)) != TRUE)
		return (s);
	TTputc('\n');		     /* Already have '\r'    */
	TTflush();
	TTclose();				/* stty to old modes	*/
	system(line);
	TTopen();
	mlputs("[End]");			/* Pause.		*/
	TTflush();
	while ((s = tgetc()) != '\r' && s != ' ')
		;
	sgarbf = TRUE;
	return (TRUE);
#endif
}

/*
 * Pipe a one line command into a window
 * Bound to ^X @
 */
pipe(f, n)
{
	register int	s;	/* return status from CLI */
	register WINDOW *wp;	/* pointer to new window */
	register BUFFER *bp;	/* pointer to buffer to zot */
	char	line[NLINE];	/* command line send to shell */
	static char bname[] = "command";

#if	AMIGA
	static char filnam[] = "ram:command";
	long newcli;
#else
	static char filnam[] = "command";
#endif

#if	MSDOS
	char *tmp;
	char *getenv();
	FILE *fp;
	FILE *fopen();
#endif

        /* don't allow this command if restricted */
	if (restflag)
		return(resterr());

#if	MSDOS
	if ((tmp = getenv("TMP")) == NULL)
		strcpy(filnam, "command");
	else
		strcpy(filnam, tmp);
#endif

#if	VMS
	mlwrite("Not availible under VMS");
	return(FALSE);
#endif
#if	CPM
	mlwrite("Not availible under CP/M-86");
	return(FALSE);
#endif

	/* get the command to pipe in */
	if ((s=mlreply("@", line, NLINE)) != TRUE)
		return(s);

	/* get rid of the command output buffer if it exists */
	if ((bp=bfind(bname, FALSE, 0)) != FALSE) {
		/* try to make sure we are off screen */
		wp = wheadp;
		while (wp != NULL) {
			if (wp->w_bufp == bp) {
				onlywind(FALSE, 1);
				break;
			}
			wp = wp->w_wndp;
		}
		if (zotbuf(bp) != TRUE)
			return(FALSE);
	}

#if	AMIGA
	newcli = Open("CON:1/1/639/199/MicroEmacs Subprocess", NEW);
	strcat(line, " >");
	strcat(line, filnam);
	Execute(line,0,newcli);
	s = TRUE;
	Close(newcli);
	sgarbf = TRUE;
#endif
#if	MSDOS
	strcat(line," >>");
	strcat(line,filnam);
	movecursor(term.t_nrow - 1, 0);
	TTkclose();
	system(line);
	TTkopen();
	sgarbf = TRUE;
	if ((fp = fopen(filnam, "r")) == NULL) {
		s = FALSE;
	} else {
		fclose(fp);
		s = TRUE;
	}
#endif
#if	V7 | USG | BSD
	TTputc('\n');		     /* Already have '\r'    */
	TTflush();
	TTclose();				/* stty to old modes	*/
	strcat(line,">");
	strcat(line,filnam);
	system(line);
	TTopen();
	TTflush();
	sgarbf = TRUE;
	s = TRUE;
#endif

	if (s != TRUE)
		return(s);

	/* split the current window to make room for the command output */
	if (splitwind(FALSE, 1) == FALSE)
			return(FALSE);

	/* and read the stuff in */
	if (getfile(filnam, FALSE) == FALSE)
		return(FALSE);

	/* make this window in VIEW mode, update all mode lines */
	curwp->w_bufp->b_mode |= MDVIEW;
	wp = wheadp;
	while (wp != NULL) {
		wp->w_flag |= WFMODE;
		wp = wp->w_wndp;
	}

	/* and get rid of the temporary file */
	unlink(filnam);
	return(TRUE);
}

/*
 * filter a buffer through an external DOS program
 * Bound to ^X #
 */
filter(f, n)

{
	register int	s;	/* return status from CLI */
	register BUFFER *bp;	/* pointer to buffer to zot */
	char line[NLINE];	/* command line send to shell */
	char tmpnam[NFILEN];	/* place to store real file name */
	static char bname1[] = "fltinp";

#if	AMIGA
	static char filnam1[] = "ram:fltinp";
	static char filnam2[] = "ram:fltout";
	long newcli;
#else
	static char filnam1[] = "fltinp";
	static char filnam2[] = "fltout";
#endif

        /* don't allow this command if restricted */
	if (restflag)
		return(resterr());

        if (curbp->b_mode&MDVIEW)       /* don't allow this command if	*/
		return(rdonly());	/* we are in read only mode	*/

#if	VMS
	mlwrite("Not availible under VMS");
	return(FALSE);
#endif
#if	CPM
	mlwrite("Not availible under CP/M-86");
	return(FALSE);
#endif

	/* get the filter name and its args */
	if ((s=mlreply("#", line, NLINE)) != TRUE)
		return(s);

	/* setup the proper file names */
	bp = curbp;
	strcpy(tmpnam, bp->b_fname);	/* save the original name */
	strcpy(bp->b_fname, bname1);	/* set it to our new one */

	/* write it out, checking for errors */
	if (writeout(filnam1) != TRUE) {
		mlwrite("[Cannot write filter file]");
		strcpy(bp->b_fname, tmpnam);
		return(FALSE);
	}

#if	AMIGA
	newcli = Open("CON:1/1/639/199/MicroEmacs Subprocess", NEW);
	strcat(line, " <ram:fltinp >ram:fltout");
	Execute(line,0,newcli);
	s = TRUE;
	Close(newcli);
	sgarbf = TRUE;
#endif
#if	MSDOS
	strcat(line," <fltinp >fltout");
	movecursor(term.t_nrow - 1, 0);
	TTkclose();
	system(line);
	TTkopen();
	sgarbf = TRUE;
	s = TRUE;
#endif
#if	V7 | USG | BSD
	TTputc('\n');		     /* Already have '\r'    */
	TTflush();
	TTclose();				/* stty to old modes	*/
	strcat(line," <fltinp >fltout");
	system(line);
	TTopen();
	TTflush();
	sgarbf = TRUE;
	s = TRUE;
#endif

	/* on failure, escape gracefully */
	if (s != TRUE || (readin(filnam2,FALSE) == FALSE)) {
		mlwrite("[Execution failed]");
		strcpy(bp->b_fname, tmpnam);
		unlink(filnam1);
		unlink(filnam2);
		return(s);
	}

	/* reset file name */
	strcpy(bp->b_fname, tmpnam);	/* restore name */
	bp->b_flag |= BFCHG;		/* flag it as changed */

	/* and get rid of the temporary file */
	unlink(filnam1);
	unlink(filnam2);
	return(TRUE);
}

#if	VMS
/*
 * Run a command. The "cmd" is a pointer to a command string, or NULL if you
 * want to run a copy of DCL in the subjob (this is how the standard routine
 * LIB$SPAWN works. You have to do wierd stuff with the terminal on the way in
 * and the way out, because DCL does not want the channel to be in raw mode.
 */
sys(cmd)
register char	*cmd;
{
	struct	dsc$descriptor	cdsc;
	struct	dsc$descriptor	*cdscp;
	long	status;
	long	substatus;
	long	iosb[2];

	status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
			  oldmode, sizeof(oldmode), 0, 0, 0, 0);
	if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
		return (FALSE);
	cdscp = NULL;				/* Assume DCL.		*/
	if (cmd != NULL) {			/* Build descriptor.	*/
		cdsc.dsc$a_pointer = cmd;
		cdsc.dsc$w_length  = strlen(cmd);
		cdsc.dsc$b_dtype   = DSC$K_DTYPE_T;
		cdsc.dsc$b_class   = DSC$K_CLASS_S;
		cdscp = &cdsc;
	}
	status = LIB$SPAWN(cdscp, 0, 0, 0, 0, 0, &substatus, 0, 0, 0);
	if (status != SS$_NORMAL)
		substatus = status;
	status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
			  newmode, sizeof(newmode), 0, 0, 0, 0);
	if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
		return (FALSE);
	if ((substatus&STS$M_SUCCESS) == 0)	/* Command failed.	*/
		return (FALSE);
	return (TRUE);
}
#endif

#if	~AZTEC & MSDOS

/*
 * This routine, once again by Bob McNamara, is a C translation of the "system"
 * routine in the MWC-86 run time library. It differs from the "system" routine
 * in that it does not unconditionally append the string ".exe" to the end of
 * the command name. We needed to do this because we want to be able to spawn
 * off "command.com". We really do not understand what it does, but if you don't
 * do it exactly "malloc" starts doing very very strange things.
 */
sys(cmd, tail)
char	*cmd;
char	*tail;
{
#if MWC_86
	register unsigned n;
	extern	 char	  *__end;

	n = __end + 15;
	n >>= 4;
	n = ((n + dsreg() + 16) & 0xFFF0) + 16;
	return(execall(cmd, tail, n));
#endif

#if LATTICE
	return(forklp(cmd, tail, (char *)NULL));
#endif

#if	MSC
	return(spawnlp(P_WAIT, cmd, tail, NULL));
#endif
}
#endif

#if	MSDOS & LATTICE
/*      System: a modified version of lattice's system() function
		that detects the proper switchar and uses it
		written by Dana Hogget				*/

system(cmd)

char *cmd;	/*  Incoming command line to execute  */

{
	char *getenv();
	static char *swchar = "/C";	/*  Execution switch  */
	union REGS inregs;	/*  parameters for dos call  */
	union REGS outregs;	/*  Return results from dos call  */
	char *shell;		/*  Name of system command processor  */
	char *p;		/*  Temporary pointer  */
	int ferr;		/*  Error condition if any  */

	/*  get name of system shell  */
	if ((shell = getenv("COMSPEC")) == NULL) {
		return (-1);		/*  No shell located  */
	}

	p = cmd;
	while (isspace(*p)) {		/*  find out if null command */
		p++;
	}

	/**  If the command line is not empty, bring up the shell  **/
	/**  and execute the command.  Otherwise, bring up the	   **/
	/**  shell in interactive mode.   **/

	if (p && *p) {
		/**  detect current switch character and us it	**/
		inregs.h.ah = 0x37;	/*  get setting data  */
		inregs.h.al = 0x00;	/*  get switch character  */
		intdos(&inregs, &outregs);
		*swchar = outregs.h.dl;
		ferr = forkl(shell, "command", swchar, cmd, (char *)NULL);
	} else {
		ferr = forkl(shell, "command", (char *)NULL);
	}

	return (ferr ? ferr : wait());
}
#endif

@//E*O*F spawn.c//
chmod u=rw,g=r,o=r spawn.c
 
echo x - st520.c
sed 's/^@//' > "st520.c" <<'@//E*O*F st520.c//'

/*

The routines in this file provide support for the Atari ST520 or 1040
using VT52 emulation.  The I/O services are provided by routines in
"termio.c".  It compiles into nothing if not a ST520 style device.  The
bell on the ST520 is terrible, so the "beep" routine is conditionalized
on defining BEL. 

*/

#define termdef 1                       /* don't define "term" external */

#include	<stdio.h>
#include	"estruc.h"
#include	"edef.h"

#if MEGAMAX
overlay "st520"
#endif

#if	ATARI & ST520 & MEGAMAX
#include	<osbind.h>
#include	<ctype.h>

#define LINEA_INIT 0xA000
#define V_CEL_WR   -0x28
#define V_CEL_MY   -0x2a
#define V_CEL_HT   -0x2e
#define V_FNT_AD   -0x16
#define V_OFF_AD   -0x0a
#define V_DISAB    -346

#define NROW	24			/* Screen size. 		*/
#define NCOL	80			/* Edit if you want to. 	*/
#define MARGIN	8			/* size of minimim margin and	*/
#define SCRSIZ	64			/* scroll size for extended lines */
#define NPAUSE	25			/* # times thru update to pause */
#define BIAS	0x20			/* Origin 0 coordinate bias.	*/
#define ESC	0x1B			/* ESC character.		*/
#define BEL	0x07			/* ascii bell character 	*/

extern	int	ttopen();		/* Forward references.		*/
extern	int	ttgetc();
extern	int	ttputc();
extern	int	ttflush();
extern	int	ttclose();
extern	int	st520move();
extern	int	st520eeol();
extern	int	st520eeop();
extern	int	st520beep();
extern	int	st520open();
extern	int	st520close();
extern	int	st520rev();
extern	int	st520cres();
extern	int st520kopen();
extern	int st520kclose();

#if	COLOR
extern	int	st520fcol();
extern	int	st520bcol();

int		cfcolor = -1;		/* current fg (character) color */
int		cbcolor = -1;		/* current bg color */
int		oldpal[8];		/* pallette when emacs was invoked */
int		newpal[8] = {		/* default emacs pallette */
	0x000, 0x700, 0x070, 0x770, 0x007, 0x707, 0x077, 0x777};
#endif

int STncolors = 0;		/* number of colors  */
int STrez;			/* physical screen resolution */	

/*
 * Dispatch table. All the
 * hard fields just point into the
 * terminal I/O code.
 */
TERM	term	= {
	NROW-1,
	NCOL,
	MARGIN,
	MARGIN,
	SCRSIZ,
	NPAUSE,
	&st520open,
	&st520close,
	&st520kopen,
	&st520kclose,
	&ttgetc,
	&ttputc,
	&ttflush,
	&st520move,
	&st520eeol,
	&st520eeop,
	&st520beep,
	&st520rev,
	&st520cres
#if	COLOR
	, &st520fcol,
	&st520bcol
#endif
};
	struct KBDvecs {
		int (*midivec) ();
		int (*vkbderr) ();
		int (*vmiderr) ();
		int (*statvec) ();
		int (*mousevec) ();
		int (*clockvec) ();
		int (*joyvec) ();
		int (*midisys) ();
		int (*ikbdsys) ();
	};
	struct Param {
		char topmode;
		char buttons;
		char xparam;
		char yparam;
		int xmax,ymax;
		int xinitial,yinitial;
	};
	struct KBDvecs *kbdvecs;
	struct Param *paramp;
	char kbdcmds[25];

st520move(row, col)
{
	ttputc(ESC);
	ttputc('Y');
	ttputc(row+BIAS);
	ttputc(col+BIAS);
}

st520eeol()
{
	ttputc(ESC);
	ttputc('K');
}

st520eeop()
{

#if	COLOR
		st520fcol(gfcolor);
		st520bcol(gbcolor);
#endif
	ttputc(ESC);
	ttputc('J');
}

st520rev(status)	/* set the reverse video state */

int status;	/* TRUE = reverse video, FALSE = normal video */

{

	if(status) {
		ttputc(ESC);
		ttputc('p');
	}
	else {
		ttputc(ESC);
		ttputc('q');
	}
}

#if	COLOR
st520fcol(color)
int color;	
{
		if(color == cfcolor || !STncolors)
			return;
		else {

			ttputc(ESC);
			ttputc('b');
			ttputc(color & 0x0f);
			cfcolor = color;
		}
}

st520bcol(color)
int color;
{
		if(color == cbcolor || !STncolors)
			return;
		else {
			ttputc(ESC);
			ttputc('c');
			ttputc(color & 0x0f);
			cbcolor = color;
		}

}
#endif

st520beep()
{
#ifdef	BEL
	ttputc(BEL);
	ttflush();
#endif
}

st520open()
{
	int i,j,k;
	long phys, log; /* screen bases */
	
/* IMPORTANT: it is ABSOLUTELY necessary that the default resolution be the
 *	largest possible so that display will allocate (malloc) the maximum
 *	size for the VIDEO arrray
 */
	STrez = Getrez();
	switch(STrez) {
		case 0: /* low res 25x40 16 colors */
			strcpy(sres, "LOW");
			phys = Physbase();
			log  = Logbase();
			Setscreen(log, phys, 1);
			STrez = 1;
			/* fall thru to med res */

		case 1: /* med res 25x80 4 colors */
			if (STrez == 1) strcpy(sres, "MEDIUM");
			term.t_nrow = 25 - 1;
			term.t_ncol  = 80;
			grez = 1;
#if	COLOR
			STncolors = 4;
			for(i=0;i<8;i++) {
				oldpal[i] = Setcolor(i,newpal[i]);
			}
#endif
			break;
		case 2: /* high res 25x80 no colors */
			strcpy(sres, "HIGH");
			term.t_nrow  = 40 - 1;
			term.t_ncol  = 80;
			grez = 2;
			make_8x10(); /* create a smaller font */
			set_40();    /* and go to 40 line mode */
#if	COLOR
			STncolors = 0;
#endif
			break;
	}

	revexist = TRUE;
	eolexist = TRUE;
	paramp = (struct Param *)malloc(sizeof(struct Param));
	kbdvecs = (struct KBDvecs *)Kbdvbase();
	paramp -> topmode = 0;
	paramp -> buttons = 4;
	paramp -> xparam = 8;
	paramp -> yparam = 10;
	paramp -> xmax = 79;
	paramp -> ymax = 23;
	paramp -> xinitial = 0;
	paramp -> yinitial = 0;
	Initmous(1,paramp,kbdvecs -> mousevec);

	i = 0;
	kbdcmds[i++] = 0x0a;	/*set mouse keycode mode */
	kbdcmds[i++] = 0x08;
	kbdcmds[i++] = 0x0a;
	Ikbdws(i-1,&kbdcmds[0]);
	Cursconf(1,0);
	Cursconf(3,0);
	Cconout(27);Cconout('E');
	ttopen();
}

st520close()

{
	int i,j,k;

	i = 0;
	kbdcmds[i++] = 0x80;	/*reset mouse keycode mode */
	kbdcmds[i++] = 0x01;
	Ikbdws(i-1,&kbdcmds[0]);
	if(grez == 2 && STrez == 2) /* b/w monitor in 40 row mode */
		restore();

#if		COLOR
	for(i=0;i<STncolors;i++)
		Setcolor(i,oldpal[i]);
#endif
	Cconout(27);Cconout('E');
	paramp -> buttons = 0;
	Initmous(2,paramp,kbdvecs -> mousevec);
	i = 0;
	kbdcmds[i++] = 0x80;	/*reset the keyboard*/
	kbdcmds[i++] = 0x01;
	Ikbdws(i-1,&kbdcmds[0]);
	Cursconf(1,0);
	ttclose();
}
st520kopen()
{

}
st520kclose()
{

}

st520cres(res)		/* change screen resolution */

char *res;		/* resolution to change to */

{
	register int nurez;	/* number of res to change to */
	int ierr, i, j ,k;
	long phys, log; /* screen bases */
	char dum[80]; /* for debugging only */

	/* determine the needed resolution */
	if (strcmp(res, "LOW") == 0)
		nurez = 1;
	else if (strcmp(res, "MEDIUM") == 0)
		nurez = 2;
	else if (strcmp(res, "HIGH") == 0)
		nurez = 3;
	else
		return(FALSE);

	if(grez == nurez)
		return(TRUE);
		
	if(STrez == 2) { /* b/w monitor-only allow hi | med rez */
		switch(nurez) {
			case 2: /* high res */
				term.t_nrow  = 40 - 1;
				term.t_ncol  = 80;
				make_8x10(); /* create a smaller font */
				set_40();    /* and go to 40 line mode */
				grez = 2;
				sgarbf = TRUE;
				onlywind(1,1);
				strcpy(sres, "HIGH");
				break;
			case 1: /* med res */
				term.t_nrow  = 25 - 1;
				term.t_ncol  = 80;
				restore();
				grez = 1;
				sgarbf = TRUE;
				onlywind(1,1);
				strcpy(sres, "MEDIUM");
				break;
			default:
				mlwrite("Invalid resolution");
				return(FALSE);
				break;
		}
	}
	else { /* color monitor-only allow low | medium resolution */
		phys = Physbase();
		log  = Logbase();
		switch(nurez) {
			case 1:
				term.t_nrow  = 25 - 1;
				term.t_ncol  = 80;
				Setscreen(log, phys, 1);
				STncolors = 4;
				grez = 1;
				sgarbf = TRUE;
				onlywind(1,1);
				strcpy(sres, "LOW");
				break;
			case 0:
				term.t_nrow  = 25 - 1;
				term.t_ncol  = 40;
				Setscreen(log, phys, 0);
				STncolors = 8;
				grez = 0;
				sgarbf = TRUE;
				onlywind(1,1);
				strcpy(sres, "MEDIUM");
				break;
			default:
				mlwrite("%Invalid resolution");
				return(FALSE);
				break;
		}
	}
	return(TRUE);
}			

STcurblink(onoff)
int onoff;
{
	if(onoff)
		Cursconf(2,0);
	else
		Cursconf(3,0);
}


char parm_save[28];
long fnt_8x10[640];

make_8x10()
{
	int i,j,k;
	long savea23[2];
	
	for(i=0;i<640;i++)
		fnt_8x10[i] = 0;
		
	asm {
	movem.l A2-A3,savea23(A6)
	
	dc.w	LINEA_INIT		;A1 -> array of font headers

	lea	parm_save(A4),A2	;A2 -> parameters savearea
	move.l	V_OFF_AD(A0),(A2)+
	move.l	V_FNT_AD(A0),(A2)+
	move.w	V_CEL_HT(A0),(A2)+
	move.w	V_CEL_MY(A0),(A2)+
	move.w	V_CEL_WR(A0),(A2)+


	move.l	04(A1),A1		; A1 -> 8x8 font header
	move.l	76(A1),A2		; A2 -> 8x8 font data
	lea	fnt_8x10+0x100(A4),A3	; A3 -> 2nd line of font buffer
	move.w	#0x200-1,D0		; D0 <- longword counter for font xfer

fnt_loop:

	move.l	(A2)+,(A3)+
	dbf	D0,fnt_loop
		
	movem.l savea23(A6),A2-A3
	}
	
}

set_40()
{
	long	savea23[2];
	
	asm {
	
c
c  use the 8x10 character set: 40 line mode
c

	movem.l A2-A3,savea23(A6)
	
	dc.w	LINEA_INIT

	move.l	04(A1),A1		; A1 -> 8x8 font header
	move.l	72(A1),V_OFF_AD(A0)	; v_off_ad <- 8x8  offset table addr
	lea	fnt_8x10(A4),A2
	move.l	A2,V_FNT_AD(A0) 	; v_fnt_ad <- 8x10 font data addr

	move.w	#10,V_CEL_HT(A0)	; v_cel_ht <- 10   8x10 cell height
	move.w	#39,V_CEL_MY(A0)	; v_cel_my <- 39   maximum cell "Y"
	move.w	#800,V_CEL_WR(A0)	; v_cel_wr <- 800  offset to cell Y+1

	movem.l savea23,A2-A3
	}
}

set_20()
{
	long	savea23[2];

	asm {
		
c
c  use the 8x10 character set: 20 line mode
c

	movem.l A2-A3,savea23(A6)
	
	dc.w	LINEA_INIT		; A0 -> line A variables

	move.l	04(A1),A1		; A1 -> 8x8 font header
	move.l	72(A1),V_OFF_AD(A0)	; v_off_ad <- 8x8  offset table addr
	lea	fnt_8x10(A4),A2
	move.l	A2,V_FNT_AD(A0) 	; v_fnt_ad <- 8x10 font data addr

	move.w	#10,V_CEL_HT(A0)	; v_cel_ht <- 10   8x10 cell height
	move.w	#19,V_CEL_MY(A0)	; v_cel_my <- 19   maximum cell "Y"
	move.w	#1600,V_CEL_WR(A0)	; v_cel_wr <- 800  offset to cell Y+1
	
	movem.l savea23,A2-A3
	}
}


restore()
{
	long savea23[2];
	
	asm {
	
c  return what was saved in parameter save zone 

	movem.l A2-A3,savea23(A6)

	dc.w	LINEA_INIT		; a0 -> line A variables

	lea	parm_save(A4),A2	; a2 -> parameter save area
	move.l	(A2)+,V_OFF_AD(A0)
	move.l	(A2)+,V_FNT_AD(A0)
	move.w	(A2)+,V_CEL_HT(A0)
	move.w	(A2)+,V_CEL_MY(A0)
	move.w	(A2)+,V_CEL_WR(A0)
	
	movem.l savea23(A6),A2-A3
	}	   
}
GetCurStat(onoff)
int	onoff;
{
	long savea23[2];

	asm {
	movem.l A2-A3,savea23(A6)

	dc.w	LINEA_INIT		; a0 -> line A variables
	move.w	V_DISAB(A0),onoff(A6)	; 0 = cursor visible
	moveq	#0,D0
	move.w	V_DISAB(A0),D0	
	movem.l savea23(A6),A2-A3
	}	   
}
#else
sthello()
{
}
#endif

@//E*O*F st520.c//
chmod u=rw,g=r,o=r st520.c
 
exit 0
