
# 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:08 PST 1988
# Contents:  tcap.c termio.c tipc.c vmsvt.c vt52.c window.c word.c
 
echo x - tcap.c
sed 's/^@//' > "tcap.c" <<'@//E*O*F tcap.c//'

/*	tcap:	Unix V5, V7 and BS4.2 Termcap video driver
		for MicroEMACS
*/

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

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

#if TERMCAP

#define MARGIN	8
#define SCRSIZ	64
#define NPAUSE	10			/* # times thru update to pause */
#define BEL	0x07
#define ESC	0x1B

extern int	ttopen();
extern int	ttgetc();
extern int	ttputc();
extern int	tgetnum();
extern int	ttflush();
extern int	ttclose();
extern int	tcapkopen();
extern int	tcapkclose();
extern int	tcapmove();
extern int	tcapeeol();
extern int	tcapeeop();
extern int	tcapbeep();
extern int	tcaprev();
extern int	tcapcres();
extern int	tcapopen();
extern int	tput();
extern char	*tgoto();
#if	COLOR
extern	int	tcapfcol();
extern	int	tcapbcol();
#endif

#define TCAPSLEN 315
char tcapbuf[TCAPSLEN];
char *UP, PC, *CM, *CE, *CL, *SO, *SE;

TERM term = {
	NULL,	/* these four values are set dynamically at open time */
	NULL,
	NULL,
	NULL,
	MARGIN,
	SCRSIZ,
	NPAUSE,
	tcapopen,
	ttclose,
	tcapkopen,
	tcapkclose,
	ttgetc,
	ttputc,
	ttflush,
	tcapmove,
	tcapeeol,
	tcapeeop,
	tcapbeep,
	tcaprev,
	tcapcres
#if	COLOR
	, tcapfcol,
	tcapbcol
#endif
};

tcapopen()

{
	char *getenv();
	char *t, *p, *tgetstr();
	char tcbuf[1024];
	char *tv_stype;
	char err_str[72];

	if ((tv_stype = getenv("TERM")) == NULL)
	{
		puts("Environment variable TERM not defined!");
		exit(1);
	}

	if ((tgetent(tcbuf, tv_stype)) != 1)
	{
		sprintf(err_str, "Unknown terminal type %s!", tv_stype);
		puts(err_str);
		exit(1);
	}

 
       if ((term.t_nrow=(short)tgetnum("li")-1) == -1){
	       puts("termcap entry incomplete (lines)");
	       exit(1);
       }
	term.t_mrow =  term.t_nrow;

       if ((term.t_ncol=(short)tgetnum("co")) == -1){
	       puts("Termcap entry incomplete (columns)");
	       exit(1);
       }
	term.t_mcol = term.t_ncol;

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

	CL = tgetstr("cl", &p);
	CM = tgetstr("cm", &p);
	CE = tgetstr("ce", &p);
	UP = tgetstr("up", &p);
	SE = tgetstr("se", &p);
	SO = tgetstr("so", &p);
	if (SO != NULL)
		revexist = TRUE;

	if(CL == NULL || CM == NULL || UP == NULL)
	{
		puts("Incomplete termcap entry\n");
		exit(1);
	}

	if (CE == NULL) 	/* will we be able to use clear to EOL? */
		eolexist = FALSE;
		
	if (p >= &tcapbuf[TCAPSLEN])
	{
		puts("Terminal description too big!\n");
		exit(1);
	}
	ttopen();
}

tcapkopen()

{
	strcpy(sres, "NORMAL");
}

tcapkclose()

{
}

tcapmove(row, col)
register int row, col;
{
	putpad(tgoto(CM, col, row));
}

tcapeeol()
{
	putpad(CE);
}

tcapeeop()
{
	putpad(CL);
}

tcaprev(state)		/* change reverse video status */

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

{
	static int revstate = FALSE;
	if (state) {
		if (SO != NULL)
			putpad(SO);
	} else
		if (SE != NULL)
			putpad(SE);
}

tcapcres()	/* change screen resolution */

{
	return(TRUE);
}

#if	COLOR
tcapfcol()	/* no colors here, ignore this */
{
}

tcapbcol()	/* no colors here, ignore this */
{
}
#endif

tcapbeep()
{
	ttputc(BEL);
}

putpad(str)
char	*str;
{
	tputs(str, 1, ttputc);
}

putnpad(str, n)
char	*str;
{
	tputs(str, n, ttputc);
}


#if	FLABEL
fnclabel(f, n)		/* label a function key */

int f,n;	/* default flag, numeric argument [unused] */

{
        /* on machines with no function keys...don't bother */
	return(TRUE);
}
#endif
#else

hello()
{
}

#endif TERMCAP
@//E*O*F tcap.c//
chmod u=rw,g=r,o=r tcap.c
 
echo x - termio.c
sed 's/^@//' > "termio.c" <<'@//E*O*F termio.c//'
/*
 * The functions in this file negotiate with the operating system for char-
 * acters, and write characters in a barely buffered fashion on the display.
 * All operating systems.
 */
#include	<stdio.h>
#include	"estruc.h"
#include	"edef.h"
 
 
#if	CRAY
#undef	USG		/* Cray version not similar to USG here */
#undef	islower
#include <ctype.h>
 
#if	TCPIP		/* direct tcp/ip network stuff */
#include "tcplib.h"
#define CRAY_OUTBUF	512
#define CRAY_INBUF	512
Event	*ep ;
int	xid ;			/* io descriptor */
#else
 
#define CRAY_OUTBUF	400
#define CRAY_INBUF	256
#endif
#endif
 
 
#if	MEGAMAX & ST520
overlay "termio"
#endif
 
#if	AMIGA
#define NEW 1006
#define AMG_MAXBUF	1024L
static long terminal;
static char	scrn_tmp[AMG_MAXBUF+1];
static long	scrn_tmp_p = 0;
#endif
 
#if ST520
#include <osbind.h>
	int STscancode = 0;	
#endif
 
#if	VMS
#include	<stsdef.h>
#include	<ssdef.h>
#include	<descrip.h>
#include	<iodef.h>
#include	<ttdef.h>
#include	<tt2def.h>
 
#define NIBUF	128			/* Input buffer size		*/
#define NOBUF	1024			/* MM says bug buffers win!	*/
#define EFN	0			/* Event flag			*/
 
char	obuf[NOBUF];			/* Output buffer		*/
int	nobuf;			/* # of bytes in above	  */
char	ibuf[NIBUF];			/* Input buffer 	 */
int	nibuf;			/* # of bytes in above	*/
int	ibufi;			/* Read index			*/
int	oldmode[3];			/* Old TTY mode bits		*/
int	newmode[3];			/* New TTY mode bits		*/
short	iochan; 		 /* TTY I/O channel		*/
#endif
 
#if	CPM
#include	<bdos.h>
#endif
 
#if	MSDOS & (LATTICE | MSC | AZTEC | MWC86)
union REGS rg;		/* cpu register for use of DOS calls */
int nxtchar = -1;	/* character held from type ahead    */
#endif
 
#if RAINBOW
#include "rainbow.h"
#endif
 
#if	USG			/* System V */
#include	<signal.h>
#include	<termio.h>
struct	termio	otermio;	/* original terminal characteristics */
struct	termio	ntermio;	/* charactoristics to use inside */
#endif
 
#if V7 | BSD
#undef	CTRL
#include	<sgtty.h>	 /* for stty/gtty functions */
#include	<signal.h>
struct	sgttyb	ostate; 	 /* saved tty state */
struct	sgttyb	nstate; 	 /* values for editor mode */
struct tchars	otchars;	/* Saved terminal special character set */
struct tchars	ntchars = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
				/* A lot of nothing */
#if BSD
#include <sys/ioctl.h>		/* to get at the typeahead */
extern	int rtfrmshell();	/* return from suspended shell */
#define TBUFSIZ 128
char tobuf[TBUFSIZ];		/* terminal output buffer */
#endif
#endif
 
 
/*
 * This function is called once to set up the terminal device streams.
 * On VMS, it translates TT until it finds the terminal, then assigns
 * a channel to it and sets it raw. On CPM it is a no-op.
 */
ttopen()
{
#if	AMIGA
	terminal = Open("RAW:1/1/639/199/MicroEMACS 3.7/Amiga", NEW);
#endif
#if	VMS
	struct	dsc$descriptor	idsc;
	struct	dsc$descriptor	odsc;
	char	oname[40];
	int	iosb[2];
	int	status;
 
	odsc.dsc$a_pointer = "TT";
	odsc.dsc$w_length  = strlen(odsc.dsc$a_pointer);
	odsc.dsc$b_dtype	= DSC$K_DTYPE_T;
	odsc.dsc$b_class	= DSC$K_CLASS_S;
	idsc.dsc$b_dtype	= DSC$K_DTYPE_T;
	idsc.dsc$b_class	= DSC$K_CLASS_S;
	do {
		idsc.dsc$a_pointer = odsc.dsc$a_pointer;
		idsc.dsc$w_length  = odsc.dsc$w_length;
		odsc.dsc$a_pointer = &oname[0];
		odsc.dsc$w_length  = sizeof(oname);
		status = LIB$SYS_TRNLOG(&idsc, &odsc.dsc$w_length, &odsc);
		if (status!=SS$_NORMAL && status!=SS$_NOTRAN)
			exit(status);
		if (oname[0] == 0x1B) {
			odsc.dsc$a_pointer += 4;
			odsc.dsc$w_length  -= 4;
		}
	} while (status == SS$_NORMAL);
	status = SYS$ASSIGN(&odsc, &iochan, 0, 0);
	if (status != SS$_NORMAL)
		exit(status);
	status = SYS$QIOW(EFN, iochan, IO$_SENSEMODE, iosb, 0, 0,
			  oldmode, sizeof(oldmode), 0, 0, 0, 0);
	if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
		exit(status);
	newmode[0] = oldmode[0];
	newmode[1] = oldmode[1] | TT$M_NOECHO;
	newmode[1] &= ~(TT$M_TTSYNC|TT$M_HOSTSYNC);
	newmode[2] = oldmode[2] | TT2$M_PASTHRU;
	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)
		exit(status);
	term.t_nrow = (newmode[1]>>24) - 1;
	term.t_ncol = newmode[0]>>16;
 
#endif
#if	CPM
#endif
 
#if	MSDOS & (HP150 == 0) & (LATTICE | MSC)
	/* kill the ctrl-break interupt */
	rg.h.ah = 0x33; 	/* control-break check dos call */
	rg.h.al = 1;		/* set the current state */
	rg.h.dl = 0;		/* set it OFF */
	intdos(&rg, &rg);	/* go for it! */
#endif
 
#if	USG
	ioctl(0, TCGETA, &otermio);	/* save old settings */
	ntermio.c_iflag = 0;		/* setup new settings */
	ntermio.c_oflag = 0;
	ntermio.c_cflag = otermio.c_cflag;
	ntermio.c_lflag = 0;
	ntermio.c_line = otermio.c_line;
	ntermio.c_cc[VMIN] = 1;
	ntermio.c_cc[VTIME] = 0;
	ioctl(0, TCSETA, &ntermio);	/* and activate them */
#endif
 
#if	V7 | BSD
	gtty(0, &ostate);			/* save old state */
	gtty(0, &nstate);			/* get base of new state */
	nstate.sg_flags |= RAW;
	nstate.sg_flags &= ~(ECHO|CRMOD);	/* no echo for now... */
	stty(0, &nstate);			/* set mode */
	ioctl(0, TIOCGETC, &otchars);		/* Save old characters */
	ioctl(0, TIOCSETC, &ntchars);		/* Place new character into K */
#if	BSD
	/* provide a smaller terminal output buffer so that
	   the type ahead detection works better (more often) */
	setbuffer(stdout, &tobuf[0], TBUFSIZ);
	signal(SIGTSTP,SIG_DFL);	/* set signals so that we can */
	signal(SIGCONT,rtfrmshell);	/* suspend & restart emacs */
#endif
 
#endif
 
#if	CRAY
#if	TCPIP
	if ( TcpStart() ) exit(0) ;
	TcpOpen(0, inet_address, inet_port, &ep) ;
	if ( ep->evStat ) {
		printf("TCP open failed: %s\n", TcpErrorName(ep->evStat) ) ;
		exit(0) ;
	}
	xid = ep->evXid ;
	FreeTcpEvent(ep) ;
#else
	ttputc('\005') ;	/* signal workstation that we need help */
	ttflush() ;
#endif
#endif
 
	/* on all screens we are not sure of the initial position of cursor */
	ttrow = 999;
	ttcol = 999;
}
 
/*
 * This function gets called just before we go back home to the command
 * interpreter. On VMS it puts the terminal back in a reasonable state.
 * Another no-operation on CPM.
 */
ttclose()
{
#if	AMIGA
	amg_flush();
	Close(terminal);
#endif
#if	VMS
	int	status;
	int	iosb[1];
 
	ttflush();
	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)
		exit(status);
	status = SYS$DASSGN(iochan);
	if (status != SS$_NORMAL)
		exit(status);
#endif
#if	CPM
#endif
#if	MSDOS & (HP150 == 0) & (LATTICE | MSC )
	/* restore the ctrl-break interupt */
	rg.h.ah = 0x33; 	/* control-break check dos call */
	rg.h.al = 1;		/* set the current state */
	rg.h.dl = 1;		/* set it ON */
	intdos(&rg, &rg);	/* go for it! */
#endif
 
#if	USG
	ioctl(0, TCSETA, &otermio);	/* restore terminal settings */
#endif
 
#if	V7 | BSD
	stty(0, &ostate);
	ioctl(0, TIOCSETC, &otchars);	/* Place old character into K */
#endif
 
#if	CRAY		/* signal workstation we are quiting */
	ttputc('\004') ;	/* ^D */
	ttflush() ;
#endif	
}
 
/*
 * Write a character to the display. On VMS, terminal output is buffered, and
 * we just put the characters in the big array, after checking for overflow.
 * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
 * MS-DOS (use the very very raw console output routine).
 */
ttputc(c)
#if	AMIGA | ST520
	char c;
#endif
{
#if	AMIGA
	scrn_tmp[scrn_tmp_p++] = c;
	if(scrn_tmp_p>=AMG_MAXBUF)
		amg_flush();
#endif
#if	ST520
	Bconout(2,c);
#endif
#if	VMS
	if (nobuf >= NOBUF)
		ttflush();
	obuf[nobuf++] = c;
#endif
 
#if	CPM
	bios(BCONOUT, c, 0);
#endif
 
#if	MSDOS & MWC86
	putcnb(c);
#endif
 
#if	MSDOS & (LATTICE | AZTEC | MSC) & ~IBMPC
	bdos(6, c, 0);
#endif
 
#if RAINBOW
	Put_Char(c);			/* fast video */
#endif
 
 
#if	V7 | USG | BSD
	fputc(c, stdout);
#endif
 
 
/* send \ as \\, buffer a bit (ctss setbuf is a no-op).  Brain-
 * damaged HCC also screws up ESC, its patched here as well.
 */
#if	CRAY	
int	i ;
static int	index=0 ;
static char	buf[CRAY_OUTBUF] ;
 
	if ( index >= CRAY_OUTBUF-2 && c != '\n' ) {
		buf[index++] = c ;
		c = '\n' ;		/* force flush */
	}
	else if ( c == '\\' ) {
		buf[index++] = c ;
	}
	
	buf[index++] = c ;
	if ( c=='\n' ) {	/* flush */
#if	TCPIP
		TcpSend(xid, buf, index, 0, 0) ;
		ep = GetTcpEvent(0, xid, 1) ;
		if ( ep->evStat ) puts(TcpErrorName(ep->evStat)) ;
		FreeTcpEvent(ep) ;
#else
		for (i=0; i<index; i++) putchar(buf[i]) ;
#endif
		index = 0 ;
	}
#endif
 
}
 
 
#if	CRAY	/* send a string, without \ translation, use with care */
sends(s)
char	*s ;
{
#if	TCPIP
	TcpSSend(xid, s, 0, 0) ;
	ep = GetTcpEvent(0, xid, 1) ;
	if ( ep->evStat ) {
		puts(TcpErrorName(ep->evStat)) ;
		exit() ;
	}
	FreeTcpEvent(ep) ;
	ttflush() ;
#else
	puts(s) ;
#endif
}
#endif
 
 
#if	AMIGA
amg_flush()
{
	if(scrn_tmp_p)
		Write(terminal,scrn_tmp,scrn_tmp_p);
	scrn_tmp_p = 0;
}
#endif
 
/*
 * Flush terminal buffer. Does real work where the terminal output is buffered
 * up. A no-operation on systems where byte at a time terminal I/O is done.
 */
ttflush()
{
#if	AMIGA
	amg_flush();
#endif
#if	VMS
	int	status;
	int	iosb[2];
 
	status = SS$_NORMAL;
	if (nobuf != 0) {
		status = SYS$QIOW(EFN, iochan, IO$_WRITELBLK|IO$M_NOFORMAT,
			 iosb, 0, 0, obuf, nobuf, 0, 0, 0, 0);
		if (status == SS$_NORMAL)
			status = iosb[0] & 0xFFFF;
		nobuf = 0;
	}
	return (status);
#endif
 
#if	CPM
#endif
 
#if	MSDOS
#endif
 
#if	V7 | USG | BSD
	fflush(stdout);
#endif
 
#if	CRAY
	ttputc('\n') ;
#endif
}
 
/*
 * Read a character from the terminal, performing no editing and doing no echo
 * at all. More complex in VMS that almost anyplace else, which figures. Very
 * simple on CPM, because the system can do exactly what you want.
 */
ttgetc()
{
#if	AMIGA
	char ch;
	amg_flush();
	Read(terminal, &ch, 1L);
	return(255 & (int)ch);
#endif
#if	ST520
	long ch;
/*
 * blink the cursor only if nothing is happening, this keeps the
 * cursor on steadily during movement making it easier to track
 */
	STcurblink(TRUE);  /* the cursor blinks while we wait */
	ch = Bconin(2);
	STcurblink(FALSE); /* the cursor is steady while we work */
	STscancode = (ch >> 16) & 0xff;
	return(255 & (int)ch);
#endif
#if	VMS
	int	status;
	int	iosb[2];
	int	term[2];
 
	while (ibufi >= nibuf) {
		ibufi = 0;
		term[0] = 0;
		term[1] = 0;
		status = SYS$QIOW(EFN, iochan, IO$_READLBLK|IO$M_TIMED,
			 iosb, 0, 0, ibuf, NIBUF, 0, term, 0, 0);
		if (status != SS$_NORMAL)
			exit(status);
		status = iosb[0] & 0xFFFF;
		if (status!=SS$_NORMAL && status!=SS$_TIMEOUT)
			exit(status);
		nibuf = (iosb[0]>>16) + (iosb[1]>>16);
		if (nibuf == 0) {
			status = SYS$QIOW(EFN, iochan, IO$_READLBLK,
				 iosb, 0, 0, ibuf, 1, 0, term, 0, 0);
			if (status != SS$_NORMAL
			|| (status = (iosb[0]&0xFFFF)) != SS$_NORMAL)
				exit(status);
			nibuf = (iosb[0]>>16) + (iosb[1]>>16);
		}
	}
	return (ibuf[ibufi++] & 0xFF);	  /* Allow multinational  */
#endif
 
#if	CPM
	return (biosb(BCONIN, 0, 0));
#endif
 
#if RAINBOW
	int Ch;
 
	while ((Ch = Read_Keyboard()) < 0);
 
	if ((Ch & Function_Key) == 0)
		if (!((Ch & 0xFF) == 015 || (Ch & 0xFF) == 0177))
			Ch &= 0xFF;
 
	return Ch;
#endif
 
#if	MSDOS & MWC86
	return (getcnb());
#endif
 
#if	MSDOS & (LATTICE | MSC | AZTEC)
	int c;		/* character read */
 
	/* if a char already is ready, return it */
	if (nxtchar >= 0) {
		c = nxtchar;
		nxtchar = -1;
		return(c);
	}
 
	/* call the dos to get a char */
	rg.h.ah = 7;		/* dos Direct Console Input call */
	intdos(&rg, &rg);
	c = rg.h.al;		/* grab the char */
	return(c & 255);
#endif
 
#if	V7 | USG | BSD
	return(127 & fgetc(stdin));
#endif
 
 
#if	CRAY
/* Special "echo avoidance" input routine.  Control characters are
 * received as three octal digits/char (i.e.  ^A is \001).  The flag
 * "inhibit_update" is held high until the last character in the buffer
 * has been acted upon, to avoid unnecessary screen updates.  Ordinary
 * control characters will also be accepted (the TCPIP version has little
 * need for the \xxx syntax, but is used to extend the character set in
 * certain cases).
 */
static char raw_buf[CRAY_INBUF*4] ;	/* just in case */
static int  int_buf[CRAY_INBUF] ;
static int buf_count = 0, buf_index = 0, raw_count = 0 ;
int	i, j ;
 
	if ( buf_index >= buf_count ) {
#if	TCPIP
		TcpRecv(xid, CRAY_INBUF, 0, &ep) ;
		if ( ep->evStat ) {
			puts(TcpErrorName(ep->evStat)) ;
			exit() ;
		}
		raw_count = ep->evDataCount ;
		strncpy(raw_buf, ep->evData, raw_count) ;
		FreeTcpEvent(ep) ;
#else
		raw_count = strlen( fgets(raw_buf,CRAY_INBUF*4,stdin) ) - 1 ;
#endif
 
		/* convert from \ddd format to char */
		for ( j=0, i=0; i<raw_count && j<CRAY_INBUF; i++ ) {
		    if ( raw_buf[i] == '\\' ) {
		    	i++ ;
		        if ( 1==sscanf(&raw_buf[i],"%3o",&int_buf[j]) ) {
		            j++ ;
		            i += 2 ;
		            continue ;
		        }
		    }
		    int_buf[j++] = raw_buf[i] ;
		}
		buf_index = 0 ;
		buf_count = j ;
	}
 
	if ( buf_count == 0 ) return(0) ;	/* shouldn't happen */
	buf_index++ ;
	inhibit_update = ! ( buf_index >= buf_count ) ;
 
/* force update before 1st special character if not on message line */
	if (	buf_index > 1 &&
		( int_buf[buf_index-1]<32 || int_buf[buf_index-1]==127 ) &&
		isprint(int_buf[buf_index-2]) &&
		ttrow != term.t_nrow
	)
		update(TRUE) ;

/* return the next character */
	return( int_buf[buf_index-1] ) ;
#endif
}
 
#if	TYPEAH
/* typahead:	Check to see if any characters are already in the
		keyboard buffer
*/
typahead()
 
{
#if	MSDOS & (LATTICE | MSC | AZTEC | MWC86)
	int c;		/* character read */
	int flags;	/* cpu flags from dos call */
 
#if	MSC
	if (kbhit() != 0)
		return(TRUE);
	else
		return(FALSE);
#endif
 
	if (nxtchar >= 0)
		return(TRUE);
 
	rg.h.ah = 6;	/* Direct Console I/O call */
	rg.h.dl = 255;	/*	   does console input */
#if	LATTICE | AZTEC | MSC
	flags = intdos(&rg, &rg);
#else
	intcall(&rg, &rg, 0x21);
	flags = rg.x.flags;
#endif
	c = rg.h.al;	/* grab the character */
 
	/* no character pending */
	if ((flags & 64) != 0)
		return(FALSE);
 
	/* save the character and return true */
	nxtchar = c;
	return(TRUE);
#endif
 
#if	BSD
	int x;	/* holds # of pending chars */
 
	return((ioctl(0,FIONREAD,&x) < 0) ? 0 : x);
#endif
 
#if	CRAY
	return(inhibit_update) ;
#else
	return(FALSE);
#endif
}
#endif
 
@//E*O*F termio.c//
chmod u=rw,g=r,o=r termio.c
 
echo x - tipc.c
sed 's/^@//' > "tipc.c" <<'@//E*O*F tipc.c//'

/*
 * The routines in this file provide support for the TI-PC and other
 * compatible terminals. It goes directly to the graphics RAM to do
 * screen output. It compiles into nothing if not a TI-PC driver
 */

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

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

#if	TIPC

#define NROW	25			/* 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	200			/* # times thru update to pause */
#define BEL	0x07			/* BEL character.		*/
#define ESC	0x1B			/* ESC character.		*/
#define SPACE	32			/* space character		*/
#define SCADD	0xDE000L		/* address of screen RAM	*/

#define CHAR_ENABLE	0x08		/* TI attribute to show char	*/
#define TI_REVERSE	0x10		/* TI attribute to reverse char */
#define BLACK	0+CHAR_ENABLE		/* TI attribute for Black	*/
#define BLUE	1+CHAR_ENABLE		/* TI attribute for Blue	*/
#define RED	2+CHAR_ENABLE		/* TI attribute for Red 	*/
#define MAGENTA 3+CHAR_ENABLE		/* TI attribute for Magenta	*/
#define GREEN	4+CHAR_ENABLE		/* TI attribute for Green	*/
#define CYAN	5+CHAR_ENABLE		/* TI attribute for Cyan	*/
#define YELLOW	6+CHAR_ENABLE		/* TI attribute for Yellow	*/
#define WHITE	7+CHAR_ENABLE		/* TI attribute for White	*/


extern	int	ttopen();		/* Forward references.		*/
extern	int	ttgetc();
extern	int	ttputc();
extern	int	ttflush();
extern	int	ttclose();
extern	int	timove();
extern	int	tieeol();
extern	int	tieeop();
extern	int	tibeep();
extern	int	tiopen();
extern	int	tirev();
extern	int	ticres();
extern	int	ticlose();
extern	int	tiputc();

#if	COLOR
extern	int	tifcol();
extern	int	tibcol();

int	cfcolor = -1;		/* current forground color */
int	cbcolor = -1;		/* current background color */
int	ctrans[] =		/* ansi to ti color translation table */
	{BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE};
#endif

/*
 * Standard terminal interface dispatch table. Most of the fields point into
 * "termio" code.
 */
TERM	term	= {
	NROW-1,
	NROW-1,
	NCOL,
	NCOL,
	MARGIN,
	SCRSIZ,
	NPAUSE,
	tiopen,
	ticlose,
	ttgetc,
	tiputc,
	ttflush,
	timove,
	tieeol,
	tieeop,
	tibeep,
	tirev,
	ticres
#if	COLOR
	, tifcol,
	tibcol
#endif
};

extern union REGS rg;

#if	COLOR
setatt( attr )
int attr;
{
	rg.h.ah = 0x16; 	/* set the forground character attribute */
	rg.h.bl = attr;
	int86( 0x49, &rg, &rg );
}

tifcol(color)		/* set the current output color */

int color;	/* color to set */

{
	cfcolor = ctrans[color];
	setatt ( cfcolor );
}

tibcol(color)		/* set the current background color */

int color;	/* color to set */

{
	cbcolor = ctrans[color];
}
#endif

timove(row, col)
{
	rg.h.ah = 2;		/* set cursor position function code */
	rg.h.dh = col;
	rg.h.dl = row;
	int86(0x49, &rg, &rg);
}

tieeol()	/* erase to the end of the line */

{
	int ccol;	/* current column cursor lives */
	int crow;	/*	   row	*/

	/* find the current cursor position */
	rg.h.ah = 3;		/* read cursor position function code */
	int86(0x49, &rg, &rg);
	ccol = rg.h.dh; 	/* record current column */
	crow = rg.h.dl; 	/* and row */

	rg.h.ah = 0x09; 	/* Write character at cursor position */
	rg.h.al = ' ';		/* Space */
	rg.h.bl = cfcolor;
	rg.x.cx = NCOL-ccol;	/* Number of characters to write */
	int86(0x49, &rg, &rg);

}

tiputc(ch)	/* put a character at the current position in the
		   current colors */

int ch;

{
	rg.h.ah = 0x0E; 	/* write char to screen with current attrs */
	rg.h.al = ch;
	int86(0x49, &rg, &rg);
}

tieeop()			/* Actually a clear screen */
{

	rg.h.ah = 0x13; 	/* Clear Text Screen and Home Cursor */
	int86(0x49, &rg, &rg);
}

tirev(state)		/* change reverse video state */

int state;	/* TRUE = reverse, FALSE = normal */

{
	setatt( state ? cbcolor : cfcolor  );
}

ticres()	/* change screen resolution */

{
	return(TRUE);
}

tibeep()
{
	bdos(6, BEL, 0);
}

tiopen()
{
	strcpy(sres, "NORMAL");
	revexist = TRUE;
	ttopen();
}

ticlose()

{
#if	COLOR
	tifcol(7);
	tibcol(0);
#endif
	ttclose();
}
#else
tihello()
{
}
#endif

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

/*
 *  VMS terminal handling routines
 *
 *  Known types are:
 *    VT52, VT100, and UNKNOWN (which is defined to be an ADM3a)
 *    written by Curtis Smith
 */

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

#if	VMSVT

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

#include <ssdef.h>		/* Status code definitions		*/
#include <descrip.h>		/* Descriptor structures		*/
#include <iodef.h>		/* IO commands				*/
#include <ttdef.h>		/* tty commands 			*/

extern	int	ttopen();		/* Forward references.		*/
extern	int	ttgetc();
extern	int	ttputc();
extern	int	ttflush();
extern	int	ttclose();
extern	int	vmsopen();
extern	int	vmskopen();
extern	int	vmskclose();
extern	int	vmseeol();
extern	int	vmseeop();
extern	int	vmsbeep();
extern	int	vmsmove();
extern	int	vmsrev();
extern	int	vmscres();
extern	int	eolexist;
#if	COLOR
extern	int	vmsfcol();
extern	int	vmsbcol();
#endif

#define NROWS	24			/* # of screen rolls		*/
#define NCOLS	80			/* # of screen columns		*/
#define MARGIN	8			/* size of minimim margin and	*/
#define SCRSIZ	64			/* scroll size for extended lines */
#define NPAUSE	100			/* # times thru update to pause */

/*
 * Dispatch table. All the
 * hard fields just point into the
 * terminal I/O code.
 */
TERM	term	= {
	NROWS - 1,
	NROWS - 1,
	NCOLS,
	NCOLS,
	MARGIN,
	SCRSIZ,
	NPAUSE,
	&vmsopen,
	&ttclose,
	&vmskopen,
	&vmskclose,
	&ttgetc,
	&ttputc,
	&ttflush,
	&vmsmove,
	&vmseeol,
	&vmseeop,
	&vmsbeep,
	&vmsrev,
	&vmscres
#if	COLOR
	, &vmsfcol,
	&vmsbcol
#endif
};

char * termeop; 		/* Erase to end of page string		*/
int eoppad;			/* Number of pad characters after eop	*/
char * termeol; 		/* Erase to end of line string		*/
int eolpad;			/* Number of pad characters after eol	*/
char termtype;			/* Terminal type identifier		*/


/*******
 *  ttputs - Send a string to ttputc
 *******/

ttputs(string)
char * string;
{
	while (*string != '\0')
		ttputc(*string++);
}


/*******
 *  vmspad - Pad the output after an escape sequence
 *******/

vmspad(count)
int count;
{
	while (count-- > 0)
		ttputc('\0');
}


/*******
 *  vmsmove - Move the cursor
 *******/

vmsmove(row, col)
{
	switch (termtype) {
		case TT$_UNKNOWN:
			ttputc('\033');
			ttputc('=');
			ttputc(row+' ');
			ttputc(col+' ');
			break;
		case TT$_VT52:
			ttputc('\033');
			ttputc('Y');
			ttputc(row+' ');
			ttputc(col+' ');
			break;
                case TT$_VT100:         /* I'm assuming that all these	*/
		case TT$_VT101: 	/* are a super set of the VT100 */
                case TT$_VT102:         /* If I'm wrong, just remove	*/
                case TT$_VT105:         /* those entries that aren't.	*/
		case TT$_VT125:
		case TT$_VT131:
		case TT$_VT132:
		case TT$_VT200_SERIES:
			{
				char buffer[24];

				sprintf(buffer, "\033[%d;%dH", row+1, col+1);
				ttputs(buffer);
				vmspad(50);
			}
	}
}

/*******
 *  vmsrev - set the reverse video status
 *******/

vmsrev(status)

int status;	/* TRUE = reverse video, FALSE = normal video */
{
	switch (termtype) {
		case TT$_UNKNOWN:
			break;
		case TT$_VT52:
			break;
		case TT$_VT100:
			if (status) {
				ttputc('\033');
				ttputc('[');
				ttputc('7');
				ttputc('m');
			} else {
				ttputc('\033');
				ttputc('[');
				ttputc('m');
			}
			break;
	}
}

/*******
 *  vmscres - Change screen resolution (which it doesn't)
 *******/

vmscres()

{
	return(TRUE);
}

#if	COLOR
/*******
 *  vmsfcol - Set the forground color (not implimented)
 *******/
 
vmsfcol()
{
}

/*******
 *  vmsbcol - Set the background color (not implimented)
 *******/
 
vmsbcol()
{
}
#endif

/*******
 *  vmseeol - Erase to end of line
 *******/

vmseeol()
{
	ttputs(termeol);
	vmspad(eolpad);
}


/*******
 *  vmseeop - Erase to end of page (clear screen)
 *******/

vmseeop()
{
	ttputs(termeop);
	vmspad(eoppad);
}


/*******
 *  vmsbeep - Ring the bell
 *******/

vmsbeep()
{
	ttputc('\007');
}


/*******
 *  vmsopen - Get terminal type and open terminal
 *******/

vmsopen()
{
	termtype = vmsgtty();
	switch (termtype) {
		case TT$_UNKNOWN:	/* Assume ADM3a */
			eolexist = FALSE;
			termeop = "\032";
			eoppad = 0;
			break;
		case TT$_VT52:
			termeol = "\033K";
			eolpad = 0;
			termeop = "\033H\033J";
			eoppad = 0;
			break;
		case TT$_VT100:
			revexist = TRUE;
			termeol = "\033[K";
			eolpad = 3;
			termeop = "\033[;H\033[2J";
			eoppad = 50;
			break;
		default:
			puts("Terminal type not supported");
			exit (SS$_NORMAL);
	}
	strcpy(sres, "NORMAL");
	ttopen();
}


struct iosb {			/* I/O status block			*/
	short	i_cond; 	/* Condition value			*/
	short	i_xfer; 	/* Transfer count			*/
	long	i_info; 	/* Device information			*/
};

struct termchar {		/* Terminal characteristics		*/
	char	t_class;	/* Terminal class			*/
	char	t_type; 	/* Terminal type			*/
	short	t_width;	/* Terminal width in characters 	*/
        long    t_mandl;        /* Terminal's mode and length		*/
	long	t_extend;	/* Extended terminal characteristics	*/
};

/*******
 *  vmsgtty - Get terminal type from system control block
 *******/

vmsgtty()
{
	short fd;
	int status;
	struct iosb iostatus;
	struct termchar tc;
	$DESCRIPTOR(devnam, "SYS$INPUT");

	status = sys$assign(&devnam, &fd, 0, 0);
	if (status != SS$_NORMAL)
		exit (status);

	status = sys$qiow(		/* Queue and wait		*/
		0,			/* Wait on event flag zero	*/
		fd,			/* Channel to input terminal	*/
		IO$_SENSEMODE,		/* Get current characteristic	*/
		&iostatus,		/* Status after operation	*/
		0, 0,			/* No AST service		*/
		&tc,			/* Terminal characteristics buf */
		sizeof(tc),		/* Size of the buffer		*/
		0, 0, 0, 0);		/* P3-P6 unused 		*/

					/* De-assign the input device	*/
	if (sys$dassgn(fd) != SS$_NORMAL)
		exit(status);

	if (status != SS$_NORMAL)	/* Jump out if bad status	*/
		exit(status);
	if (iostatus.i_cond != SS$_NORMAL)
		exit(iostatus.i_cond);

	return tc.t_type;		/* Return terminal type 	*/
}

vmskopen()

{
}

vmskclose()

{
}

#if	FLABEL
fnclabel(f, n)		/* label a function key */

int f,n;	/* default flag, numeric argument [unused] */

{
        /* on machines with no function keys...don't bother */
	return(TRUE);
}
#endif
#else

hellovms()

{
}

#endif	VMSVT
@//E*O*F vmsvt.c//
chmod u=rw,g=r,o=r vmsvt.c
 
echo x - vt52.c
sed 's/^@//' > "vt52.c" <<'@//E*O*F vt52.c//'

/*
 * The routines in this file
 * provide support for VT52 style terminals
 * over a serial line. The serial I/O services are
 * provided by routines in "termio.c". It compiles
 * into nothing if not a VT52 style device. The
 * bell on the VT52 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	VT52

#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	100			/* # 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	vt52move();
extern	int	vt52eeol();
extern	int	vt52eeop();
extern	int	vt52beep();
extern	int	vt52open();
extern	int	vt52rev();
extern	int	vt52kopen();
extern	int	vt52kclose();

#if	COLOR
extern	int	vt52fcol();
extern	int	vt52bcol();
#endif

/*
 * Dispatch table. All the
 * hard fields just point into the
 * terminal I/O code.
 */
TERM	term	= {
	NROW-1,
	NROW-1,
	NCOL,
	NCOL,
	MARGIN,
	SCRSIZ,
	NPAUSE,
	&vt52open,
	&ttclose,
	&vt52kopen,
	&vt52kclose,
	&ttgetc,
	&ttputc,
	&ttflush,
	&vt52move,
	&vt52eeol,
	&vt52eeop,
	&vt52beep,
	&vt52rev
#if	COLOR
	, &vt52fcol,
	&vt52bcol
#endif
};

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

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

vt52eeop()
{
	ttputc(ESC);
	ttputc('J');
}

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

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

{
	/* can't do this here, so we won't */
}

#if	COLOR
vt52fcol()	/* set the forground color [NOT IMPLIMENTED] */
{
}

vt52bcol()	/* set the background color [NOT IMPLIMENTED] */
{
}
#endif

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

vt52open()
{
#if	V7 | BSD
	register char *cp;
	char *getenv();

	if ((cp = getenv("TERM")) == NULL) {
		puts("Shell variable TERM not defined!");
		exit(1);
	}
	if (strcmp(cp, "vt52") != 0 && strcmp(cp, "z19") != 0) {
		puts("Terminal type not 'vt52'or 'z19' !");
		exit(1);
	}
#endif
	ttopen();
}

vt52kopen()

{
}

vt52kclose()

{
}


#if	FLABEL
fnclabel(f, n)		/* label a function key */

int f,n;	/* default flag, numeric argument [unused] */

{
        /* on machines with no function keys...don't bother */
	return(TRUE);
}
#endif
#else

vt52hello()

{
}

#endif
@//E*O*F vt52.c//
chmod u=rw,g=r,o=r vt52.c
 
echo x - window.c
sed 's/^@//' > "window.c" <<'@//E*O*F window.c//'
/*
 * Window management. Some of the functions are internal, and some are
 * attached to keys that the user actually types.
 */

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

#if	MEGAMAX & ST520
overlay "window"
#endif

/*
 * 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). With no argument it defaults to 0. Bound to M-!.
 */
reposition(f, n)
    {
    if (f == FALSE)	/* default to 0 to center screen */
	n = 0;
    curwp->w_force = n;
    curwp->w_flag |= WFFORCE;
    return (TRUE);
    }

/*
 * Refresh the screen. With no argument, it just does the refresh. With an
 * argument it recenters "." in the current window. Bound to "C-L".
 */
refresh(f, n)
    {
    if (f == FALSE)
	sgarbf = TRUE;
    else
	{
	curwp->w_force = 0;		/* Center dot. */
	curwp->w_flag |= WFFORCE;
	}

#if	CRAY
	report_modes() ;
#endif
    return (TRUE);
    }

/*
 * The command make the next window (next => down the screen) the current
 * window. There are no real errors, although the command does nothing if
 * there is only 1 window on the screen. Bound to "C-X C-N".
 *
 * with an argument this command finds the <n>th window from the top
 *
 */
nextwind(f, n)

int f, n;	/* default flag and numeric argument */

{
	register WINDOW *wp;
	register int nwindows;		/* total number of windows */

	if (f) {

		/* first count the # of windows */
		wp = wheadp;
		nwindows = 1;
		while (wp->w_wndp != NULL) {
			nwindows++;
			wp = wp->w_wndp;
		}

		/* if the argument is negative, it is the nth window
		   from the bottom of the screen			*/
		if (n < 0)
			n = nwindows + n + 1;

		/* if an argument, give them that window from the top */
		if (n > 0 && n <= nwindows) {
			wp = wheadp;
			while (--n)
				wp = wp->w_wndp;
		} else {
			mlwrite("Window number out of range");
			return(FALSE);
		}
	} else
		if ((wp = curwp->w_wndp) == NULL)
			wp = wheadp;
	curwp = wp;
	curbp = wp->w_bufp;
	upmode();
	return (TRUE);
}

/*
 * This command makes the previous window (previous => up the screen) the
 * current window. There arn't any errors, although the command does not do a
 * lot if there is 1 window.
 */
prevwind(f, n)
{
	register WINDOW *wp1;
	register WINDOW *wp2;

	/* if we have an argument, we mean the nth window from the bottom */
	if (f)
		return(nextwind(f, -n));

	wp1 = wheadp;
	wp2 = curwp;

	if (wp1 == wp2)
		wp2 = NULL;

	while (wp1->w_wndp != wp2)
		wp1 = wp1->w_wndp;

	curwp = wp1;
	curbp = wp1->w_bufp;
	upmode();
	return (TRUE);
}

/*
 * This command moves the current window down by "arg" lines. Recompute the
 * top line in the window. The move up and move down code is almost completely
 * the same; most of the work has to do with reframing the window, and picking
 * a new dot. We share the code by having "move down" just be an interface to
 * "move up". Magic. Bound to "C-X C-N".
 */
mvdnwind(f, n)

int n;

{
	return (mvupwind(f, -n));
}

/*
 * Move the current window up by "arg" lines. Recompute the new top line of
 * the window. Look to see if "." is still on the screen. If it is, you win.
 * If it isn't, then move "." to center it in the new framing of the window
 * (this command does not really move "."; it moves the frame). Bound to
 * "C-X C-P".
 */
mvupwind(f, n)
    int n;
    {
    register LINE *lp;
    register int i;

    lp = curwp->w_linep;

    if (n < 0)
	{
	while (n++ && lp!=curbp->b_linep)
	    lp = lforw(lp);
	}
    else
	{
	while (n-- && lback(lp)!=curbp->b_linep)
	    lp = lback(lp);
	}

    curwp->w_linep = lp;
    curwp->w_flag |= WFHARD;		/* Mode line is OK. */

    for (i = 0; i < curwp->w_ntrows; ++i)
	{
	if (lp == curwp->w_dotp)
	    return (TRUE);
	if (lp == curbp->b_linep)
	    break;
	lp = lforw(lp);
	}

    lp = curwp->w_linep;
    i  = curwp->w_ntrows/2;

    while (i-- && lp != curbp->b_linep)
	lp = lforw(lp);

    curwp->w_dotp  = lp;
    curwp->w_doto  = 0;
    return (TRUE);
    }

/*
 * This command makes the current window the only window on the screen. Bound
 * to "C-X 1". Try to set the framing so that "." does not have to move on the
 * display. Some care has to be taken to keep the values of dot and mark in
 * the buffer structures right if the distruction of a window makes a buffer
 * become undisplayed.
 */
onlywind(f, n)
{
	register WINDOW *wp;
	register LINE	*lp;
	register int	i;

	while (wheadp != curwp) {
		wp = wheadp;
		wheadp = wp->w_wndp;
		if (--wp->w_bufp->b_nwnd == 0) {
			wp->w_bufp->b_dotp  = wp->w_dotp;
			wp->w_bufp->b_doto  = wp->w_doto;
			wp->w_bufp->b_markp = wp->w_markp;
			wp->w_bufp->b_marko = wp->w_marko;
		}
		free((char *) wp);
	}
	while (curwp->w_wndp != NULL) {
		wp = curwp->w_wndp;
		curwp->w_wndp = wp->w_wndp;
		if (--wp->w_bufp->b_nwnd == 0) {
			wp->w_bufp->b_dotp  = wp->w_dotp;
			wp->w_bufp->b_doto  = wp->w_doto;
			wp->w_bufp->b_markp = wp->w_markp;
			wp->w_bufp->b_marko = wp->w_marko;
		}
		free((char *) wp);
	}
	lp = curwp->w_linep;
	i  = curwp->w_toprow;
	while (i!=0 && lback(lp)!=curbp->b_linep) {
		--i;
		lp = lback(lp);
	}
	curwp->w_toprow = 0;
	curwp->w_ntrows = term.t_nrow-1;
	curwp->w_linep	= lp;
	curwp->w_flag  |= WFMODE|WFHARD;
	return (TRUE);
}

/*
 * Delete the current window, placing its space in the window above,
 * or, if it is the top window, the window below. Bound to C-X 0.
 */

delwind(f,n)

int f, n;	/* arguments are ignored for this command */

{
	register WINDOW *wp;	/* window to recieve deleted space */
	register WINDOW *lwp;	/* ptr window before curwp */
	register int target;	/* target line to search for */

        /* if there is only one window, don't delete it */
	if (wheadp->w_wndp == NULL) {
		mlwrite("Can not delete this window");
		return(FALSE);
	}

	/* find window before curwp in linked list */
	wp = wheadp;
	lwp = NULL;
	while (wp != NULL) {
		if (wp == curwp)
			break;
		lwp = wp;
		wp = wp->w_wndp;
	}

	/* find recieving window and give up our space */
	wp = wheadp;
	if (curwp->w_toprow == 0) {
		/* find the next window down */
		target = curwp->w_ntrows + 1;
		while (wp != NULL) {
			if (wp->w_toprow == target)
				break;
			wp = wp->w_wndp;
		}
		if (wp == NULL)
			return(FALSE);
		wp->w_toprow = 0;
		wp->w_ntrows += target;
	} else {
		/* find the next window up */
		target = curwp->w_toprow - 1;
		while (wp != NULL) {
			if ((wp->w_toprow + wp->w_ntrows) == target)
				break;
			wp = wp->w_wndp;
		}
		if (wp == NULL)
			return(FALSE);
		wp->w_ntrows += 1 + curwp->w_ntrows;
	}

	/* get rid of the current window */
	if (--curwp->w_bufp->b_nwnd == 0) {
		curwp->w_bufp->b_dotp = curwp->w_dotp;
		curwp->w_bufp->b_doto = curwp->w_doto;
		curwp->w_bufp->b_markp = curwp->w_markp;
		curwp->w_bufp->b_marko = curwp->w_marko;
	}
	if (lwp == NULL)
		wheadp = curwp->w_wndp;
	else
		lwp->w_wndp = curwp->w_wndp;
	free((char *)curwp);
	curwp = wp;
	wp->w_flag |= WFHARD;
	curbp = wp->w_bufp;
	upmode();
	return(TRUE);
}

/*

Split the current window.  A window smaller than 3 lines cannot be
split.	An argument of 1 forces the cursor into the upper window, an
argument of two forces the cursor to the lower window.	The only other
error that is possible is a "malloc" failure allocating the structure
for the new window.  Bound to "C-X 2". 

 */
splitwind(f, n)

int f, n;	/* default flag and numeric argument */

{
	register WINDOW *wp;
	register LINE	*lp;
	register int	ntru;
	register int	ntrl;
	register int	ntrd;
	register WINDOW *wp1;
	register WINDOW *wp2;
	char *malloc();

	if (curwp->w_ntrows < 3) {
		mlwrite("Cannot split a %d line window", curwp->w_ntrows);
		return (FALSE);
	}
	if ((wp = (WINDOW *) malloc(sizeof(WINDOW))) == NULL) {
		mlwrite("Cannot allocate WINDOW block");
		return (FALSE);
	}
	++curbp->b_nwnd;			/* Displayed twice.	*/
	wp->w_bufp  = curbp;
	wp->w_dotp  = curwp->w_dotp;
	wp->w_doto  = curwp->w_doto;
	wp->w_markp = curwp->w_markp;
	wp->w_marko = curwp->w_marko;
	wp->w_flag  = 0;
	wp->w_force = 0;
#if	COLOR
	/* set the colors of the new window */
	wp->w_fcolor = gfcolor;
	wp->w_bcolor = gbcolor;
#endif
	ntru = (curwp->w_ntrows-1) / 2; 	/* Upper size		*/
	ntrl = (curwp->w_ntrows-1) - ntru;	/* Lower size		*/
	lp = curwp->w_linep;
	ntrd = 0;
	while (lp != curwp->w_dotp) {
		++ntrd;
		lp = lforw(lp);
	}
	lp = curwp->w_linep;
	if (((f == FALSE) && (ntrd <= ntru)) || ((f == TRUE) && (n == 1))) {
		/* Old is upper window. */
		if (ntrd == ntru)		/* Hit mode line.	*/
			lp = lforw(lp);
		curwp->w_ntrows = ntru;
		wp->w_wndp = curwp->w_wndp;
		curwp->w_wndp = wp;
		wp->w_toprow = curwp->w_toprow+ntru+1;
		wp->w_ntrows = ntrl;
	} else {				/* Old is lower window	*/
		wp1 = NULL;
		wp2 = wheadp;
		while (wp2 != curwp) {
			wp1 = wp2;
			wp2 = wp2->w_wndp;
		}
		if (wp1 == NULL)
			wheadp = wp;
		else
			wp1->w_wndp = wp;
		wp->w_wndp   = curwp;
		wp->w_toprow = curwp->w_toprow;
		wp->w_ntrows = ntru;
		++ntru; 			/* Mode line.		*/
		curwp->w_toprow += ntru;
		curwp->w_ntrows  = ntrl;
		while (ntru--)
			lp = lforw(lp);
	}
	curwp->w_linep = lp;			/* Adjust the top lines */
	wp->w_linep = lp;			/* if necessary.	*/
	curwp->w_flag |= WFMODE|WFHARD;
	wp->w_flag |= WFMODE|WFHARD;
	return (TRUE);
}

/*
 * Enlarge the current window. Find the window that loses space. Make sure it
 * is big enough. If so, hack the window descriptions, and ask redisplay to do
 * all the hard work. You don't just set "force reframe" because dot would
 * move. Bound to "C-X Z".
 */
enlargewind(f, n)
{
	register WINDOW *adjwp;
	register LINE	*lp;
	register int	i;

	if (n < 0)
		return (shrinkwind(f, -n));
	if (wheadp->w_wndp == NULL) {
		mlwrite("Only one window");
		return (FALSE);
	}
	if ((adjwp=curwp->w_wndp) == NULL) {
		adjwp = wheadp;
		while (adjwp->w_wndp != curwp)
			adjwp = adjwp->w_wndp;
	}
	if (adjwp->w_ntrows <= n) {
		mlwrite("Impossible change");
		return (FALSE);
	}
	if (curwp->w_wndp == adjwp) {		/* Shrink below.	*/
		lp = adjwp->w_linep;
		for (i=0; i<n && lp!=adjwp->w_bufp->b_linep; ++i)
			lp = lforw(lp);
		adjwp->w_linep	= lp;
		adjwp->w_toprow += n;
	} else {				/* Shrink above.	*/
		lp = curwp->w_linep;
		for (i=0; i<n && lback(lp)!=curbp->b_linep; ++i)
			lp = lback(lp);
		curwp->w_linep	= lp;
		curwp->w_toprow -= n;
	}
	curwp->w_ntrows += n;
	adjwp->w_ntrows -= n;
	curwp->w_flag |= WFMODE|WFHARD;
	adjwp->w_flag |= WFMODE|WFHARD;
	return (TRUE);
}

/*
 * Shrink the current window. Find the window that gains space. Hack at the
 * window descriptions. Ask the redisplay to do all the hard work. Bound to
 * "C-X C-Z".
 */
shrinkwind(f, n)
{
	register WINDOW *adjwp;
	register LINE	*lp;
	register int	i;

	if (n < 0)
		return (enlargewind(f, -n));
	if (wheadp->w_wndp == NULL) {
		mlwrite("Only one window");
		return (FALSE);
	}
	if ((adjwp=curwp->w_wndp) == NULL) {
		adjwp = wheadp;
		while (adjwp->w_wndp != curwp)
			adjwp = adjwp->w_wndp;
	}
	if (curwp->w_ntrows <= n) {
		mlwrite("Impossible change");
		return (FALSE);
	}
	if (curwp->w_wndp == adjwp) {		/* Grow below.		*/
		lp = adjwp->w_linep;
		for (i=0; i<n && lback(lp)!=adjwp->w_bufp->b_linep; ++i)
			lp = lback(lp);
		adjwp->w_linep	= lp;
		adjwp->w_toprow -= n;
	} else {				/* Grow above.		*/
		lp = curwp->w_linep;
		for (i=0; i<n && lp!=curbp->b_linep; ++i)
			lp = lforw(lp);
		curwp->w_linep	= lp;
		curwp->w_toprow += n;
	}
	curwp->w_ntrows -= n;
	adjwp->w_ntrows += n;
	curwp->w_flag |= WFMODE|WFHARD;
	adjwp->w_flag |= WFMODE|WFHARD;
	return (TRUE);
}

/*	Resize the current window to the requested size */

resize(f, n)

int f, n;	/* default flag and numeric argument */

{
	int clines;	/* current # of lines in window */
	
	/* must have a non-default argument, else ignore call */
	if (f == FALSE)
		return(TRUE);

	/* find out what to do */
	clines = curwp->w_ntrows;

	/* already the right size? */
	if (clines == n)
		return(TRUE);

	return(enlargewind(TRUE, n - clines));
}

/*
 * Pick a window for a pop-up. Split the screen if there is only one window.
 * Pick the uppermost window that isn't the current window. An LRU algorithm
 * might be better. Return a pointer, or NULL on error.
 */
WINDOW	*
wpopup()
{
	register WINDOW *wp;

	if (wheadp->w_wndp == NULL		/* Only 1 window	*/
        && splitwind(FALSE, 0) == FALSE)        /* and it won't split	*/
		return (NULL);
	wp = wheadp;				/* Find window to use	*/
	while (wp!=NULL && wp==curwp)
		wp = wp->w_wndp;
	return (wp);
}

scrnextup(f, n) 	/* scroll the next window up (back) a page */

{
	nextwind(FALSE, 1);
	backpage(f, n);
	prevwind(FALSE, 1);
}

scrnextdw(f, n) 	/* scroll the next window down (forward) a page */

{
	nextwind(FALSE, 1);
	forwpage(f, n);
	prevwind(FALSE, 1);
}

savewnd(f, n)		/* save ptr to current window */

{
	swindow = curwp;
	return(TRUE);
}

restwnd(f, n)		/* restore the saved screen */

{
	register WINDOW *wp;

	/* find the window */
	wp = wheadp;
	while (wp != NULL) {
		if (wp == swindow) {
			curwp = wp;
			curbp = wp->w_bufp;
			upmode();
			return (TRUE);
		}
		wp = wp->w_wndp;
	}

	mlwrite("[No such window exists]");
	return(FALSE);
}

newsize(f, n)	/* resize the screen, re-writing the screen */

int f;	/* default flag */
int n;	/* numeric argument */

{
	WINDOW *wp;	/* current window being examined */
	WINDOW *nextwp; /* next window to scan */
	WINDOW *lastwp; /* last window scanned */
	int lastline;	/* screen line of last line of current window */

	/* if the command defaults, assume the largest */
	if (f == FALSE)
		n = term.t_mrow + 1;

        /* make sure it's in range */
	if (n < 3 || n > term.t_mrow + 1) {
		mlwrite("%%Screen size out of range");
		return(FALSE);
	}

	if (term.t_nrow == n - 1)
		return(TRUE);
	else if (term.t_nrow < n - 1) {

		/* go to the last window */
		wp = wheadp;
		while (wp->w_wndp != NULL)
			wp = wp->w_wndp;

		/* and enlarge it as needed */
		wp->w_ntrows = n - wp->w_toprow - 2;
		wp->w_flag |= WFHARD|WFMODE;

	} else {

		/* rebuild the window structure */
		nextwp = wheadp;
		wp = NULL;
		lastwp = NULL;
		while (nextwp != NULL) {
			wp = nextwp;
			nextwp = wp->w_wndp;
	
			/* get rid of it if it is too low */
			if (wp->w_toprow > n - 2) {

				/* save the point/mark if needed */
				if (--wp->w_bufp->b_nwnd == 0) {
					wp->w_bufp->b_dotp = wp->w_dotp;
					wp->w_bufp->b_doto = wp->w_doto;
					wp->w_bufp->b_markp = wp->w_markp;
					wp->w_bufp->b_marko = wp->w_marko;
				}
	
				/* update curwp and lastwp if needed */
				if (wp == curwp)
					curwp = wheadp;
					curbp = curwp->w_bufp;
				if (lastwp != NULL)
					lastwp->w_wndp = NULL;

				/* free the structure */
				free((char *)wp);
				wp = NULL;

			} else {
				/* need to change this window size? */
				lastline = wp->w_toprow + wp->w_ntrows - 1;
				if (lastline >= n - 2) {
					wp->w_ntrows = n - wp->w_toprow - 2;
					wp->w_flag |= WFHARD|WFMODE;
				}
			}
	
			lastwp = wp;
		}
	}

	/* screen is garbage */
	term.t_nrow = n - 1;
	sgarbf = TRUE;
	return(TRUE);
}

newwidth(f, n)	/* resize the screen, re-writing the screen */

int f;	/* default flag */
int n;	/* numeric argument */

{
	/* if the command defaults, assume the largest */
	if (f == FALSE)
		n = term.t_mcol;

        /* make sure it's in range */
	if (n < 10 || n > term.t_mcol) {
		mlwrite("%%Screen width out of range");
		return(FALSE);
	}

	/* otherwise, just re-width it (no big deal) */
	term.t_ncol = n;
	term.t_margin = n / 10;
	term.t_scrsiz = n - (term.t_margin * 2);
	curwp->w_flag |= WFHARD | WFMOVE;
	sgarbf = TRUE;
	return(TRUE);
}
@//E*O*F window.c//
chmod u=rw,g=r,o=r window.c
 
echo x - word.c
sed 's/^@//' > "word.c" <<'@//E*O*F word.c//'
/*
 * The routines in this file implement commands that work word or a
 * paragraph at a time.  There are all sorts of word mode commands.  If I
 * do any sentence mode commands, they are likely to be put in this file. 
 */

#if	MEGAMAX & ST520
overlay "word"
#endif

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

/* Word wrap on n-spaces. Back-over whatever precedes the point on the current
 * line and stop on the first word-break or the beginning of the line. If we
 * reach the beginning of the line, jump back to the end of the word and start
 * a new line.	Otherwise, break the line at the word-break, eat it, and jump
 * back to the end of the word.
 * Returns TRUE on success, FALSE on errors.
 */
wrapword(f, n)

int f;		/* default flag */
int n;		/* numeric argument */

{
	register int cnt;	/* size of word wrapped to next line */
	register int c; 	/* charector temporary */

	/* backup from the <NL> 1 char */
	if (!backchar(0, 1))
		return(FALSE);

        /* back up until we aren't in a word,
	   make sure there is a break in the line */
	cnt = 0;
	while (((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ')
				&& (c != '\t')) {
		cnt++;
		if (!backchar(0, 1))
			return(FALSE);
		/* if we make it to the beginning, start a new line */
		if (curwp->w_doto == 0) {
			gotoeol(FALSE, 0);
			return(lnewline());
		}
	}

	/* delete the forward white space */
	if (!forwdel(0, 1))
		return(FALSE);

	/* put in a end of line */
	if (!lnewline())
		return(FALSE);

	/* and past the first word */
	while (cnt-- > 0) {
		if (forwchar(FALSE, 1) == FALSE)
			return(FALSE);
	}
	return(TRUE);
}

/*
 * Move the cursor backward by "n" words. All of the details of motion are
 * performed by the "backchar" and "forwchar" routines. Error if you try to
 * move beyond the buffers.
 */
backword(f, n)
{
	if (n < 0)
		return (forwword(f, -n));
	if (backchar(FALSE, 1) == FALSE)
		return (FALSE);
	while (n--) {
		while (inword() == FALSE) {
			if (backchar(FALSE, 1) == FALSE)
				return (FALSE);
		}
		while (inword() != FALSE) {
			if (backchar(FALSE, 1) == FALSE)
				return (FALSE);
		}
	}
	return (forwchar(FALSE, 1));
}

/*
 * Move the cursor forward by the specified number of words. All of the motion
 * is done by "forwchar". Error if you try and move beyond the buffer's end.
 */
forwword(f, n)
{
	if (n < 0)
		return (backword(f, -n));
	while (n--) {
#if	NFWORD
		while (inword() != FALSE) {
			if (forwchar(FALSE, 1) == FALSE)
				return (FALSE);
		}
#endif
		while (inword() == FALSE) {
			if (forwchar(FALSE, 1) == FALSE)
				return (FALSE);
		}
#if	NFWORD == 0
		while (inword() != FALSE) {
			if (forwchar(FALSE, 1) == FALSE)
				return (FALSE);
		}
#endif
	}
	return(TRUE);
}

/*
 * Move the cursor forward by the specified number of words. As you move,
 * convert any characters to upper case. Error if you try and move beyond the
 * end of the buffer. Bound to "M-U".
 */
upperword(f, n)
{
	register int	c;

        if (curbp->b_mode&MDVIEW)       /* don't allow this command if	*/
		return(rdonly());	/* we are in read only mode	*/
	if (n < 0)
		return (FALSE);
	while (n--) {
		while (inword() == FALSE) {
			if (forwchar(FALSE, 1) == FALSE)
				return (FALSE);
		}
		while (inword() != FALSE) {
			c = lgetc(curwp->w_dotp, curwp->w_doto);
			if (c>='a' && c<='z') {
				c -= 'a'-'A';
				lputc(curwp->w_dotp, curwp->w_doto, c);
				lchange(WFHARD);
			}
			if (forwchar(FALSE, 1) == FALSE)
				return (FALSE);
		}
	}
	return (TRUE);
}

/*
 * Move the cursor forward by the specified number of words. As you move
 * convert characters to lower case. Error if you try and move over the end of
 * the buffer. Bound to "M-L".
 */
lowerword(f, n)
{
	register int	c;

        if (curbp->b_mode&MDVIEW)       /* don't allow this command if	*/
		return(rdonly());	/* we are in read only mode	*/
	if (n < 0)
		return (FALSE);
	while (n--) {
		while (inword() == FALSE) {
			if (forwchar(FALSE, 1) == FALSE)
				return (FALSE);
		}
		while (inword() != FALSE) {
			c = lgetc(curwp->w_dotp, curwp->w_doto);
			if (c>='A' && c<='Z') {
				c += 'a'-'A';
				lputc(curwp->w_dotp, curwp->w_doto, c);
				lchange(WFHARD);
			}
			if (forwchar(FALSE, 1) == FALSE)
				return (FALSE);
		}
	}
	return (TRUE);
}

/*
 * Move the cursor forward by the specified number of words. As you move
 * convert the first character of the word to upper case, and subsequent
 * characters to lower case. Error if you try and move past the end of the
 * buffer. Bound to "M-C".
 */
capword(f, n)
{
	register int	c;

        if (curbp->b_mode&MDVIEW)       /* don't allow this command if	*/
		return(rdonly());	/* we are in read only mode	*/
	if (n < 0)
		return (FALSE);
	while (n--) {
		while (inword() == FALSE) {
			if (forwchar(FALSE, 1) == FALSE)
				return (FALSE);
		}
		if (inword() != FALSE) {
			c = lgetc(curwp->w_dotp, curwp->w_doto);
			if (c>='a' && c<='z') {
				c -= 'a'-'A';
				lputc(curwp->w_dotp, curwp->w_doto, c);
				lchange(WFHARD);
			}
			if (forwchar(FALSE, 1) == FALSE)
				return (FALSE);
			while (inword() != FALSE) {
				c = lgetc(curwp->w_dotp, curwp->w_doto);
				if (c>='A' && c<='Z') {
					c += 'a'-'A';
					lputc(curwp->w_dotp, curwp->w_doto, c);
					lchange(WFHARD);
				}
				if (forwchar(FALSE, 1) == FALSE)
					return (FALSE);
			}
		}
	}
	return (TRUE);
}

/*
 * Kill forward by "n" words. Remember the location of dot. Move forward by
 * the right number of words. Put dot back where it was and issue the kill
 * command for the right number of characters. Bound to "M-D".
 */
delfword(f, n)
{
	register LINE	*dotp;
	register int	doto;
	long size;

        if (curbp->b_mode&MDVIEW)       /* don't allow this command if	*/
		return(rdonly());	/* we are in read only mode	*/
	if (n < 0)
		return (FALSE);
	if ((lastflag&CFKILL) == 0)	/* Clear kill buffer if */
                kdelete();              /* last wasn't a kill.	*/
	thisflag |= CFKILL;
	dotp = curwp->w_dotp;
	doto = curwp->w_doto;
	size = 0;
	while (n--) {
#if	NFWORD
		if (curwp->w_doto == llength(curwp->w_dotp)) {
			if (forwchar(FALSE,1) == FALSE)
				return(FALSE);
			++size;
		}

		while (inword() != FALSE) {
			if (forwchar(FALSE,1) == FALSE)
				return(FALSE);
			++size;
		}

		while ((inword() == FALSE) &&
				(curwp->w_doto != llength(curwp->w_dotp))) {
			if (forwchar(FALSE, 1) == FALSE)
				return (FALSE);
			++size;
		}
#else
		while (inword() == FALSE) {
			if (forwchar(FALSE, 1) == FALSE)
				return (FALSE);
			++size;
		}

		while (inword() != FALSE) {
			if (forwchar(FALSE, 1) == FALSE)
				return (FALSE);
			++size;
		}
#endif
	}
	curwp->w_dotp = dotp;
	curwp->w_doto = doto;
	return (ldelete(size, TRUE));
}

/*
 * Kill backwards by "n" words. Move backwards by the desired number of words,
 * counting the characters. When dot is finally moved to its resting place,
 * fire off the kill command. Bound to "M-Rubout" and to "M-Backspace".
 */
delbword(f, n)
{
	long size;

        if (curbp->b_mode&MDVIEW)       /* don't allow this command if	*/
		return(rdonly());	/* we are in read only mode	*/
	if (n < 0)
		return (FALSE);
	if ((lastflag&CFKILL) == 0)	/* Clear kill buffer if */
                kdelete();              /* last wasn't a kill.	*/
	thisflag |= CFKILL;
	if (backchar(FALSE, 1) == FALSE)
		return (FALSE);
	size = 0;
	while (n--) {
		while (inword() == FALSE) {
			if (backchar(FALSE, 1) == FALSE)
				return (FALSE);
			++size;
		}
		while (inword() != FALSE) {
			if (backchar(FALSE, 1) == FALSE)
				return (FALSE);
			++size;
		}
	}
	if (forwchar(FALSE, 1) == FALSE)
		return (FALSE);
	return (ldelete(size, TRUE));
}

/*
 * 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()
{
	register int	c;

	if (curwp->w_doto == llength(curwp->w_dotp))
		return (FALSE);
	c = lgetc(curwp->w_dotp, curwp->w_doto);
	if (c>='a' && c<='z')
		return (TRUE);
	if (c>='A' && c<='Z')
		return (TRUE);
	if (c>='0' && c<='9')
		return (TRUE);
	if (c=='$' || c=='_')			/* For identifiers	*/
		return (TRUE);
	return (FALSE);
}

#if	WORDPRO
fillpara(f, n)	/* Fill the current paragraph according to the current
		   fill column						*/

int f, n;	/* deFault flag and Numeric argument */

{
	register int c; 		/* current char durring scan	*/
	register int wordlen;		/* length of current word	*/
	register int clength;		/* position on line during fill */
	register int i; 		/* index during word copy	*/
	register int newlength; 	/* tentative new line length	*/
	register int eopflag;		/* Are we at the End-Of-Paragraph? */
	register int firstflag; 	/* first word? (needs no space) */
	register LINE *eopline; 	/* pointer to line just past EOP */
	register int dotflag;		/* was the last char a period?	*/
	char wbuf[NSTRING];		/* buffer for current word	*/

        if (curbp->b_mode&MDVIEW)       /* don't allow this command if	*/
		return(rdonly());	/* we are in read only mode	*/
	if (fillcol == 0) {	/* no fill column set */
		mlwrite("No fill column set");
		return(FALSE);
	}

	/* record the pointer to the line just past the EOP */
	gotoeop(FALSE, 1);
	eopline = lforw(curwp->w_dotp);

	/* and back top the beginning of the paragraph */
	gotobop(FALSE, 1);

	/* initialize various info */
	clength = curwp->w_doto;
	if (clength && curwp->w_dotp->l_text[0] == TAB)
		clength = 8;
	wordlen = 0;
	dotflag = FALSE;

	/* scan through lines, filling words */
	firstflag = TRUE;
	eopflag = FALSE;
	while (!eopflag) {
		/* get the next character in the paragraph */
		if (curwp->w_doto == llength(curwp->w_dotp)) {
			c = ' ';
			if (lforw(curwp->w_dotp) == eopline)
				eopflag = TRUE;
		} else
			c = lgetc(curwp->w_dotp, curwp->w_doto);

		/* and then delete it */
		ldelete(1L, FALSE);

		/* if not a separator, just add it in */
		if (c != ' ' && c != '\t') {
			dotflag = (c == '.');		/* was it a dot */
			if (wordlen < NSTRING - 1)
				wbuf[wordlen++] = c;
		} else if (wordlen) {
			/* at a word break with a word waiting */
			/* calculate tantitive new length with word added */
			newlength = clength + 1 + wordlen;
			if (newlength <= fillcol) {
				/* add word to current line */
				if (!firstflag) {
					linsert(1, ' '); /* the space */
					++clength;
				}
				firstflag = FALSE;
			} else {
				/* start a new line */
				lnewline();
				clength = 0;
			}

			/* and add the word in in either case */
			for (i=0; i<wordlen; i++) {
				linsert(1, wbuf[i]);
				++clength;
			}
			if (dotflag) {
				linsert(1, ' ');
				++clength;
			}
			wordlen = 0;
		}
	}
	/* and add a last newline for the end of our new paragraph */
	lnewline();
	return(TRUE);
}

killpara(f, n)	/* delete n paragraphs starting with the current one */

int f;	/* default flag */
int n;	/* # of paras to delete */

{
	register int status;	/* returned status of functions */

	while (n--) {		/* for each paragraph to delete */

		/* mark out the end and beginning of the para to delete */
		gotoeop(FALSE, 1);

		/* set the mark here */
		curwp->w_markp = curwp->w_dotp;
		curwp->w_marko = curwp->w_doto;

		/* go to the beginning of the paragraph */
		gotobop(FALSE, 1);
		curwp->w_doto = 0;	/* force us to the beginning of line */
	
		/* and delete it */
		if ((status = killregion(FALSE, 1)) != TRUE)
			return(status);

		/* and clean up the 2 extra lines */
		ldelete(2L, TRUE);
	}
	return(TRUE);
}


/*	wordcount:	count the # of words in the marked region,
			along with average word sizes, # of chars, etc,
			and report on them.			*/

wordcount(f, n)

int f, n;	/* ignored numeric arguments */

{
	register LINE *lp;	/* current line to scan */
	register int offset;	/* current char to scan */
	long size;		/* size of region left to count */
	register int ch;	/* current character to scan */
	register int wordflag;	/* are we in a word now? */
	register int lastword;	/* were we just in a word? */
	long nwords;		/* total # of words */
	long nchars;		/* total number of chars */
	int nlines;		/* total number of lines in region */
	int avgch;		/* average number of chars/word */
	int status;		/* status return code */
	REGION region;		/* region to look at */

	/* make sure we have a region to count */
	if ((status = getregion(&region)) != TRUE)
		return(status);
	lp = region.r_linep;
	offset = region.r_offset;
	size = region.r_size;

	/* count up things */
	lastword = FALSE;
	nchars = 0L;
	nwords = 0L;
	nlines = 0;
	while (size--) {

		/* get the current character */
		if (offset == llength(lp)) {	/* end of line */
			ch = '\n';
			lp = lforw(lp);
			offset = 0;
			++nlines;
		} else {
			ch = lgetc(lp, offset);
			++offset;
		}

		/* and tabulate it */
		wordflag = ((ch >= 'a' && ch <= 'z') ||
			    (ch >= 'A' && ch <= 'Z') ||
			    (ch >= '0' && ch <= '9') ||
			    (ch == '$' || ch == '_'));
		if (wordflag == TRUE && lastword == FALSE)
			++nwords;
		lastword = wordflag;
		++nchars;
	}

	/* and report on the info */
	if (nwords > 0L)
		avgch = (int)((100L * nchars) / nwords);
	else
		avgch = 0;

	mlwrite("Words %D Chars %D Lines %d Avg chars/word %f",
		nwords, nchars, nlines + 1, avgch);
	return(TRUE);
}
#endif
@//E*O*F word.c//
chmod u=rw,g=r,o=r word.c
 
exit 0
