[comp.sources.misc] v02i050: Unify TEXT fields from ACCELL Part 1/5

ustel@well.UUCP (Mark Hargrove) (02/11/88)

Comp.sources.misc: Volume 2, Issue 50

Submitted-By: "Mark Hargrove" <ustel@well.UUCP>

Archive-Name: accell-text/Part1


Comp.sources.misc: Volume 2, Issue 50
Submitted-By: "Mark Hargrove" <ustel@well.UUCP>
Archive-Name: accell-text/Part1

[Sendlist gave me a size warning; this may get truncated.  ++bsa]

	The following collection of stuff allows you to access
	and use UNIFY Text (and by extension, Binary)  fields
	from within the Accell environment.  Also included is
	a deliberately crippled version of micro-gnu emacs that
	has been mangled into presenting a very Accell-like
	"look and feel" to the user.  On an NCR Tower, the resulting
	executable is only about 55K.  For casual users, this
	has turned out to be a better editor than say, vi or
	ed :-)  As with UNIFY, your choice of editors is 
	available via the EDIT environment variable.

	The C-hooks which write the text out to the database 
	HAVE been modified to work around the recently discovered
	(and rather gruesome) UNIFY bug which frequently led to
	corruption of file.dbv.  Remember that using ENTER to 
	edit a text field WILL STILL CAUSE CORRUPTION OF FILE.DBV.

	[If you don't know about this bug and you are using text
	 fields from either C or via ENTER -- call Unify TS TODAY
	 and get a description of the problem ]

	Bug reports would be appreciated.
	
		-Mark Hargrove

#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./region.c`
then
echo "writing ./region.c"
cat > ./region.c << '\Rogue\Monster\'
/*
 *		Region based commands.
 * 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	"def.h"

/*
 * Kill the region. Ask "getregion"
 * to figure out the bounds of the region.
 * Move "." to the start, and kill the characters.
 */
/*ARGSUSED*/
killregion(f, n, k)
{
	register int	s;
	REGION		region;

	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, KFORW));
}


/*
 * This routine figures out the bound of the region
 * in the current window, and stores the results into the fields
 * of the REGION structure. Dot and mark are usually close together,
 * but I don't know the order, so I scan outward from dot, in both
 * directions, looking for mark. The size is kept in a long. At the
 * end, after the size is figured out, it is assigned to the size
 * field of the region structure. If this assignment loses any bits,
 * then we print an error. This is "type independent" overflow
 * checking. All of the callers of this routine should be ready to
 * get an ABORT status, because I might add a "if regions is big,
 * ask before clobberring" flag.
 */
getregion(rp) register REGION *rp;
{
	register LINE	*flp;
	register LINE	*blp;
	register long	fsize;			/* Long now.		*/
	register long	bsize;

	if (curwp->w_markp == NULL)
	{
		ewprintf("No mark set in this window");
		return (FALSE);
	}
	if (curwp->w_dotp == curwp->w_markp)
	{	/* "r_size" always ok.	*/
		rp->r_linep = curwp->w_dotp;
		if (curwp->w_doto < curwp->w_marko)
		{
			rp->r_offset = curwp->w_doto;
			rp->r_size = (RSIZE) (curwp->w_marko-curwp->w_doto);
		}
		else
		{
			rp->r_offset = curwp->w_marko;
			rp->r_size = (RSIZE) (curwp->w_doto-curwp->w_marko);
		}
		return (TRUE);
	}
	blp = curwp->w_dotp;			/* Get region size.	*/
	flp = curwp->w_dotp;
	bsize = curwp->w_doto;
	fsize = 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;
				return (setsize(rp,
					(RSIZE) (fsize+curwp->w_marko)));
			}
			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;
				return (setsize(rp,
					(RSIZE) (bsize-curwp->w_marko)));
			}
		}
	}
	ewprintf("Bug: lost mark");		/* Gak!			*/
	return (FALSE);
}

/*
 * Set size, and check for overflow.
 */
setsize(rp, size)
   register REGION *rp;
   register RSIZE size;
{

	rp->r_size = size;
	if (rp->r_size != size)
	{
		ewprintf("Region is too large");
		return (FALSE);
	}
	return (TRUE);
}

#ifdef	PREFIXREGION
/*
 * Implements one of my favorite keyboard macros; put a string at the
 * beginning of a number of lines in a buffer.  The quote string is
 * settable by using set-prefix-string.  Great for quoting mail, which
 * is the real reason I wrote it, but also has uses for creating bar
 * comments (like the one you're reading) in C code.
 */

#define PREFIXLENGTH 40
static char prefix_string[PREFIXLENGTH] = { '>', '\0' };

/*
 * Prefix the region with whatever is in prefix_string.
 * Leaves dot at the beginning of the line after the end
 * of the region.  If an argument is given, prompts for the
 * line prefix string.
 */

/*ARGSUSED*/
prefixregion(f, n, k)
{
	register int	s;
	register LINE	*first, *last;
	register int	nline;
	REGION		region;
	char		*prefix = prefix_string;

	if ((f == TRUE) && ((s = setprefix(FALSE, 1, KRANDOM)) != TRUE))
		return (s);

	/* get # of lines to affect */
	if ((s = getregion(&region)) != TRUE)
		return (s);
	first = region.r_linep;
	last = (first == curwp->w_dotp) ? curwp->w_markp : curwp->w_dotp;
	for (nline = 1; first != last; nline++)
		first = lforw(first);

	/*move to beginning of region */
	curwp->w_dotp = region.r_linep;
	curwp->w_doto = region.r_offset;

	/* for each line, go to beginning and insert the prefix string */
	while (nline--)
	{
		gotobol();
		for (prefix = prefix_string; *prefix; prefix++)
			(VOID) linsert((RSIZE) 1, *prefix);
		forwline(FALSE, 1, KRANDOM);
	}
	gotobol();
	return (TRUE);
}

/*
 * Set prefix string.
 */

/*ARGSUSED*/
setprefix(f, n, k)
{
	char		buf[PREFIXLENGTH];
	register int	s;

	if (prefix_string[0] == '\0')
		s = ereply("Prefix string: ",buf,sizeof buf);
	else
		s = ereply("Prefix string (default %s): ",
				buf,sizeof buf,prefix_string);
	if (s == TRUE)
		(VOID) strcpy(prefix_string, buf);
	if ((s == FALSE) && (prefix_string[0] != '\0'))	/* CR -- use old one */
		s = TRUE;
	return (s);
}
#endif
\Rogue\Monster\
else
  echo "will not over write ./region.c"
fi
if `test ! -s ./search.c`
then
echo "writing ./search.c"
cat > ./search.c << '\Rogue\Monster\'
/*
 * 		Search commands.
 * The functions in this file implement the
 * search commands (both plain and incremental searches
 * are supported) and the query-replace command.
 *
 * The plain old search code is part of the original
 * MicroEMACS "distribution". The incremental search code,
 * and the query-replace code, is by Rich Ellison.
 */
#include	"def.h"

#define SRCH_BEGIN	(0)			/* Search sub-codes.	*/
#define	SRCH_FORW	(-1)
#define SRCH_BACK	(-2)
#define SRCH_NOPR	(-3)
#define SRCH_ACCM	(-4)
#define	SRCH_MARK	(-5)

typedef struct  {
	int	s_code;
	LINE	*s_dotp;
	int	s_doto;
}	SRCHCOM;

static	SRCHCOM	cmds[NSRCH];
static	int	cip;

int	srch_lastdir = SRCH_NOPR;		/* Last search flags.	*/

VOID	is_cpush();
VOID	is_lpush();
VOID	is_pop();
VOID	is_prompt();
VOID	is_dspl();

/*
 * Search forward.
 * Get a search string from the user, and search for it,
 * starting at ".". If found, "." gets moved to just after the
 * matched characters, and display does all the hard stuff.
 * If not found, it just prints a message.
 */
/*ARGSUSED*/
forwsearch(f, n, k)
{
	register int	s;

	if ((s=readpattern("Search")) != TRUE)
		return (s);
	if (forwsrch() == FALSE)
	{
		ewprintf("Search failed: \"%s\"", pat);
		return (FALSE);
	}
	srch_lastdir = SRCH_FORW;
	return (TRUE);
}

/*
 * 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].
 */
/*ARGSUSED*/
backsearch(f, n, k)
{
	register int	s;

	if ((s=readpattern("Search backward")) != TRUE)
		return (s);
	if (backsrch() == FALSE)
	{
		ewprintf("Search failed: \"%s\"", pat);
		return (FALSE);
	}
	srch_lastdir = SRCH_BACK;
	return (TRUE);
}

/* 
 * Search again, using the same search string
 * and direction as the last search command. The direction
 * has been saved in "srch_lastdir", so you know which way
 * to go.
 */
/*ARGSUSED*/
searchagain(f, n, k)
{
	if (srch_lastdir == SRCH_FORW)
	{
		if (forwsrch() == FALSE)
		{
			ewprintf("Search failed: \"%s\"", pat);
			return (FALSE);
		}
		return (TRUE);
	}
	if (srch_lastdir == SRCH_BACK)
	{
		if (backsrch() == FALSE)
		{
			ewprintf("Search failed: \"%s\"", pat);
			return (FALSE);
		}
		return (TRUE);
	}
	ewprintf("No last search");
	return (FALSE);
}


/*
 * This routine does the real work of a
 * forward search. The pattern is sitting in the external
 * variable "pat". If found, dot is updated, the window system
 * is notified of the change, and TRUE is returned. If the
 * string isn't found, FALSE is returned.
 */
forwsrch()
{
	register LINE	*clp;
	register int	cbo;
	register LINE	*tlp;
	register int	tbo;
	register char	*pp;
	register int	c;

	clp = curwp->w_dotp;
	cbo = curwp->w_doto;
	while (clp != curbp->b_linep)
	{
		if (cbo == llength(clp))
		{
			clp = lforw(clp);
			cbo = 0;
			c = SEOL;
		} else
			c = lgetc(clp, cbo++);
		if (eq(c, pat[0]) != FALSE)
		{
			tlp = clp;
			tbo = cbo;
			pp  = &pat[1];
			while (*pp != 0)
			{
				if (tlp == curbp->b_linep)
					goto fail;
				if (tbo == llength(tlp))
				{
					tlp = lforw(tlp);
					if (tlp == curbp->b_linep)
						goto fail;
					tbo = 0;
					c = SEOL;
				} else
					c = lgetc(tlp, tbo++);
				if (eq(c, *pp++) == FALSE)
					goto fail;
			}
			curwp->w_dotp  = tlp;
			curwp->w_doto  = tbo;
			curwp->w_flag |= WFMOVE;
			return (TRUE);
		}
	fail:	;
	}
	return (FALSE);
}

/*
 * This routine does the real work of a
 * backward search. The pattern is sitting in the external
 * variable "pat". If found, dot is updated, the window system
 * is notified of the change, and TRUE is returned. If the
 * string isn't found, FALSE is returned.
 */
backsrch()
{
	register LINE	*clp;
	register int	cbo;
	register LINE	*tlp;
	register int	tbo;
	register int	c;
	register char	*epp;
	char		*pp;

	for (epp = &pat[0]; epp[1] != 0; ++epp)
		;
	clp = curwp->w_dotp;
	cbo = curwp->w_doto;
	for (;;)
	{
		if (cbo == 0)
		{
			clp = lback(clp);
			if (clp == curbp->b_linep)
				return (FALSE);
			cbo = llength(clp)+1;
		}
		if (--cbo == llength(clp))
			c = SEOL;
		else
			c = lgetc(clp,cbo);
		if (eq(c, *epp) != FALSE)
		{
			tlp = clp;
			tbo = cbo;
			pp  = epp;
			while (pp != &pat[0])
			{
				if (tbo == 0)
				{
					tlp = lback(tlp);
					if (tlp == curbp->b_linep)
						goto fail;
					tbo = llength(tlp)+1;
				}
				if (--tbo == llength(tlp))
					c = SEOL;
				else
					c = lgetc(tlp,tbo);
				if (eq(c, *--pp) == FALSE)
					goto fail;
			}
			curwp->w_dotp  = tlp;
			curwp->w_doto  = tbo;
			curwp->w_flag |= WFMOVE;
			return (TRUE);
		}
	fail:	;
	}
	/* NOTREACHED*/
}

/*
 * Compare two characters.
 * The "bc" comes from the buffer.
 * It has its case folded out. The
 * "pc" is from the pattern.
 */
eq(bc, pc)
{
	register int	ibc;
	register int	ipc;

	ibc = bc & 0xFF;
	ipc = pc & 0xFF;
	if (ISLOWER(ibc) != FALSE)
		ibc = TOUPPER(ibc);
	if (ISLOWER(ipc) != FALSE)
		ipc = TOUPPER(ipc);
	if (ibc == ipc)
		return (TRUE);
	return (FALSE);
}

/*
 * Read a pattern.
 * Stash it in the external variable "pat". The "pat" 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.
 */
readpattern(prompt) char *prompt;
{
	register int	s;
	char		tpat[NPAT];

	if (tpat[0] == '\0') s = ereply("%s: ", tpat, NPAT, prompt);
	else s = ereply("%s: (default %s) ", tpat, NPAT, prompt, pat);

	if (s == TRUE)				/* Specified		*/
		(VOID) strcpy(pat, tpat);
	else if (s==FALSE && pat[0]!=0)		/* CR, but old one	*/
		s = TRUE;
	return (s);
}
\Rogue\Monster\
else
  echo "will not over write ./search.c"
fi
if `test ! -s ./spawn.c`
then
echo "writing ./spawn.c"
cat > ./spawn.c << '\Rogue\Monster\'
/*
 * Name:	MicroEMACS
 *		Spawn CLI for System V.
 * Version:	0
 * Last edit:	17-Apr-86
 * By:		gonzo!daveb
 *		{sun, amdahl, mtxinu}!rtech!daveb
 *
 * Spawn for System V.
 */
#include	"def.h"

#include	<signal.h>
#include	<stdio.h>

extern	char	*getenv();

/*
 * Execute a single command using the shell. If no argument,
 * then print the file in the top (only) buffer, after making
 * sure that it has been flushed to disk.
 */
/*ARGSUSED*/
spawncmd( f, n, k)
   int f, n;
   char **k;
{
   char cmdbuf[80];
   extern char *getenv();
   register int   pid;
   register int   wpid;
   int   (*oqsig)();
   int   (*oisig)();
   int      status;
   int      errp = FALSE;

   if (f == FALSE)      /* no command provided */
   {
      char *printcmd;
      char *argv[32];
      char argbuf[128];
      char *ptr;
      int argc;

      (void)memset(argbuf, 0, 128);
      if ((printcmd = getenv("SPOOLER")) == NULL)
         printcmd = "lp -s";
      (void)strcpy( argbuf, printcmd);
#ifdef DEBUG
	fprintf(stderr, "spooler='%s'\n", argbuf);
#endif
      for (argc=0, ptr=argbuf; *ptr; )
      {
         while (*ptr && (*ptr == ' ' || *ptr == '\t'))
	   {
	     *ptr++ = '\0';
	   }
         argv[argc++] = ptr;
         while (*ptr && *ptr != ' ' && *ptr != '\t')
            ++ptr;
      }
      if (argv[argc-1][0] == '\0')
         argv[argc-1] = NULL;
      argv[argc] = NULL;
#ifdef DEBUG
	{
	int i;
		fprintf(stderr, "argc=%d,", argc);
		fprintf(stderr, " argv='%s'", argv[0]);
		for (i=1; i<=argc; ++i)
		   fprintf(stderr, ",'%s'", argv[i]);
		fprintf(stderr, "\n");
	}
#endif
      (void)strcpy( cmdbuf, wheadp->w_bufp->b_fname);

      ewprintf("Please Wait...");
      oqsig = signal(SIGQUIT, SIG_IGN);
      oisig = signal(SIGINT,  SIG_IGN);
      if ((pid=fork()) == 0)
      {
         freopen( cmdbuf, "r", stdin);
         execvp( argv[0], argv);
         _exit(1);         /* Should do better!   */
      }
      else if (pid > 0)
      {
         while ((wpid=wait(&status))>=0 && wpid!=pid)
            ;
      }
      else
         errp = TRUE;

      signal(SIGQUIT, oqsig);
      signal(SIGINT,  oisig);
      if(errp)
         ewprintf("Print failed (can't create process).");
      else if (status)
         ewprintf("spooler returned error status=%d", status);
      else
         ewprintf("Text Queued for print");
   }
   else
   {
      /*
       * Don't do nuthin currently
       */
   }
   return TRUE;
}

#ifdef MENU_INSERT
/*
 * Menu Insert -- spawn a shell with the menu shell script
 */
spawninsert( f, n, k)
{
   extern char   *strrchr(), *strcpy(), *strcat(), *tmpnam();
   register int   pid;
   register int   wpid;
   register int   (*oqsig)();
   register int   (*oisig)();
   int      status;
   int      errp = FALSE;
   char      menup[80], *menuname = NULL;
   char      tempfile[L_tmpnam];

   (void)strcpy( menup, getenv("DBBIN"));
   if (menup[strlen(menup)-1] != '/')
      (void)strcat( menup, "/");
   if ((menuname = getenv("EMENU")) == NULL)
   {
      menuname = "mgx-menu.sh";
   }
   (void)strcat(menup, menuname);
   menuname = strrchr( menup, '/' ); 
   menuname = menuname ? menuname++ : menup;

   strcpy (tempfile, tmpnam((char *)0));
   ttcolor(CTEXT);
   ttnowindow();
   ttmove(nrow-1, 0);
   if (epresf != FALSE)
   {
      tteeol();
      epresf = FALSE;
   }
   ttclose();
   sgarbf = TRUE;            /* Force repaint.   */
   oqsig = signal(SIGQUIT, SIG_IGN);
   oisig = signal(SIGINT,  SIG_IGN);
   if ((pid=fork()) == 0)
   {
      execlp(menup, menuname, tempfile, NULL);
      _exit(1);         /* Should do better!   */
   }
   else if (pid > 0)
   {
      while ((wpid=wait(&status))>=0 && wpid!=pid)
         ;
   }
   else
      errp = TRUE;

   signal(SIGINT,  oisig);
   ttopen();
   if(errp)
      ewprintf("Failed to create process");
   else
   {
      gotobol( FALSE, 0, 0);
      insertfile( tempfile, (char *)0);
   }
   unlink( tempfile);
   return ( errp | status );
}
#endif
\Rogue\Monster\
else
  echo "will not over write ./spawn.c"
fi
if `test ! -s ./symbol.c`
then
echo "writing ./symbol.c"
cat > ./symbol.c << '\Rogue\Monster\'
/*
 * Symbol tables, and keymap setup.
 * The terminal specific parts of building the
 * keymap has been moved to a better place.
 */
#include	"def.h"

/*
 * Heavily modified routine for the TINY version of MicroGnuEmacs.
 */

/*
 * Defined here so to collect the #ifdef MEYN config stuff in one file
 * If you set either MINDENT or MFILL, then you need to change the bindings
 * in this file to match: KCTRL|'M' -> newline-and-indent and KCTRL|'J' ->
 * insert-newline for MINDENT, and ' ' -> insert-with-wrap for MFILL.
 * MEYN is used for compile-time customization of the system for micros.
 */

int	mode = MFILL | MOVRSTK | MFLOW;

/*
 * Defined by "main.c".
 */
extern	int	ctrlg();		/* Abort out of things		*/
extern	int	quit();			/* Quit				*/

/*
 * Defined by "search.c".
 */
extern	int	forwsearch();		/* Search forward		*/
extern	int	backsearch();		/* Search backwards		*/
extern  int	searchagain();		/* Repeat last search command	*/

/*
 * Defined by "basic.c".
 */
extern	int	gotobol();		/* Move to start of line	*/
extern	int	backchar();		/* Move backward by characters	*/
extern	int	gotoeol();		/* Move to end of line		*/
extern	int	forwchar();		/* Move forward by characters	*/
extern	int	gotobob();		/* Move to start of buffer	*/
extern	int	gotoeob();		/* Move to end of buffer	*/
extern	int	forwline();		/* Move forward by lines	*/
extern	int	backline();		/* Move backward by lines	*/
extern	int	setmark();		/* Set mark			*/
/*
 * Defined by "buffer.c".
 */
extern	int	savebuffers();		/* Save unmodified buffers	*/
extern	int	notmodified();		/* Reset modification flag	*/

#ifdef	DIRLIST
/*
 * Defined by "dirlist.c".
 */
extern	int	dirlist();		/* Directory list.		*/
#endif

/*
 * Defined by "display.c"
 */
extern	int	rotatmode();		/* rotate mode-line help	*/

/*
 * Defined by "file.c".
 */
extern	int	filevisit();		/* Get a file, read write	*/
extern	int	filewrite();		/* Write a file			*/
extern	int	filesave();		/* Save current file		*/
extern	int	fileinsert();		/* Insert file into buffer	*/
#ifdef	BACKUP
extern	int	makebkfile();		/* Control backups on saves	*/
#endif

/*
 * Defined by "random.c".
 */
extern	int	selfinsert();		/* Insert character		*/
extern	int	showcpos();		/* Show the cursor position	*/
extern	int	openline();		/* Open up a blank line		*/
extern	int	newline();		/* Insert CR-LF			*/
extern	int	forwdel();		/* Forward delete		*/
extern	int	backdel();		/* Backward delete in		*/
extern	int	killline();		/* Kill forward			*/
extern	int	bsmapmode();		/* set bsmap mode		*/
extern	int	flowmode();		/* set flow mode		*/
extern	int	fillmode();		/* set word-wrap mode		*/
extern	int	insovrmode();		/* toggle insert overstrike mode */
extern	int	yank();			/* Yank back from killbuffer.	*/

/*
 * Defined by "region.c".
 */
extern	int	killregion();		/* Kill region.			*/
#ifdef	PREFIXREGION
extern	int	prefixregion();		/* Prefix all lines in region	*/
extern	int	setprefix();		/* Set line prefix string	*/
#endif

/*
 * Defined by "window.c".
 */
extern	int	reposition();		/* Reposition window		*/
extern	int	refresh();		/* Refresh the screen		*/

/*
 * Defined by "word.c".
 */
extern	int	delfword();		/* Delete forward word.		*/
extern	int	delbword();		/* Delete backward word.	*/

/*
 * Defined by "extend.c".
 */
extern	int	extend();		/* Extended commands.		*/
extern	int	startover();		/* reread file, restart edit	*/
extern	int	reallyquit();		/* kill emacs, don't save files	*/
extern	int	deleteline();		/* delete line from anywhere	*/
#ifdef	STARTUP
extern	int	evalexpr();		/* Extended commands (again)	*/
extern	int	evalbuffer();		/* Evaluate current buffer	*/
extern	int	evalfile();		/* Evaluate a file		*/
#endif

/*
 * defined by "paragraph.c" - the paragraph justification code.
 */
extern	int	gotobop();		/* Move to start of paragraph.	*/
extern	int	gotoeop();		/* Move to end of paragraph.	*/
extern	int	fillpara();		/* Justify a paragraph.		*/
extern	int	killpara();		/* Delete a paragraph.		*/
extern	int	setfillcol();		/* Set fill column for justify.	*/
extern	int	fillword();		/* Insert char with word wrap.	*/

#ifdef MISLOG
/*
 * defined by "newlog.c" - the mislog code.
 */
extern	int	newlog();		/* newlog function for MISLOG	*/
#endif

typedef	struct	{
	KEY	k_key;			/* Key to bind.			*/
	int	(*k_funcp)();		/* Function.			*/
	char	*k_name;		/* Function name string.	*/
}	KEYTAB;

/*
 * Default key binding table. This contains
 * the function names, the symbol table name, and (possibly)
 * a key binding for the builtin functions. There are no
 * bindings for C-U or C-X. These are done with special
 * code, but should be done normally.
 */
KEYTAB	key[] = {
	KCTRL|'C',	ctrlg,		"keyboard-quit",
	KCTRL|'D',	forwdel,	"delete-char",
	KCTRL|'E',	gotoeol,	"end-of-line",
	KCTRL|'I',	selfinsert,	"self-insert-command",
	KCTRL|'G',	ctrlg,		"keyboard-quit",
	KCTRL|'M',	newline,	"insert-newline",
	KCTRL|'R',	refresh,	"redraw-display",
	KCTRL|'S',	forwsearch,	"search-forward",
	KCTLX|KCTRL|'Q',quit,		"save-buffers-kill-emacs",
	KCTLX|KCTRL|'F',filevisit,	"find-file",
	KMETA|'X',	extend,		"execute-extended-command",
	KCTRL|'B',	backchar,	"backward-char",
	KCTRL|'F',	forwchar,	"forward-char",
	KCTRL|'N',	forwline,	"next-line",
	KCTRL|'P',	backline,	"previous-line",
	KCTLX|'=',	showcpos,	"what-cursor-position",
	KCTLX|'I',	fileinsert,	"insert-file",
	KMETA|'M',	setmark,	"set-mark-command",
	KMETA|'C',	killregion,	"kill-region",
	KMETA|'P',	yank,		"yank",
	' ',		fillword,	"insert-with-wrap",
	-1,		backsearch,	"search-backward",
	-1,		gotobol,	"beginning-of-line",
	-1,		reposition,	"recenter",
	-1,		killline,	"kill-line",
	-1,		openline,	"open-line",
#ifdef	DIRLIST
	-1,		dirlist,	"display-directory",
#endif
	-1,		filesave,	"save-buffer",
	-1,		filewrite,	"write-file",
	-1,		savebuffers,	"save-some-buffers",
	-1,		setfillcol,	"set-fill-column",
	-1,		gotoeob,	"end-of-buffer",
	-1,		gotobob,	"beginning-of-buffer",
	-1,		gotobop,	"backward-paragraph",
	-1,		gotoeop,	"forward-paragraph",
	-1,		fillpara,	"fill-paragraph",
	-1,		notmodified,	"not-modified",
#ifdef	STARTUP
	-1,		evalexpr,	"eval-expression",
	-1,		evalbuffer,	"eval-current-buffer",
	-1,		evalfile,	"load",
#endif
	-1,		bsmapmode,	"bsmap-mode",
	-1,		flowmode,	"flow-mode",
	-1,		fillmode,	"auto-fill-mode",
	-1,		searchagain,	"search-again",
	-1,		killpara,	"kill-paragraph",
#ifdef	PREFIXREGION
	-1,		prefixregion,	"prefix-region",
	-1,		setprefix,	"set-prefix-string",
#endif
#ifdef	BACKUP
	-1,		makebkfile,	"make-backup-files",
#endif
	/* new functions for TinyGnuEmacs */
	-1,		insovrmode,	"toggle-insert-overstrike",
	-1,		startover,	"restart-edit",
	-1,		reallyquit,	"kill-emacs",
	-1,		deleteline,	"delete-line",
	-1,		rotatmode,	"rotate-help",
#ifdef MISLOG
	-1,		newlog,		"newlog",
#endif
};

#define	NKEY	(sizeof(key) / sizeof(key[0]))

/*
 * Just some definitions, to keep ANSI compilers happy.
 */
VOID	keymapinit();
VOID	keyadd();
VOID	keydup();

/*
 * Symbol table lookup.
 * Return a pointer to the SYMBOL node, or NULL if
 * the symbol is not found.
 */
SYMBOL	*
symlookup(cp) register char *cp;
{
	register SYMBOL	*sp;

#ifdef	HASH
	sp = symbol[symhash(cp)];
#else
	sp = symbol[0];
#endif
	while (sp != NULL)
	{
		if (strcmp(cp, sp->s_name) == 0)
			return (sp);
#ifdef	HASH
		if ((sp->s_flags&SFEND) != 0) break;
#endif
		sp = sp->s_symp;
	}
	return (NULL);
}

#ifdef	HASH
/*
 * Take a string, and compute the symbol table
 * bucket number. This is done by adding all of the characters
 * together, and taking the sum mod NSHASH. The string probably
 * should not contain any GR characters; if it does the "*cp"
 * may get a nagative number on some machines, and the "%"
 * will return a negative number!
 */
symhash(cp) register char *cp;
{
	register int	c;
	register int	n;

	n = 0;
	while ((c = *cp++) != 0)
		n += c;
	return (n % NSHASH);
}
#endif

/*
 * Build initial keymap. The funny keys
 * (commands, odd control characters) are mapped using
 * a big table and calls to "keyadd". The printing characters
 * are done with some do-it-yourself handwaving. The terminal
 * specific keymap initialization code is called at the
 * very end to finish up. All errors are fatal.
 */
VOID
keymapinit()
{
	register SYMBOL	*sp;
	register KEYTAB	*kp;
	register int	i;

	for (i=0; i<NKEYS; ++i)
		binding[i] = NULL;
	for (kp = &key[0]; kp < &key[NKEY]; ++kp)
		keyadd(kp->k_key, kp->k_funcp, kp->k_name);
	keydup((KEY) (KCTLX|KCTRL|'C'),	"keyboard-quit");
	keydup((KEY) (KMETA|KCTRL|'C'),	"keyboard-quit");
	keyadd((KEY) (KMETA|0x7F), delbword,
				"backward-kill-word");
	keyadd((KEY) 0x7F, backdel,	"backward-delete-char");
	/*
	 * Should be bound by "tab" already.
	 */
	if ((sp=symlookup("self-insert-command")) == NULL)
		panic("no self-insert-command in keymapinit");
	if (binding[0x20] == NULL)	/* 0x20 == ' ' may already be	*/
		binding[0x20] = sp;	/* bound to insert-with-wrap	*/
	for (i=0x21; i<0x7F; ++i)
	{
		if (binding[i] != NULL)
			panic("nonull binding in keymapinit");
		binding[i] = sp;
	}
	ttykeymapinit();
#ifdef	HASH
	/* Link up the symbol table entries	*/
	for (sp = symbol[i = 0]; i < NSHASH-1; sp = sp->s_symp)
		if (sp->s_symp == NULL) sp->s_symp = symbol[++i];
#endif			
}

/*
 * Create a new builtin function "name"
 * with function "funcp". If the "new" is a real
 * key, bind it as a side effect. All errors
 * are fatal.
 */
VOID
keyadd(new, funcp, name) register KEY new; int (*funcp)(); char *name;
{
	register SYMBOL	*sp;
#ifdef	HASH
	register int	hash;
#endif

	if ((sp=(SYMBOL *)malloc(sizeof(SYMBOL))) == NULL)
		panic("No memory");
#ifdef	HASH
	hash = symhash(name);
	if (symbol[hash] == NULL) sp->s_flags |= SFEND;
	sp->s_symp = symbol[hash];
	symbol[hash] = sp;
#else
	sp->s_symp = symbol[0];
        symbol[0] = sp;
#endif
	sp->s_name = name;
	sp->s_funcp = funcp;
	if (new >= 0)
	{				/* Bind this key.	*/
		if (binding[new] != NULL)
		{
			char buf[80];
			sprintf(buf,"rebinding old symbol: %s", name);
			panic(buf);
		}
		binding[new] = sp;
	}
}

/*
 * Bind key "new" to the existing
 * routine "name". If the name cannot be found,
 * or the key is already bound, abort.
 */
VOID
keydup(new, name) register KEY new; char *name;
{
	register SYMBOL	*sp;

	if (binding[new]!=NULL || (sp=symlookup(name))==NULL)
	{
#ifdef	KEYDUP_ERROR
		fprintf (stderr, "keydup: binding[%d] = %x",
				new, binding[new]);
		fprintf (stderr, " and symlookup(%s) == %x\n", name, sp);
#endif
		panic("keydup");
	}
	binding[new] = sp;
}
\Rogue\Monster\
else
  echo "will not over write ./symbol.c"
fi
if `test ! -s ./tty.c`
then
echo "writing ./tty.c"
cat > ./tty.c << '\Rogue\Monster\'
/*
 * Termcap/terminfo display driver
 *
 * Termcap is a terminal information database and routines to describe 
 * terminals on most UNIX systems.  Many other systems have adopted
 * this as a reasonable way to allow for widly varying and ever changing
 * varieties of terminal types.  This should be used where practical.
 */
/* Known problems:
 *	tputs is always called with the number of lines affected set to
 *	one.  Therefore, padding may be insufficient on some sequences
 *	dispite termcap being set up correctly.
 *
 *	If you have a terminal with no clear to end of screen and
 *	memory of lines below the ones visible on the screen, display
 *	will be wrong in some cases.  I doubt that any such terminal
 *	was ever made, but I thought everyone with delete line would
 *	have clear to end of screen too...
 *
 *	Code for terminals without clear to end of screen and/or clear
 *	to end of line has not been extensivly tested.
 *
 *	Cost calculations are very rough.  Costs of insert/delete line
 *	may be far from the truth.  This is accentuated by display.c
 *	not knowing about multi-line insert/delete.
 *
 *	Using scrolling region vs insert/delete line should probably
 *	be based on cost rather than the assuption that scrolling
 *	region operations look better.
 */
#include	"def.h"

#define	BEL	0x07			/* BEL character.		*/
#define	LF	0x0A			/* Line feed.			*/

extern	int	ttrow;
extern	int	ttcol;
extern	int	tttop;
extern	int	ttbot;
extern	int	tthue;

int	tceeol;			/* Costs are set later */
int	tcinsl;
int	tcdell;

static	int	insdel;		/* Do we have both insert & delete line? */

#ifdef NO_RESIZE
static  setttysize();
#endif

char	*tgetstr();
char	*tgoto();
int	ttputc();

#define TCAPSLEN 1024

char tcapbuf[TCAPSLEN];

/* PC, UP, and BC are used by termlib, so must be extern and have these
 * names unless you have a non-standard termlib.
 */

int	LI;			/* standard # lines */
char    PC,
        *CM,
        *CE,
        *UP,
	*BC,
	*IM,			/* insert mode */
	*IC,			/* insert a single space */
	*EI,			/* end insert mode */
	*DC,
	*AL,			/* add line */
	*DL,			/* del line */
	*pAL,			/* parameterized add line */
	*pDL,			/* parameterized delete line */
	*TI,			/* term init -- start using cursor motion */
	*TE,			/* term end --- end using cursor motion */
	*SO,
	*SE,
        *CD,
	*CS,			/* set scroll region			*/
	*SR;			/* back index (used with scroll region	*/
#ifdef	XKEYS
char	*K[NFKEYS],		/* other function key codes		*/
	*L[NFKEYS],		/* labels for other functions keys	*/
	*KS, *KE,		/* enter keypad mode, exit keypad mode	*/
	*KH, *KU, *KD, *KL, *KR; /* home, arrow keys			*/
#endif
int	SG;	/* number of glitches, 0 for invisable, -1 for none	*/
	/* (yes virginia, there are terminals with invisible glitches)	*/

/*
 * Initialize the terminal when the editor
 * gets started up.
 */
static char tcbuf[1024];

ttinit() {
#ifndef __50SERIES
        char *getenv();
        char *tv_stype;
#else
        fortran void gv$get();
        short code;
        static struct {short len; char data[15];} TERM
            = {15, '.'|0200, 'T'|0200, 'E'|0200, 'R'|0200, 'M'|0200,
                   'I'|0200, 'N'|0200, 'A'|0200, 'L'|0200, '_'|0200,
                   'T'|0200, 'Y'|0200, 'P'|0200, 'E'|0200, '$'|0200};
        struct {short len; char data[32];} termtype;
#       define tv_stype termtype.data
#endif
        char *t, *p, *tgetstr();
#ifdef	XKEYS
	char kname[3], lname[3];
	int i;
#endif

#ifdef	VAXC
        if ((tv_stype = trnlnm("TERM")) == NULL)
	{
		ttclose();
                panic("Environment variable TERM not defined!");
	}
#else
#ifndef __50SERIES
        if ((tv_stype = getenv("TERM")) == NULL)/* Don't want VAX C getenv() */
	{
		ttclose();
                panic("Environment variable TERM not defined!");
	}
#else
        gv$get(TERM, termtype, 31, code);
        if (code)
	{
		ttclose();
		panic("Global variable .Terminal_Type$ not defined");
        }
	termtype.data[termtype.len] = '\0';
        t = tv_stype;
        while(*t) *t++ &= 0177;
#endif
#endif
        if((tgetent(tcbuf, tv_stype)) != 1)
	{
		(VOID) strcpy(tcbuf, "Unknown terminal type ");
		(VOID) strcat(tcbuf, tv_stype);
		ttclose();
                panic(tcbuf);
        }

        p = tcapbuf;
        t = tgetstr("pc", &p);
        if(t) PC = *t;

	LI = tgetnum("li");
        CD = tgetstr("cd", &p);
        CM = tgetstr("cm", &p);
        CE = tgetstr("ce", &p);
        UP = tgetstr("up", &p);
	BC = tgetstr("bc", &p);
	IM = tgetstr("im", &p);
	IC = tgetstr("ic", &p);
	EI = tgetstr("ei", &p);
	DC = tgetstr("dc", &p);
	AL = tgetstr("al", &p);
	DL = tgetstr("dl", &p);
	pAL= tgetstr("AL", &p);	/* parameterized insert and del. line */
	pDL= tgetstr("DL", &p);
	TI = tgetstr("ti", &p);
	TE = tgetstr("te", &p);
	SO = tgetstr("so", &p);
	SE = tgetstr("se", &p);
	CS = tgetstr("cs", &p); /* set scrolling region */
	SR = tgetstr("sr", &p);
	SG = tgetnum("sg");	/* standout glitch 	*/
#ifdef	XKEYS
	/* get the 10 standard termcap keys */
	strcpy(kname,"kx");
	strcpy(lname,"lx");
	for (i = 1; i < 10; i++) {
		kname[1] = i + '0';
		K[i] = tgetstr(kname, &p);
		lname[1] = i + '0';
		L[i] = tgetstr(lname, &p);
	}
	kname[1] = 'A';
	K[0] = tgetstr(kname, &p);
	lname[1] = 'A';
	L[0] = tgetstr(lname, &p);

	/* Hack to get another bunch */
	strcpy(kname,"Kx");
	strcpy(lname,"Lx");
	for (i = 1; i < 10; i++) {
		kname[1] = i + '0';
		K[10 + i] = tgetstr(kname, &p);
		lname[1] = i + '0';
		L[10 + i] = tgetstr(lname, &p);
	}
	kname[1] = 'A';
	K[10] = tgetstr(kname, &p);
	lname[1] = 'A';
	L[10] = tgetstr(lname, &p);

	/* Get the rest of the sequences */
	KS = tgetstr("ks", &p);
	KE = tgetstr("ke", &p);
	KH = tgetstr("kh", &p);
	KU = tgetstr("ku", &p);
	KD = tgetstr("kd", &p);
	KL = tgetstr("kl", &p);
	KR = tgetstr("kr", &p);
#endif

        if(CM == NULL || UP == NULL)
	{
		ttclose();
		panic("This terminal is too stupid to run MicroGnuEmacs\n");
	}
	ttresize();			/* set nrow & ncol	*/

	/* watch out for empty capabilities (sure to be wrong)	*/
	if (CE && !*CE) CE = NULL;
	if (CS && !*CS) CS = NULL;
	if (SR && !*SR) SR = NULL;
	if (AL && !*AL) AL = NULL;
	if (DL && !*DL) DL = NULL;
	if (pAL && !*pAL) pAL = NULL;
	if (pDL && !*pDL) pDL = NULL;
	if (CD && !*CD) CD = NULL;

	if(!CE)	tceeol = ncol;
	else 	tceeol = charcost(CE);

	/* Estimate cost of inserting a line */
	if (CS && SR)	tcinsl = charcost(CS)*2 + charcost(SR);
	else if (pAL)   tcinsl = charcost(pAL);
	else if (AL)    tcinsl = charcost(AL);
	else		tcinsl = NROW * NCOL;	/* make this cost high enough */

	/* Estimate cost of deleting a line */
	if (CS)		tcdell = charcost(CS)*2 + 1;
	else if (pDL)   tcdell = charcost(pDL);
	else if (DL)    tcdell = charcost(DL);
	else		tcdell = NROW * NCOL;	/* make this cost high enough */

	/* Flag to indicate that we can both insert and delete lines */
	insdel = (AL || pAL) && (DL || pDL);

        if (p >= &tcapbuf[TCAPSLEN])
	{
		ttclose();
		panic("Terminal description too big!\n");
	}
	if (TI && *TI)
		putpad (TI);	/* init the term */
}

/*
 * Clean up the terminal, in anticipation of
 * a return to the command interpreter. This is a no-op
 * on the ANSI display. On the SCALD display, it sets the
 * window back to half screen scrolling. Perhaps it should
 * query the display for the increment, and put it
 * back to what it was.
 */
tttidy() {
	if (TE && *TE) putpad (TE);	/* set the term back to normal mode */
#ifdef	XKEYS
	ttykeymaptidy();
#endif
}

/*
 * Move the cursor to the specified
 * origin 0 row and column position. Try to
 * optimize out extra moves; redisplay may
 * have left the cursor in the right
 * location last time!
 */
ttmove(row, col) {
    char        *tgoto();

    if (ttrow!=row || ttcol!=col) {
	putpad(tgoto(CM, col, row));
	ttrow = row;
	ttcol = col;
    }
}

/*
 * Erase to end of line.
 */
tteeol() {
    if(CE) putpad(CE);
    else {
	register int i=ncol-ttcol;
	while(i--) ttputc(" ");
	ttrow = ttcol = HUGE;
    }
}

/*
 * Erase to end of page.
 */
tteeop() {
    if(CD) putpad(CD);
    else {
    	putpad(CE);
	if (insdel) ttdell(ttrow + 1, LI, LI - ttrow - 1);
	else {		/* do it by hand */
	    register int line;
	    for (line = ttrow + 1; line <= LI; ++line) {
	    	ttmove(line, 0);
		tteeol();
	    }
	}
	ttrow = ttcol = HUGE;
    }
}

/*
 * Make a noise.
 */
ttbeep() {
	ttputc(BEL);
	ttflush();
}

/*
 * Insert nchunk blank line(s) onto the
 * screen, scrolling the last line on the
 * screen off the bottom.  Use the scrolling
 * region if possible for a smoother display.
 * If no scrolling region, use a set
 * of insert and delete line sequences
 */
ttinsl(row, bot, nchunk) {
    register int	i;
    
    if (row == bot) {		/* Case of one line insert is 	*/
	ttmove(row, 0);		/*	special			*/
	tteeol();
	return;
    }
    if (CS && SR) {		/* Use scroll region and back index	*/
	ttwindow(row,bot);
	ttmove(row, 0);
	while (nchunk--) putpad(SR);
	ttnowindow();
	return;
    } else if (insdel) {
	ttmove(1+bot-nchunk, 0);
	if (pDL) putpad (tgoto(pDL, 0, nchunk));
	else for (i=0; i<nchunk; i++)	/* For all lines in the chunk	*/
		putpad(DL);
	ttmove(row, 0);
	if (pAL) putpad (tgoto(pAL, 0, nchunk));
	else for (i=0; i<nchunk; i++)	/* For all lines in the chunk	*/
		putpad(AL);
	ttrow = HUGE;
	ttcol = HUGE;
    } else panic("ttinsl: Can't insert/delete line");
}

/*
 * Delete nchunk line(s) from "row", replacing the
 * bottom line on the screen with a blank line. 
 * Unless we're using the scrolling region, this is 
 * done with a crafty sequences of insert and delete 
 * lines.  The presence of the echo area makes a
 * boundry condition go away.
 */
ttdell(row, bot, nchunk)
{
    register int	i;
    
    if (row == bot) {		/* One line special case	*/
	ttmove(row, 0);
	tteeol();
	return;
    }
    if (CS) {			/* scrolling region	*/
	ttwindow(row, bot);
	ttmove(bot, 0);
	while (nchunk--) ttputc(LF);
	ttnowindow();
    }
    else if(insdel) {
	ttmove(row, 0);			/* Else use insert/delete line	*/
	if (pDL) putpad (tgoto(pDL, 0, nchunk));
	else for (i=0; i<nchunk; i++)	/* For all lines in the chunk	*/
		putpad(DL);
	ttmove(1+bot-nchunk,0);
	if (pAL) putpad (tgoto(pAL, 0, nchunk));
	else for (i=0; i<nchunk; i++)	/* For all lines in the chunk	*/
		putpad(AL);
	ttrow = HUGE;
	ttcol = HUGE;
    } else panic("ttdell: Can't insert/delete line");
}

/*
 * This routine sets the scrolling window
 * on the display to go from line "top" to line
 * "bot" (origin 0, inclusive). The caller checks
 * for the pathalogical 1 line scroll window that
 * doesn't work right, and avoids it. The "ttrow"
 * and "ttcol" variables are set to a crazy value
 * to ensure that the next call to "ttmove" does
 * not turn into a no-op (the window adjustment
 * moves the cursor).
 * 
 */
ttwindow(top, bot)
{
	if (CS && (tttop!=top || ttbot!=bot)) {
		putpad(tgoto(CS, bot, top));
		ttrow = HUGE;			/* Unknown.		*/
		ttcol = HUGE;
		tttop = top;			/* Remember region.	*/
		ttbot = bot;
	}
}

/*
 * Switch to full screen scroll. This is
 * used by "spawn.c" just before is suspends the
 * editor, and by "display.c" when it is getting ready
 * to exit.  This function gets to full screen scroll 
 * by telling the terminal to set a scrolling regin
 * that is LI or nrow rows high, whichever is larger.
 * This behavior seems to work right on systems
 * where you can set your terminal size.
 */
ttnowindow()
{
    if (CS) {
	putpad(tgoto(CS, (nrow > LI ? nrow : LI) - 1, 0));
	ttrow = HUGE;			/* Unknown.		*/
	ttcol = HUGE;
	tttop = HUGE;			/* No scroll region.	*/
	ttbot = HUGE;
    }
}

/*
 * Set the current writing color to the
 * specified color. Watch for color changes that are
 * not going to do anything (the color is already right)
 * and don't send anything to the display.
 * The rainbow version does this in putline.s on a
 * line by line basis, so don't bother sending
 * out the color shift. The "color already right" optimization
 * doesn't work on some terminals (such as Falco): it's gone!
 */
ttcolor(color) register int color; {
    if (color == CTEXT) {		/* Normal video.	*/
        putpad(SE);
    } else if (color == CMODE) {	/* Reverse video.	*/
        putpad(SO);
    }
    tthue = color;			/* Save the color.	*/
}

/*
 * This routine is called by the
 * "refresh the screen" command to try and resize
 * the display. The new size, which must be deadstopped
 * to not exceed the NROW and NCOL limits, it stored
 * back into "nrow" and "ncol". Display can always deal
 * with a screen NROW by NCOL. Look in "window.c" to
 * see how the caller deals with a change.
 */
ttresize() {
	setttysize();			/* found in "ttyio.c",	*/
					/* ask OS for tty size	*/
	if (nrow < 1)			/* Check limits.	*/
		nrow = 1;
	else if (nrow > NROW)
		nrow = NROW;
	if (ncol < 1)
		ncol = 1;
	else if (ncol > NCOL)
		ncol = NCOL;
}

#ifdef NO_RESIZE
static setttysize() {
	nrow = tgetnum("li");
	ncol = tgetnum("co");
}
#endif

static int cci;

static			/* fake char output for charcost() */
fakec(c) char c; {
#ifdef	lint
	c++;
#endif
	cci++;
}

/* calculate the cost of doing string s */
charcost (s) char *s; {
    cci = 0;

    tputs(s, nrow, fakec);
    return cci;
}

putpad(str) char *str; {
        tputs(str, 1, ttputc);
}
\Rogue\Monster\
else
  echo "will not over write ./tty.c"
fi
if `test ! -s ./ttyio.c`
then
echo "writing ./ttyio.c"
cat > ./ttyio.c << '\Rogue\Monster\'
/*
 * Name:	MicroEMACS
 *		System V terminal I/O.
 * Version:	0
 * Last edit:	Tue Aug 26 23:57:57 PDT 1986
 * By:		gonzo!daveb
 *		{sun, amdahl, mtxinu}!rtech!gonzo!daveb
 *
 * The functions in this file
 * negotiate with the operating system for
 * keyboard characters, and write characters to
 * the display in a barely buffered fashion.
 *
 * This version goes along with tty/termcap/tty.c.
 * Terminal size is determined there, rather than here, and
 * this does not open the termcap file
 */
#include	"def.h"

#include	<sys/types.h>
#include	<fcntl.h>
#include	<termio.h>

#define	NOBUF	512			/* Output buffer size.		*/

char	obuf[NOBUF];			/* Output buffer.		*/
int	nobuf;				/* buffer count			*/

static struct termio	ot;		/* entry state of the terminal	*/
static struct termio	nt;		/* editor's terminal state	*/

static int ttyactivep = FALSE;		/* terminal in editor mode?	*/
static int ttysavedp = FALSE;		/* terminal state saved?	*/

int	nrow;				/* Terminal size, rows.		*/
int	ncol;				/* Terminal size, columns.	*/

/* These are used to implement typeahead on System V */

int kbdflgs;			/* saved keyboard fd flags	*/
int kbdpoll;			/* in O_NDELAY mode			*/
int kbdqp;			/* there is a char in kbdq	*/
char kbdq;			/* char we've already read	*/

/*
 * This function gets called once, to set up
 * the terminal channel.  This version turns off flow
 * control.  This may be wrong for your system, but no
 * good solution has really been found (daveb).
 */
ttopen()
{
	register char	*cp;
	extern char	*getenv();

	if (ttyactivep)
		return;

	if( !ttysavedp )
	{
		if (ioctl(0, TCGETA, &ot) < 0)
			abort();
		nt = ot;		/* save entry state		*/
		nt.c_cc[VMIN] = 1;	/* one character read is OK	*/
		nt.c_cc[VTIME] = 0;	/* Never time out.		*/
		nt.c_iflag |= IGNBRK;
		nt.c_iflag &= ~( ICRNL | INLCR | ISTRIP | IXON | IXOFF );
		nt.c_oflag &= ~OPOST;
#ifdef BIT7EVEN
		nt.c_cflag &= ~CS8;
		nt.c_cflag |= CS7;	/* disallow 8th bit on input	*/
		nt.c_cflag |= PARENB;	/* check parity			*/
		nt.c_cflag &= ~PARODD;	/* even parity			*/
#else
		nt.c_cflag |= CS8;	/* allow 8th bit on input	*/
		nt.c_cflag &= ~PARENB;	/* Don't check parity		*/
#endif
		nt.c_lflag &= ~( ECHO | ICANON | ISIG );

		kbdflgs = fcntl( 0, F_GETFL, 0 );
		kbdpoll = FALSE;
	
		ttysavedp = TRUE;
	}
	
	if (ioctl(0, TCSETAF, &nt) < 0)
		abort();

	/* This really belongs in tty/termcap... */

	if ((cp=getenv("TERMCAP")) == NULL
	|| (nrow=getvalue(cp, "li")) <= 0
	|| (ncol=getvalue(cp, "co")) <= 0) {
		nrow = 24;
		ncol = 80;
	}
	if (nrow > NROW)			/* Don't crash if the	*/
		nrow = NROW;			/* termcap entry is	*/
	if (ncol > NCOL)			/* too big.		*/
		ncol = NCOL;

	ttyactivep = TRUE;
}

/*
 * This routine scans a string, which is
 * actually the return value of a getenv call for the TERMCAP
 * variable, looking for numeric parameter "name". Return the value
 * if found. Return -1 if not there. Assume that "name" is 2
 * characters long. This limited use of the TERMCAP lets us find
 * out the size of a window on the X display.
 */
getvalue(cp, name)
register char	*cp;
register char	*name;
{
	for (;;) {
		while (*cp!=0 && *cp!=':')
			++cp;
		if (*cp++ == 0)			/* Not found.		*/
			return (-1);
		if (cp[0]==name[0] && cp[1]==name[1] && cp[2]=='#')
			return (atoi(cp+3));	/* Stops on ":".	*/
	}
}

/*
 * This function gets called just
 * before we go back home to the shell. Put all of
 * the terminal parameters back.
 */
ttclose()
{
	if(!ttysavedp || !ttyactivep)
		return;
	ttflush();
	if (ioctl(0, TCSETAF, &ot) < 0 || fcntl( 0, F_SETFL, kbdflgs ) < 0)
		abort();
	ttyactivep = FALSE;
}

/*
 * Write character to the display.
 * Characters are buffered up, to make things
 * a little bit more efficient.
 */
ttputc(c)
{
	if (nobuf >= NOBUF)
		ttflush();
	obuf[nobuf++] = c;
}

/*
 * Flush output.
 */
ttflush()
{
	if (nobuf != 0) {
		write(1, obuf, nobuf);
		nobuf = 0;
	}
}

/*
 * Read character from terminal.
 * All 8 bits are returned, so that you can use
 * a multi-national terminal.
 *
 * If keyboard 'queue' already has typeahead from a typeahead() call,
 * just return it.  Otherwise, make sure we are in blocking i/o mode
 * and read a character.
 */
ttgetc()
{
	if( kbdqp )
		kbdqp = FALSE;
	else
	{
		if( kbdpoll && fcntl( 0, F_SETFL, kbdflgs ) < 0 )
			abort();
		kbdpoll = FALSE;
		while (read(0, &kbdq, 1) != 1)
			;
	}
#ifdef BIT7EVEN
	return ( kbdq & 0x7f );
#else
	return ( kbdq & 0xff );
#endif
}

/*
 * Return non-FALSE if typeahead is pending.
 *
 * If already got unread typeahead, do nothing.
 * Otherwise, set keyboard to O_NDELAY if not already, and try
 * a one character read.
 */
typeahead()
{
	if( !kbdqp )
	{
		if( !kbdpoll && fcntl( 0, F_SETFL, kbdflgs | O_NDELAY ) < 0 )
			abort();
		kbdqp = (1 == read( 0, &kbdq, 1 ));
	}
	return ( kbdqp );
}


/*
 * panic:  print error and die, leaving core file.
 * Don't know why this is needed (daveb).
 */
panic(s)
char *s;
{
	fprintf(stderr, "%s\r\n", s);
	abort();
}


/*
** This should check the size of the window, and reset if needed.
*/

setttysize()
{
#ifdef	TIOCGWINSZ
	if (ioctl(0, TIOCGWINSZ, (char *) &winsize) == 0) {
		nrow = winsize . ws_row;
		ncol = winsize . ws_col;
	} else
#endif
	if ((nrow=tgetnum ("li")) <= 0
	|| (ncol=tgetnum ("co")) <= 0) {
		nrow = 24;
		ncol = 80;
	}
	if (nrow > NROW)			/* Don't crash if the	*/
		nrow = NROW;			/* termcap entry is	*/
	if (ncol > NCOL)			/* too big.		*/
		ncol = NCOL;
}

\Rogue\Monster\
else
  echo "will not over write ./ttyio.c"
fi
if `test ! -s ./ttykbd.c`
then
echo "writing ./ttykbd.c"
cat > ./ttykbd.c << '\Rogue\Monster\'
/*
 * Name:	MicroEmacs
 * Version:	30
 *		Termcap keyboard driver
 * Created:	21-Aug-1986
 *		Mic Kaczmarczik ...!ihnp4!seismo!ut-sally!ut-ngp!mic
 * Last edit:	20-Feb-1987
 *
 * [ Several of the nasty comments about the XKEYS code are
 *   by me.  [Bob Larson (usc-oberon!blarson)]  It is my opinion
 *   that function keys cannot be made to work with standard
 *   emacs keybindings except on a very limited set of terminals.
 *   I just work with to many that do not fit the assumptions Mic's
 *   XKEYS code makes to consider it useful to me, and think that
 *   others considering using this code should look and see what
 *   it realy does first.
 * ]
 *
 * If XKEYS is defined this routine looks for the following 
 * termcap sequences, which are obtained by "tty.c":
 *
 *	ks	-- start keypad transmit mode
 *	ke	-- end keypad transmit mode
 *	kh	-- home key
 *	ku	-- up arrow
 *	kd	-- down arrow
 *	kl	-- left arrow
 *	kr	-- right arrow
 *	k0-k9	-- standard termcap function keys
 *	l0-l9	-- labels for termcap function keys
 *	(nonstandard)
 *	K0-K9	-- extra keys that we look for -- the get mapped
 *		   internally to F10-F19
 *	L0-L9	-- labels for same.
 *
 * Bugs/features/problems:
 *
 *	XKEYS and DPROMPT do not work together well.
 *
 *	If the META introducer is used as the initial character of
 *	a function key sequence, what should the key parser do when the
 *	user wants to type a META-ed key, or just the META introducer
 *	alone?	This is of practical importance on DEC terminals, where
 *	the META introducer is the Escape key.  Even worse things happen
 *	on terminals that have something (or more than one thing) other
 *	than the META introducer as the inital character of a function
 *	sequence.
 *
 *	The approach I took was that if the META introducer is the first
 *	character in a function sequence, and the second character c
 *	isn't part of a function key sequence, the parser returns
 *	(KMETA | c).  If it sees two META introducers in a row, it
 *	returns one instance of METACH.   This approach is subject to
 *	discussion and debate, but it works.  [In at lease some cases.]
 *
 *	If the META introducer is NOT the first character in a function
 *	sequence (including arrow keys) this code has a very nasty
 *	side effect of eating that key.  For example, on an Adds viewpoint
 *	60, six normal control characters are eaten if you have defined
 *	XKEYS and put the keys in the termcap.  More than a little 
 *	creativity is needed because ^U is one of the arrow keys, and
 *	prefixes aren't bindable.
 *
 *	[ From a quick look at the code, it seems that a single character
 *	  funciton key won't work, but it is still put in the table.
 *	]
 */
#include	"def.h"

/*
 * Default key name table.  Can be overridden by
 * definitions of l0-l9 in the termcap entry.  You
 * can't redefine the names for the arrow keys
 * and the home key.
 */

#ifdef	XKEYS
/* key sequences (from tty.c) */
extern	char	*K[], *L[], *KS, *KE, *KH, *KU, *KD, *KL, *KR;
extern	int	putpad();	/* also from tty.c */
char	*keystrings[] = {
	NULL,		"Home",		"Down-Arrow",	"Up-Arrow",
	"Left-Arrow",	"Right-Arrow",	"F0",		"F1",
	"F2",		"F3",		"F4",		"F5",
	"F6",		"F7",		"F8",		"F9",
	"F10",		"F11",		"F12",		"F13",
	"F14",		"F15",		"F16",		"F17",
	"F18",		"F19",		NULL,		NULL,
	NULL,		NULL,		NULL,		NULL
};
#else
char	*keystrings[] = {
	NULL,		NULL,		NULL,		NULL,
	NULL,		NULL,		NULL,		NULL,
	NULL,		NULL,		NULL,		NULL,
	NULL,		NULL,		NULL,		NULL,
	NULL,		NULL,		NULL,		NULL,
	NULL,		NULL,		NULL,		NULL,
	NULL,		NULL,		NULL,		NULL,
	NULL,		NULL,		NULL,		NULL
};
#endif

#ifdef	XKEYS
/*
 * Type declarations for data structure we
 * use to parse for function key sequences
 */
#define	NODE		0	/* internal node		*/
#define	VALUE		1	/* internal key code value	*/
#define SENTINEL	2	/* sentinel value		*/

typedef struct trienode {
	int type;	/* one of NODE, LEAF */
	struct trienode *sibling, *child;
	KEY value;
} TRIENODE, *TRIE;

TRIE keywords, sentinel, talloc(), tinsert();
#endif

/*
 * Get keyboard character, and interpret
 * any special keys on the keyboard.  If XKEYS is
 * #defined, use a dictionary organized as a
 * trie to keep the parsing overhead down.
 *
 * To keep the function call overhead down, do the
 * first level of parse() inside getkbd().
 *
 * Also, since ESC (the usual value of METACH) is
 * the first character in many function key sequences,
 * we  return (KMETA | ch) if METACH-<ch> is not
 * the start of an escape sequence.  Blecch.  Furthermore,
 * if we see METACH-METACH, we return the value METACH.
 * Phhhht.
 */
getkbd()
{
#ifndef	XKEYS
	return (ttgetc());
#else
	register TRIE	t;
	register int	c;
	KEY		code;

	c = ttgetc();
	for (t = keywords; t->type == NODE; t = t->sibling)
		if (t->value == c)
		{	/* possible function key sequence  */
			if (c != METACH)
				return (parse(t->child));
			else
			{		/* maybe sequence, maybe META char */
				c = ttgetc();
				for (t = t->child; t->type == NODE; t = t->sibling)
					if (t->value == c)
						return (parse(t->child));
				/* METACH-METACH -> METACH */
				if (c == METACH)
					return (METACH);
				/* Else make c into a META character */
				if (ISLOWER(c) != FALSE)
					c = TOUPPER(c);
				if (c>=0x00 && c<=0x1F)
					c = KCTRL | (c+'@');
				return (KMETA | c);
			}
		}
	return (c);
#endif
}

#ifdef	XKEYS
static parse(first)
TRIE first;
{
	register TRIE	t;
	register int	c;

	if (first->type == VALUE)		/* found a match!	*/
		return (first->value);

	c = ttgetc();
	for (t = first; t->type == NODE; t = t->sibling)/* look thru list   */
		if (t->value == c)
			return (parse(t->child));	/* try next level   */
	return (c);	/* nothing matched */
}
#endif

/*
 * If XKEYS is defined, get key definitions from the termcap 
 * entry and put them in the parse table.
 *
 * If DO_METAKEY is defined, kbd.c expects function keys to have
 * KCTRL set to differentiate them from real meta-ized control
 * characters. To do this, we put the code (KCTRL | fkey) into
 * the dictionary, instead of the code itself.  Trust me...
 */

#ifdef	DO_METAKEY
#define	FNKEY(c) ((KEY) (KCTRL | c))
#else
#define	FNKEY(c) ((KEY) c)
#endif

ttykeymapinit()
{
#ifdef	XKEYS
	register int	i;
	register int	s;
	register char	*cp;
	register SYMBOL	*sp;
	extern	 int	spawncmd();
	extern   int	spawninsert();

	if (KS && *KS)			/* turn on keypad	*/
		putpad(KS);		

	tinit();			/* set up initial trie */

	for (i = 0; i < NFKEYS; i++)
	{
		if (K[i] && *K[i])
			adddict(K[i], FNKEY(KF0 + i));
		if (L[i] && *L[i])	/* record new name */
			keystrings[(KF0-KFIRST)+i] = L[i];
	}

	/*
	 * Add the home and arrow keys
	 */
	if (KH && *KH)
		adddict(KH, FNKEY(KHOME));
	if (KU && *KU)
		adddict(KU, FNKEY(KUP));
	if (KD && *KD)
		adddict(KD, FNKEY(KDOWN));
	if (KL && *KL)
		adddict(KL, FNKEY(KLEFT));
	if (KR && *KR)
		adddict(KR, FNKEY(KRIGHT));

	/*
	 * Bind things to the movement keys
	 */
	keydup(KHOME,	"beginning-of-buffer");	/* for now */
	keydup(KUP,	"previous-line");
	keydup(KDOWN,	"next-line");
	keydup(KLEFT,	"backward-char");
	keydup(KRIGHT,	"forward-char");

	keydup( KF1,	"save-buffers-kill-emacs");
#ifdef MISLOG
	keydup( KF2,	"newlog");
#endif
	keydup( KF3,	"previous-line");
	keydup( KF4,	"next-line");
	keydup( KF5,	"open-line");			/* modified function */
	keydup( KF6,	"fill-paragraph");
#ifdef MENU_INSERT
	keyadd( KF7,	spawninsert,	"spawn-insert-file");/* new function */
#endif
	keydup( KF8,	"toggle-insert-overstrike");	/* new function */
	keydup( KF9,	"save-buffer");
	keydup( KF0,	"rotate-help");			/* new function */
	keydup( KF11,	"restart-edit");		/* new function */
	keyadd( KF12,	spawncmd,	"print-buffer");/* new function */
	keydup( KF13,	"search-forward");
	keydup( KF14,	"backward-paragraph");
	keydup( KF15,	"forward-paragraph");
	keydup( KF16,	"beginning-of-line");
	keydup( KF17,	"end-of-line");
	keydup( KF18,	"delete-line");			/* new function */
	keydup( KF19,	"kill-emacs");			/* new function */

#endif	XKEYS
}

#ifdef	XKEYS
/*
 * Clean up the keyboard -- called by tttidy()
 */
ttykeymaptidy()
{
	tdelete(keywords);	/* get rid of parse tree	*/
	free(sentinel);		/* remove sentinel value	*/
	if (KE && *KE)
		putpad(KE);	/* turn off keypad		*/
}

/*
 * * * * * * * * Dictionary management * * * * * * * * *
 */

/*
 * Add a key string to the dictionary.
 */

static adddict(kstr, kcode)
char *kstr;
KEY kcode;
{
	keywords = tinsert(kstr, kcode, keywords);
}

/*
 * Initialize the parse tree by creating the sentinel value
 */

static tinit()
{
	keywords = sentinel = talloc();
	sentinel->type = SENTINEL;
	sentinel->value = (KEY) -1;
	sentinel->sibling = sentinel->child = sentinel;	/* set up a loop */
}

/*
 * Deallocate all the space used by the trie --
 * Tell all the siblings to deallocate space, then
 * all the children.
 */

static tdelete(t)
register TRIE t;
{
	if (t->type != SENTINEL)
	{
		tdelete(t->sibling);
		tdelete(t->child);
		free(t);
	}
}

/*
 * Insert a dictionary key string and a value into the dictionary,
 * returning as the value the first sibling in the current sublevel,
 * which may have been changed by an insertion into the list of siblings.
 */

static TRIE tinsert(kstring, kcode, first)
register char *kstring;
register KEY kcode;
TRIE first;
{
	register TRIE	match;
	register TRIE	p;
	
	if (!*kstring)
	{	/* base case -- return a value node */
		p = talloc();
		p->type = VALUE;
		p->value = kcode;
		p->sibling = p->child = sentinel;
		return (p);
	}
	/* recursive case -- insert rest of string in trie */

	/* search for sibling that matches the current character */
	match = NULL;
	for (p = first; p->type == NODE; p = p->sibling)
		if (p->value == *kstring)
		{
			match = p;
			break;
		}

	if (match == NULL)
	{	/* if not, add it to beginning of the list */
		match = talloc();
		match->type = NODE;
		match->value = *kstring;
		match->sibling = first;
		match->child = sentinel;
		first = match;
	}
	/* add rest of string to this child's subtrie */
	match->child = tinsert(kstring+1, kcode, match->child);
	return (first);
}

/*
 * Allocate a trie node
 */
static TRIE talloc()
{
	char *malloc();
	TRIE t;

	if ((t = (TRIE) malloc(sizeof(TRIENODE))) == NULL)
		panic("talloc: can't allocate trie node!");
	return (t);
}
#endif
\Rogue\Monster\
else
  echo "will not over write ./ttykbd.c"
fi
if `test ! -s ./version.c`
then
echo "writing ./version.c"
cat > ./version.c << '\Rogue\Monster\'
/*
 * This file contains the string that get written 
 * out by the emacs-version command.
 * Rich had it generated by a command file. I do
 * it manually, until I can figure out a way to get
 * the MicroGnuEmacs version number generated in an
 * reasonable and automatic manner.
 */

char	*version = "TinyGnuEmacs 1b" ;

#ifdef __50SERIES
#ifndef __CI
static void dummmy(){}          /* work around bug in primos 64v mode */
#endif
#endif
\Rogue\Monster\
else
  echo "will not over write ./version.c"
fi
if `test ! -s ./window.c`
then
echo "writing ./window.c"
cat > ./window.c << '\Rogue\Monster\'
/*
 *		Window handling.
 */
#include	"def.h"

/*
 * Reposition dot in the current
 * window to line "n". If the argument is
 * positive, it is that line. If it is negative it
 * is that line from the bottom. If it is 0 the window
 * is centered (this is what the standard redisplay code
 * does).  If GOSREC is undefined, default is 0, so it acts like GNU.
 * If GOSREC is defined, with no argument it defaults to 1
 * and works like in Gosling.
 */
/*ARGSUSED*/
reposition(f, n, k)
{
#ifndef	GOSREC
	curwp->w_force = ((f == FALSE) ? 0 : n) ;
#else
	curwp->w_force = n;
#endif
	curwp->w_flag |= WFFORCE;
	sgarbf = TRUE;
	return (TRUE);
}

/*
 * Refresh the display. A call is made to the
 * "ttresize" entry in the terminal handler, which tries
 * to reset "nrow" and "ncol". They will, however, never
 * be set outside of the NROW or NCOL range. If the display
 * changed size, arrange that everything is redone, then
 * call "update" to fix the display. We do this so the
 * new size can be displayed. In the normal case the
 * call to "update" in "main.c" refreshes the screen,
 * and all of the windows need not be recomputed.
 * Note that when you get to the "display unusable"
 * message, the screen will be messed up. If you make
 * the window bigger again, and send another command,
 * everything will get fixed!
 */
/*ARGSUSED*/
refresh(f, n, k)
{
	register WINDOW	*wp;
	register int	oldnrow;
	register int	oldncol;

	oldnrow = nrow;
	oldncol = ncol;
	ttresize();
	if (nrow!=oldnrow || ncol!=oldncol)
	{
		wp = wheadp;			/* Find last.		*/
		while (wp->w_wndp != NULL)
			wp = wp->w_wndp;
		if (nrow < wp->w_toprow+3)
		{	/* Check if too small.	*/
			ewprintf("Display unusable");
			return (FALSE);
		}		
		wp->w_ntrows = nrow-wp->w_toprow-2;
		sgarbf = TRUE;
		update();
		if (kbdmop == NULL) ewprintf("New size %d by %d", nrow, ncol);
	}
	else
		sgarbf = TRUE;
	return (TRUE);
}
\Rogue\Monster\
else
  echo "will not over write ./window.c"
fi
if `test ! -s ./word.c`
then
echo "writing ./word.c"
cat > ./word.c << '\Rogue\Monster\'
/*
 *		Word mode commands.
 * The routines in this file
 * implement commands that work word at
 * a time. There are all sorts of word mode
 * commands. If I do any sentence and/or paragraph
 * mode commands, they are likely to be put in
 * this file.
 */
#include	"def.h"


/*
 * Kill forward by "n" words.
 */
/*ARGSUSED*/
delfword(f, n, k)
{
	register RSIZE	size;
	register LINE	*dotp;
	register int	doto;

	if (n < 0)
		return (FALSE);
	if ((lastflag&CFKILL) == 0)		/* Purge kill buffer.	*/
		kdelete();
	thisflag |= CFKILL;
	dotp = curwp->w_dotp;
	doto = curwp->w_doto;
	size = 0;
	while (n--)
	{
		while (inword() == FALSE)
		{
			if (forwchar(FALSE, 1, KRANDOM) == FALSE)
				goto out;	/* Hit end of buffer.	*/
			++size;
		}
		while (inword() != FALSE)
		{
			if (forwchar(FALSE, 1, KRANDOM) == FALSE)
				goto out;	/* Hit end of buffer.	*/
			++size;
		}
	}
out:
	curwp->w_dotp = dotp;
	curwp->w_doto = doto;
	return (ldelete(size, KFORW));
}

/*
 * Kill backwards by "n" words. The rules
 * for success and failure are now different, to prevent
 * strange behavior at the start of the buffer. The command
 * only fails if something goes wrong with the actual delete
 * of the characters. It is successful even if no characters
 * are deleted, or if you say delete 5 words, and there are
 * only 4 words left. I considered making the first call
 * to "backchar" special, but decided that that would just
 * be wierd. Normally this is bound to "M-Rubout" and
 * to "M-Backspace".
 */
/*ARGSUSED*/
delbword(f, n, k)
{
	register RSIZE	size;

	if (n < 0)
		return (FALSE);
	if ((lastflag&CFKILL) == 0)		/* Purge kill buffer.	*/
		kdelete();
	thisflag |= CFKILL;
	if (backchar(FALSE, 1, KRANDOM) == FALSE)
		return (TRUE);			/* Hit buffer start.	*/
	size = 1;				/* One deleted.		*/
	while (n--)
	{
		while (inword() == FALSE)
		{
			if (backchar(FALSE, 1, KRANDOM) == FALSE)
				goto out;	/* Hit buffer start.	*/
			++size;
		}
		while (inword() != FALSE)
		{
			if (backchar(FALSE, 1, KRANDOM) == FALSE)
				goto out;	/* Hit buffer start.	*/
			++size;
		}
	}
	if (forwchar(FALSE, 1, KRANDOM) == FALSE)
		return (FALSE);
	--size;					/* Undo assumed delete.	*/
out:
	return (ldelete(size, KBACK));
}

/*
 * Return TRUE if the character at dot
 * is a character that is considered to be
 * part of a word. The word character list is hard
 * coded. Should be setable.
 */
inword()
{
	if (curwp->w_doto == llength(curwp->w_dotp))
		return (FALSE);
	if (ISWORD(lgetc(curwp->w_dotp, curwp->w_doto)) != FALSE)
		return (TRUE);
	return (FALSE);
}
\Rogue\Monster\
else
  echo "will not over write ./word.c"
fi
echo "Finished archive 1 of 5"
exit

-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Mark A. Hargrove                                             U.S. TeleCenters
Voice: 408-496-1800                                          Santa Clara, CA
uucp : {dual, hoptoad, hplabs, portal, ptsfa}!well!ustel