[net.sources] WTerm for Atari ST, part 1 of 2

esfraga@water.UUCP (Eric S Fraga) (09/11/86)

# 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 water!esfraga on Sun Aug  3 17:22:02 EDT 1986
# Contents:  README debug.c externs.c main.c screen.c tek.c window.c wterm.h
#	wterm.inp
 
echo x - README
sed 's/^@//' > "README" <<'@//E*O*F README//'
				WTerm-II


Description

This is a new version of WTerm (posted to the net several months
ago).  All the features in the old version have been retained
(these included: Tek 4010 emulation, sysline support, add/delete
line and char) with several new features added.

The new version uses many more features of GEM.  The menu bar is
used for a cleaner user interface.  This allows the use of any
desk accessories that may be available.  The terminal screen is
now displayed inside a window which may be sized and moved.


How to use

This new program is a GEM application -- just double click on
the particular icon and it will start up.  The initial window is
full size (77x20) but may be changed thereafter.  The menu bar
allows the user to select a new baud rate (although the default
will be used) and the duplex.  Any other line characteristics
must be set elsewhere (I use the VT52 desk accessory for that).

The approach taken with respect to the window is that the
terminal screen takes up the whole window (nothing more; nothing
less).  That means that the window is not a 'window' into a
virtual screen.  As a result, whenever the window is resized,
the host machine must be informed of this (if the host needs to
know screen sizes as in Unix to use 'vi', 'emacs', etc.).  The
program has an option "New Termcap" which will send the termcap
entry with the proper 'co' and 'li' entries to the host (note:
this must only be done when the user is at the command level and
that command level must be a 'csh' type because the command sent
is of the form:

setenv TERMCAP 'xx|window|window-s:hs:ts=\EN:fs=\EO:co#77:li#19...'

).

The default termcap entry (which corresponds to the biggest
window allowed = initial window) is:

xx|window520st-s|window-s|window 520st vt52 emulation with sysline:\
	:hs:ts=\EN:fs=\EO:\
	:tc=window:
xx|window520st|window|window 520st vt52 emulation:\
	:co#77:li#20:nd=\EC:\
	:am:bs:pt:xt:\
	:cd=\EJ:ce=\EK:cl=\EE:\
	:do=\EB:up=\EA:cm=\EY%+ %+ :\
	:dl=\EM:al=\EL:\
	:dc=\Em:ic=\El:im=:ei=:\
	:ku=\EA:kl=\ED:kd=\EB:kr=\EC:kh=\EH:\
	:kb=^H:\
	:so=\Ep:se=\Eq:


Known Bugs and Limitations

There are several known bugs/limitations:

- for some reason, the bottom row of pixels in a line is
sometimes lost (this happens in 'vi' when scrolling up for
example).  I haven't been able to track this one down...

- due to some interaction between the GEM and TOS levels on the
ST, the first few characters typed in are ignored by the
program.  That is, the program does not get the first few
characters (anywhere from 3 to 10).  I have seen this bug
elsewhere and has to do with using GEM event routines in
conjunction with TOS console i/o routines...  Just hold down
some key until the program responds!

- will not run very well at baud rates > 2400.  The program
should not lose characters but effective baud rate at 9600 comes
out to approximately 2400.

- tek mode plots are relative to the top left of the physical
screen and are clipped to fit in the actual window.  This means
that if the actual plot uses parts of the edges of the screen,
this information will not come out in the window.  Yechh.

I think that's it (whew).  If anybody finds any more, please let
me know (although due to the fact that my machine and I will be
on separate continents for most of the next year, it is doubtful
that I will do anything...).



Eric S Fraga		   ||				   esfraga@water.uucp
Dept of Computer Science   ||			   esfraga@water.Waterloo.edu
U of Waterloo		   ||			 esfraga%water@waterloo.csnet
@//E*O*F README//
chmod u=rw,g=r,o=r README
 
echo x - debug.c
sed 's/^@//' > "debug.c" <<'@//E*O*F debug.c//'
#include <osbind.h>

Debug(s)
char *s;
{
	Cconout(27);
	Cconws( "Y  " );	/* top left corner of screen */
	Cconout(27);
	Cconout( 'K' );		/* clear to end of line */
	Cconws(s);
}

char *digits = "0123456789";

DebugP(s,x)
char *s;
int x;
{
	int d,i,len;
	char sign, buf[12];

	buf[11] = '\0';
	for( i=0; i<11; i++ )
		buf[i] = ' ';
	len = 11;
	Debug(s);
	sign = ' ';
	if( x < 0 ) {
		sign = '-';
		x = -x;
	}
	i = len - 1;
	do {
		d = x % 10;
		buf[i] = digits[d];
		i--;
		x = x/10;
	} while( x != 0 );
	buf[i] = sign;
	Cconws( &buf[i] );
	Cconin();
	Debug( "ok" );
}
@//E*O*F debug.c//
chmod u=rw,g=r,o=r debug.c
 
echo x - externs.c
sed 's/^@//' > "externs.c" <<'@//E*O*F externs.c//'
#define EXTERN 1
#include "wterm.h"

int	Window;
int	Handle;
int	Ox, Oy, Ow, Oh;	/* outer size of window */
int	Ix, Iy, Iw, Ih; /* inner size of window */
int	n_col = N_COL, n_row = N_ROW;	/* number of rows and columns in window */
int	max_col, max_row;	/* maximum number allowed by physical screen */

long	gaddr;		/* used by the resource files */

int	Xdesk, Ydesk, Wdesk, Hdesk;
int	CharW, CharH;	/* character cell width and height */
int	Baseline;	/* Bottom line relative to baseline */

char	Screen[N_ROW][1+N_COL];		/* image of whole screen */
int	Scr_col, Scr_row;
int	Sysl_row, Sysl_col, Sysline;

int	command, comd_pos;		/* used in screen.c mostly */
int	Half;				/* Half/full duplex */
int	T_mode, T_draw, T_count;	/* used in TEK 4010 emulation */
int	T_x, T_y;			/* current X and Y graphics pos */

int	contrl[12];
int	intin[128];
int	ptsin[128];
int	intout[128];
int	ptsout[128];
@//E*O*F externs.c//
chmod u=rw,g=r,o=r externs.c
 
echo x - main.c
sed 's/^@//' > "main.c" <<'@//E*O*F main.c//'
/*
 * Terminal emulator using VDI routines
 *
 * Eric S Fraga
 * 1986 March 4
 * Revision: 1986 July 10 -- converted to use a window and menu bar
 *
 * Based on a window demo:
 *
 *****************************************************
 * Window demo					     *
 * by Jerome M. Lang   21 February 1986	             *
 * PD						     *
 *****************************************************/

#include <obdefs.h>
#include <gemdefs.h>
#include <define.h>
#include <osbind.h>
#include "wterm.h"

/*
 * main processing
 */


main()
{
#ifdef	WINDOW
	/*
	 * The window version of this program uses the menu bar.
	 */
	 
	int MenuId;

	MenuId = -1;
	Window = NO_WINDOW;
#endif

	appl_init();

#ifdef	WINDOW
	/*
	 * make sure the mouse is an arrow.
	 */
	 
	graf_mouse( ARROW, 0L);
#endif

	/*
	 * Initialize very many things...  amongst them, open the
	 * window (if using windows), clear the screen, set up all
	 * the appropriate flags, and possibly set up the menu.
	 */
	 
	initMain();

	/*
	 * Init Screen stuff, then show the window.
	 */
	
	Init_Scr();
	
	/*
	 * Finally, call the actual terminal emulator (routine that
	 * processes characters from the serial port and the
	 * keyboard).
	 */
	 
	term();

#ifdef	WINDOW
	menu_bar( gaddr, 0 );	/* erase the menu bar */
	
	rsrc_free();	/* free up the resources */
#endif
	
	v_clsvwk( Handle );	/* close the window */
	
	appl_exit();
}

initMain()
{
	int	attrib[10];
	int	distances[5],effects[3];
	int	workIn[11], workOut[57];
	auto	int	dummy;
	int	i;
	int ret;

	/* find size of desk */
#ifdef	WINDOW
	wind_get( 0, WF_WORKXYWH, &Xdesk, &Ydesk, &Wdesk, &Hdesk );
#else
	/*
	 * very kludgy:  hard coded constants!!!  (yechhh)
	 */
	 
	Ix = 0;
	Iy = 0;
	Iw = 639;
	Ih = 399;
#endif

	/*
	 * Get a handle (no pun intended) on the screen.  Set up all
	 * the VDI shit... and finally open the workstation.
	 */
	 
	Handle=graf_handle(&dummy,&dummy,&dummy,&dummy);
	for( i=0; i<10; i++)
		workIn[i]=1;
	workIn[10]=2;
	v_opnvwk(workIn, &Handle, workOut);

	/*
	 * how big is character cell?
	 */
	 
	vqt_attribute( Handle, attrib );
	CharW = attrib[8];
	CharH = attrib[9];

#ifdef	WINDOW

	/*
	 * Calculate the location and size of the maximum size window
	 * that can be used.
	 */
	 
	Ox = Xdesk;
	Oy = Ydesk;
	Ow = Wdesk;
	Oh = Hdesk;
	
	ret = wind_calc(1, W_KIND, Ox, Oy, Ow, Oh, &Ix, &Iy, &Iw, &Ih );
	n_row = max_row = Ih / CharH - 1;
	n_col = max_col = Iw / CharW;
	if( n_row > N_ROW )
		n_row = max_row = N_ROW;
	if( n_col > N_COL )
		n_col = max_col = N_COL;
		
	Iw = n_col * CharW;
	Ih = (n_row+1) * CharH;
	ret = wind_calc( 0, W_KIND, Ix, Iy, Iw, Ih, &Ox, &Oy, &Ow, &Oh );
#endif

	vqt_fontinfo( Handle, &dummy, &dummy, distances, &dummy, effects);
	Baseline = distances[0];

	/*
	 * set fill pattern & color in order to clear window
	 */
	 
	vsf_color( Handle, 0 );

	/*
	 * Initialize some other stuff
	 */
	 
#ifdef	WINDOW
	Wopen();		/* open the window */
#endif
	Clear();		/* clear the window */
	Clear_Sysl();		/* and the sysline line */
	command = FALSE;	/* no terminal command started yet */
	comd_pos = 0;		/* used by MOVE_CURSOR term command */
	Half = FALSE;		/* Full duplex is the default */
	T_mode = ALPHA;		/* text mode at start */
	T_x = 0;		/* TEK x coord = 0 */
	T_y = 0;		/* ditto for TEK y */
	Sysline = FALSE;	/* not in sysline mode yet */

#ifdef	WINDOW
	/*
	 * attempt to load in the resource file and then
	 * set up the menu bar...
	 */
	 
	ret = rsrc_load( RSC_FILE );
	if( 0 == ret ) {
		Pterm0();
	}

	/*
	 * to set up the menu bar, must get the address of
	 * the menu from the tree.
	 */
	 
	ret = rsrc_gaddr( 0, TREE1, &gaddr );
	if( 0 == ret ) {
		Pterm0();
	}

	/*
	 * now actually set up the menu
	 */
	 
	ret = menu_bar( gaddr, 1 );	/* display the menu */
	if( 0 == ret ) {
		Pterm0();
	}	
#endif
}

/*
 * term
 *
 * This is the actual terminal emulator.  Characters are read in
 * from the serial port, processed, and then displayed as necessary.
 * Likewise, characters from the keyboard are sent down the serial
 * line.
 *
 * In the window version, any time there has been no activity at
 * either the serial line or the keyboard, GEM is given control
 * for a little while (to allow user to use the mouse and desk
 * accessories).
 */
 
term()
{
	long lx;
	int ret, done = FALSE;
	int flag = FALSE;
	register int x, Curscnt, n, Gemcount, mouse;
	register char c;

	Cursor();
	Curscnt = CURSCNT;
	Gemcount = GEMCOUNT;
	graf_mouse( M_OFF, 0L );
	mouse = FALSE;
	while(!done)
	{
		/*
		 * Check keyboard for characters.  Using event seems
		 * to miss lots of chars unfortunately.
		 */
		
		flag = FALSE;
		x = Cconis();	/* check status */
		if( 0 != x ) {	/* some chars waiting */
			if( TRUE == mouse ) {
				graf_mouse( M_OFF, 0L );
				mouse = FALSE;
			}
			Gemcount = GEMCOUNT;
			flag = TRUE;
			lx = (long) Crawcin();		/* read from console */
			c = (char) (lx & 0x7fL);	/* actual character */
			if( NIL == c )
				done = special(lx);
			else {
				Cauxout(c);	/* send to serial port */
				if( TRUE == Half ) {
				  	if( Curscnt <= 0 )
						Cursor(); /* Disable cursor */
					proc( (char) c );
					Curscnt = CURSCNT; /* reset count */
				}
			}
		}
		
		/*
		 * Finally, check the serial port for stuff.
		 */
		
		x = Cauxis();
		if( -1 == x ) {		/* there's something there */
			if( TRUE == mouse ) {
				graf_mouse( M_OFF, 0L );
				mouse = FALSE;
			}
			Gemcount = GEMCOUNT;
			flag = TRUE;
		  	if( Curscnt <= 0 )
				Cursor();	/* Disable cursor */
			n = 10;			/* read up to 10 chars */
			do {
				c = Cauxin();
				c = c & 0x7f;	/* get rid of parity */
				proc( (char) c );
			} while( n-->0 && (x=Cauxis()) == -1);
			Curscnt = CURSCNT;	/* reset count */
		} else if( Curscnt > 0 && ALPHA == T_mode ) {
			Curscnt--;
			if( Curscnt <= 0 )
				Cursor();	/* Enable cursor */
		}
#ifdef	WINDOW
		if( --Gemcount < 0 ) {
			/*
			 * there was neither a character from the
			 * keyboard nor the serial line in a long
			 * time so let GEM get some control.
			 */
			 
			if( FALSE == mouse ) {
				graf_mouse( M_ON, 0L );
				mouse = TRUE;
			}
			done = Wproc();
			Gemcount = 0;		/* reset counter */
		}
#endif
	}
}

/*
 * Special key has been hit
 * (ie. function keys, arrow keys, HELP, UNDO, etc)
 */

special(x)
long x;
{
	register char c;

	c = (char) ( (x >> 16) & 0x7f );
	switch( c ) {

	case HELP:
		do_help();
		break;

	case UNDO:
		return( TRUE );
		break;

	case HOME:
		Cauxout( ESC );
		Cauxout( HO );
		break;

	case UARROW:
		Cauxout( ESC );
		Cauxout( UP );
		break;

	case LARROW:
		Cauxout( ESC );
		Cauxout( LE );
		break;

	case DARROW:
		Cauxout( ESC );
		Cauxout( DO );
		break;

	case RARROW:
		Cauxout( ESC );
		Cauxout( ND );
		break;
	}
	return( FALSE );
}

/*
 * do_help
 *
 * User hit HELP key.  This key gives short description (ie. help) and
 * allows user to set some variables (like baud rate and such).
 */

do_help()
{
	/*
	 * don't this right now as it screws up the desktop...
	 * (must do the baud rate and duplex stuff using menu
	 * items which is better anyway)
	 */
	 
#ifndef	WINDOW
	register char c;
	do {
		Cconout( ESC );
		Cconout( CL );
		Cconws( "WTerm -- UNDO to quit, HELP for help\r\n" );
		Cconws( "(c) 1986 Eric S. Fraga\r\n\n" );
		Cconws( "Hit:\r\n" );
		Cconws( "\t1\t300 baud\r\n" );
		Cconws( "\t2\t1200 baud\r\n" );
		Cconws( "\t3\t2400 baud\r\n" );
		Cconws( "\t4\t4800 baud\r\n" );
		Cconws( "\t5\t9600 baud\r\n\n" );
		Cconws( "\tf\tFull duplex\r\n" );
		Cconws( "\th\tHalf duplex\r\n\n" );
		Cconws( "\tspace\tto return\r\n\n" );
		Cconws( "-->" );

		/*
		 * read in char from user
		 */
	
		c = Cconin();
		switch( c ) {
		case 'q':
		case ' ':	wshow( Ix, Iy, Iw, Ih );
			break;
		
		case '1':	Rsconf( B300, -1, -1, -1, -1, -1 ); break;
		case '2':	Rsconf( B1200, -1, -1, -1, -1, -1 ); break;
		case '3':	Rsconf( B2400, -1, -1, -1, -1, -1 ); break;
		case '4':	Rsconf( B4800, -1, -1, -1, -1, -1 ); break;
		case '5':	Rsconf( B9600, -1, -1, -1, -1, -1 ); break;
		case 'f':	Half = FALSE;			break;
		case 'h':	Half = TRUE;			break;
		default:	Cconout(7);			break;
		}
	} while( c != ' ' && c != 'q' );
#endif	/* !WINDOW */

	T_mode = ALPHA;		/* just to have some way to reset for now */
}

#ifdef	MEGAMAX
vqt_fontin(handle,minADE,maxADE,dist,maxw,effects)
int handle,dist[5],effects[3];
int *minADE, *maxADE, *maxw;
{
	vqt_font_info(handle,minADE,maxADE,dist,maxw,effects);
}
#endif	/* MEGAMAX */
@//E*O*F main.c//
chmod u=rw,g=r,o=r main.c
 
echo x - screen.c
sed 's/^@//' > "screen.c" <<'@//E*O*F screen.c//'
#include <obdefs.h>
#include <gemdefs.h>
#include <define.h>
#include <osbind.h>
#include "wterm.h"

/*
 * Init_Scr
 *
 * Initialize all the stuff associated with the screen:
 *
 * Clear the screen, reset row and column, etc.
 */

Init_Scr()
{
	register int i, j;
	
	for( i=0; i<n_row; i++ ) {
		for( j=0; j<N_COL; j++ ) {
			Screen[i][j] = ' ';
		}
		Screen[i][n_col] = EOS;
	}

	Scr_col = 0;
	Scr_row = 0;
}

/*
 * Clear the sysline
 */
 
Init_Sysl()
{
	register int i;
	for( i=0; i<n_col; i++ )
		Screen[n_row][i] = ' ';
	Screen[n_row][n_col] = EOS;
}

/*
 * proc
 *
 * Process a character that is going out onto the screen.
 */

proc(c)
char c;
{
	if( command == TRUE ) {
		do_comd(c);
		return;
	} else if( comd_pos > 0 ) {
		do_pos(c);
		comd_pos--;
		return;
	}
	if( Sysline == TRUE && c != (char) 27 ) {
		show_char(c);
		Scr_col++;
		if( Scr_col >= n_col )
			Scr_col = n_col - 1;
		return;
	}

	/*
	 * There are two distinct modes:  ALPHA and Graphics, the latter
	 * emulating a Tektronix 4010 mode.
	 */
	
	if( GRAPH == T_mode ) {
		tek(c);		/* process as if this were a TEK 4010 */
		return;
	}
	switch( c ) {

	case '\r':	Scr_col = 0;				break;
	case '\n':	Scr_row++;
			if( Scr_row >= n_row )
				Scroll();
			break;
	case 7:		Cconout( 7 );				break;
	case 8:		Scr_col--;
			if( Scr_col < 0 )
				Scr_col = 0;
			break;
	case '\t':	Scr_col = 8 * ( Scr_col/8 + 1 );
			if( Scr_col >= n_col ) {
				Scr_col = 0;
				Scr_row++;
				if( Scr_row >= n_row )
					Scroll();
			}
			break;
	case 27:	command = TRUE;				break;
	case GS:	T_mode = GRAPH;
			T_draw = FALSE;
			T_count = 0;
			break;
	case US:	T_mode = ALPHA;				break;
	default:	
			if( c > (char)31 ) {
				Screen[Scr_row][Scr_col] = c;
				show_char(c);
				Scr_col++;
				if( Scr_col >= n_col ) {
					Scr_col = 0;
					Scr_row++;
					if( Scr_row >= n_row )
						Scroll();
				}
			}
			break;
	}
}

/*
 * do_comd
 *
 * a terminal command.
 */

do_comd(c)
char c;
{
	switch(c) {
	case 'A':	Scr_row = (Scr_row > 0) ? --Scr_row : 0; break;
	case 'B':	Scr_row = (Scr_row < n_row-1) ? ++Scr_row : n_row-1;
			break;
	case 'C':	if( Scr_col < n_col-1 ) {
				Scr_col++;
			} else {
				Scr_col = 0;
				Scr_row++;
				if( Scr_row >= n_row )
					Scroll();
			}
			break;
	case 'D':	Scr_col = (Scr_col > 0) ? --Scr_col : 0; break;
	case FF:	/* for TEK mode ... */
	case 'E':	Clear();				break;
	case 'H':	Scr_col = Scr_row = 0;			break;
	case 'J':	EOP_Clear();				break;
	case 'K':	EOL_Clear();				break;
	case 'L':	Ins_Line();				break;
	case 'M':	Del_Line();				break;
	case 'N':	Sysl_On();				break;
	case 'O':	Sysl_Off();				break;
	case 'Y':	comd_pos = 2;				break;
	case 'l':	Ins_Char();				break;
	case 'm':	Del_Char();				break;
	case 'p':	vst_effects(Handle,2);
			break;
	case 'q':	vst_effects(Handle,0);
			break;
	default:	break;
	}
	command = FALSE;
}

do_pos(c)
register char c;
{
	if( comd_pos == 2 ) {
		Scr_row = (int) (c - ' ');
		if( Scr_row >= n_row )
			Scr_row = n_row-1;
	} else {
		Scr_col = (int) (c - ' ');
		if( Scr_col >= n_col )
			Scr_col = n_col-1;
	}
}
/*
 * Scroll
 *
 * Scroll in a new line (do this the dumb way for now).
 */

Scroll()
{
	register int i, j;
	int x,y,w,h;
	register char *from, *to;

	int wr_mode, pxy[8], src[10], des[10];

	from = &Screen[1][0];
	to = &Screen[0][0];
	for( i=1; i<N_ROW; i++, to++, from++ )
		for( j=0; j<N_COL; j++ )
			*to++ = *from++;

	Scr_row = n_row - 1;

	for( j=0; j<n_col; j++ )
		Screen[Scr_row][j] = ' ';

	/*
	 * Try using a raster operation to scroll... ha ha
	 */
#ifdef	SMOOTH
	for( j=0; j<CharH; j++ ) {
		Raster( 3, Ix, Iy+1, Ix, Iy, n_col*CharW, n_row*CharH - 1 );
	}
	eraseWindow( Handle, Ix, Iy+(n_row-1)*CharH,
			n_col*CharW, CharH );
#else
	Raster( 3, Ix, Iy+CharH, Ix, Iy, n_col*CharW, (n_row-1)*CharH );
	eraseWindow( Handle, Ix, Iy+(n_row-1)*CharH,
			n_col*CharW, CharH );
#endif
}

Clear()
{
	Init_Scr();
	eraseWindow( Handle, Ix, Iy, Iw, Ih-CharH );
}

EOP_Clear()
{
	register int i, j;
	EOL_Clear();
	i = Scr_row++;
	j = Scr_col;
	Scr_col = 0;
	for( ; Scr_row < n_row; Scr_row++ )
		EOL_Clear();
	Scr_row = i;
	Scr_col = j;
}

EOL_Clear()
{
	register int i;
	for( i=Scr_col; i<n_col; i++ )
		Screen[Scr_row][i] = ' ';
	eraseWindow( Handle, Ix+Scr_col*CharW, Iy+Scr_row*CharH,
			(n_col-Scr_col)*CharW, CharH );
}

Ins_Line()
{
	register int i, j;
	register char *p, *q;

	for( i=n_row-1; i>Scr_row; i-- ) {
		p = &Screen[i][0];
		q = &Screen[i-1][0];
		for( j=0; j<N_COL; j++ )
			*p++ = *q++;
	}
	/*
	 * Try using a raster operation to scroll... ha ha
	 */
	 
	Raster( 3, Ix, Iy+Scr_row*CharH, Ix, Iy+(Scr_row+1)*CharH,
		n_col*CharW, (n_row-Scr_row-1)*CharH );

	Scr_col = 0;
	EOL_Clear();
}

Del_Line()
{
	register int i, j;
	register char *p, *q;
	
	for( i=Scr_row; i<n_row; i++ ) {
		p = &Screen[i][0];
		q = &Screen[i+1][0];
		for( j=0; j<N_COL; j++ )
			*p++ = *q++;
	}
	/*
	 * Try using a raster operation to scroll... ha ha
	 */
	 
	Raster( 3, Ix, Iy+(Scr_row+1)*CharH, Ix, Iy+Scr_row*CharH,
		n_col*CharW, (n_row-Scr_row-1)*CharH );

	Scr_col = 0;
	i = Scr_row;
	Scr_row = n_row - 1;
	EOL_Clear();
	Scr_row = i;
}

Del_Char()
{
	register int i, j;
	register char *p, *q;
	
	p = &Screen[Scr_row][Scr_col];
	q = &Screen[Scr_row][Scr_col+1];
	for( i=Scr_col; i<n_col-1; i++ )
			*p++ = *q++;

	/* Shift chars over */
	Raster( 3, Ix+(Scr_col+1)*CharW, Iy+Scr_row*CharH,
		Ix+Scr_col*CharW, Iy+Scr_row*CharH,
		(n_col-Scr_col-1)*CharW, CharH );
	/* Clear last byte */
	Raster( 0, Ix+(n_col-1)*CharW, Iy+Scr_row*CharH,
		Ix+(n_col-1)*CharW, Iy+Scr_row*CharH,
		CharW, CharH );
}
Ins_Char()
{
	register int i, j;
	register char *p, *q;
	
	p = &Screen[Scr_row][Scr_col+1];
	q = &Screen[Scr_row][Scr_col];
	for( i=n_col-1; i>Scr_col; i-- )
			*p++ = *q++;

	Raster( 3, Ix+Scr_col*CharW, Iy+Scr_row*CharH,
		Ix+(Scr_col+1)*CharW, Iy+Scr_row*CharH,
		(n_col-Scr_col-1)*CharW, CharH );
	/* Clear current byte */
	Raster( 0, Ix+Scr_col*CharW, Iy+Scr_row*CharH,
		Ix+Scr_col*CharW, Iy+Scr_row*CharH,
		CharW, CharH );
}

Sysl_On()
{
	Sysline = TRUE;
	Sysl_row = Scr_row;
	Sysl_col = Scr_col;
	Scr_row = n_row;	/* Sysline is on bottom row */
	Scr_col = 0;
	Init_Sysl();		/* clear the storage associated with the sysline */
	Clear_Sysl();		/* clear the actual line on the screen */
	vst_effects(Handle,2);
}

Sysl_Off()
{
	vst_effects(Handle,0);
	Scr_row = Sysl_row;
	Scr_col = Sysl_col;
	Sysline = FALSE;
}

Clear_Sysl()
{
	Raster( 0, 0, 0, Ix, Iy+n_row*CharH, n_col*CharW, CharH );
}
@//E*O*F screen.c//
chmod u=rw,g=r,o=r screen.c
 
echo x - tek.c
sed 's/^@//' > "tek.c" <<'@//E*O*F tek.c//'
/*
 * tek
 *
 * This routine will attempt to emulate a Tektronix 4010 storage scope
 * terminal...
 */

#include "wterm.h"

#define FALSE   0
#define TRUE    1

int Ly, Lx, Hy, Hx;

tek(c)
char c;
{
	register int y, x;

	if( GS == c ) {
		T_mode = GRAPH;
		T_draw = FALSE;
		T_count = 0;
	} else if( US == c ) {
		T_mode = ALPHA;
	} else {
		switch( (int) (c & 0x60) ) {

		case 0x20: /* high order Y or X */
			if( T_count > 0 ) {
				/* high order X */
				Hx = c & 0x1f;
			} else {
				/* high order Y */
				Hy = (int) (c & 0x1f);
			}
			break;

		case 0x60: /* low order Y */
			Ly = (int) (c & 0x1f);
			T_count = 1;  /* X next */
			break;

		case 0x40: /* low X */
			Lx = (int) (c & 0x1f);
			x = Lx | (int) (Hx << 5);
			y = Ly | (int) (Hy << 5);
			plot(x,y,T_draw);
			T_count = 0;
			T_draw = TRUE;
			break;

		default:
			/*
			 * this really should not happen but we all
			 * know better...
			 */
			break;		/* just ignore (lazy, I guess) */
		}
	}
}

plot(x,y,draw)
{
	int pxy[8];

	x = x / 2;
	y = 399 - (y/2);
	if( y < 0 )
		y = 0;
	pxy[2] = x;
	pxy[3] = y;

	/*
	 * if draw is TRUE then we are joining the previous point to
	 * the current one.  Otherwise, we just plot a point.
	 */
	if( TRUE == draw ) {
		pxy[0] = T_x;
		pxy[1] = T_y;
	} else {
		pxy[0] = x;
		pxy[1] = y;
	}
	v_pline( Handle, 2, pxy );
	T_x = x;
	T_y = y;
}




@//E*O*F tek.c//
chmod u=rw,g=r,o=r tek.c
 
echo x - window.c
sed 's/^@//' > "window.c" <<'@//E*O*F window.c//'
#include <obdefs.h>
#include <gemdefs.h>
#include <define.h>
#include <osbind.h>
#include "wterm.h"


#ifdef	WINDOW

/*
 * Wopen
 *
 * Open up a window
 */
 
Wopen()
{
	int ret;

	Window = wind_create(W_KIND, Ox, Oy, Ow, Oh);
	if( 0 >= Window)
	{
		Window = NO_WINDOW;
		return ;
	}
	ret = wind_set(Window, WF_NAME, WINDNAME);
	ret = wind_open(Window, Ox, Oy, Ow, Oh);
}

/* Wclose - 
 * close calculator display window
 */
Wclose()
{
	if (Window != NO_WINDOW)
	{
		wind_close(Window);
		wind_delete(Window);
		Window = NO_WINDOW;
	}
}

/*
 * Wproc
 *
 * Process a message from GEM or wait for a millisecond...
 */

int Last_Baud = -1;		/* for check mark on baud rate */
 
int Wproc()
{
	int event, msgbuf[8], ret, done=FALSE;

	do {
	    /*
	     * Turn on the mouse so that the user can do things.  Then
	     * allow him to use the menu, size the window, etc.
	     */
	     
	    event = evnt_multi( MU_TIMER | MU_MESAG,
			0, 0, 0,
			0, 0, 0, 0, 0,
			0, 0, 0, 0, 0,
			msgbuf, 1, 0,
			&ret, &ret, &ret, &ret, &ret, &ret);
	    if( event & MU_MESAG ) {
		switch (msgbuf[0])
		{
#ifdef ACC
		case AC_OPEN: /* for future usage */
			if (msgbuf[4] == MenuId)
			{
				closeWindow();
				do_calc();
				show_calc();
			}
			break;
		case AC_CLOSE: /* for future usage */
			if (msgbuf[3] == MenuId)
				Window = NO_WINDOW;
			break;
#endif
		case WM_CLOSED:
			if (msgbuf[3] == Window)
			{
				Wclose();
				done=TRUE;
			}
			break;
		case WM_MOVED:
			if (msgbuf[3] == Window)
			{
				Ox = msgbuf[4];
				Oy = msgbuf[5];
				Ow = msgbuf[6];
				Oh = msgbuf[7];
				wind_set( Window, WF_CURRXYWH,
					Ox, Oy, Ow, Oh);
				wind_calc(1, W_KIND, Ox, Oy, Ow, Oh,
					&Ix, &Iy, &Iw, &Ih);
				clip( Handle, Ix, Iy, Iw, Ih );
			}
			break;
		case WM_SIZED:
			if (msgbuf[3] == Window)
			{
				Ox = msgbuf[4];
				Oy = msgbuf[5];
				Ow = msgbuf[6];
				Oh = msgbuf[7];
				
				/*
				 * What does this mean in terms of
				 * the inside area?
				 */
				 
				wind_calc(1, W_KIND, Ox, Oy, Ow, Oh,
					&Ix, &Iy, &Iw, &Ih);
				n_row = Ih / CharH - 1;
				n_col = Iw / CharW;
				
				/*
				 * If these dimensions are not acceptable,
				 * reset them to a bare minimum.
				 */
				 
				if( n_row < MIN_ROW )
					n_row = MIN_ROW;
				else if( n_row > N_ROW )
					n_row = N_ROW;
					
				if( n_col < MIN_COL )
					n_col = MIN_COL;
				else if( n_col > N_COL )
					n_col = N_COL;

				Ih = (n_row+1) * CharH;
				Iw = n_col * CharW;
				
				/*
				 * Recalculate outer dimensions and define
				 * the new window.
				 */
				 
				wind_calc( 0, W_KIND, Ix, Iy, Iw, Ih,
					&Ox, &Oy, &Ow, &Oh );
				wind_set( Window, WF_CURRXYWH,
					Ox, Oy, Ow, Oh);
				Init_Scr();
				Init_Sysl();
				clip( Handle, Ix, Iy, Iw, Ih );
				eraseWindow( Handle, Ix, Iy, Iw, Ih );
				Cursor();
			}
			break;
		case WM_NEWTOP:
		case WM_TOPPED:
			if (msgbuf[3] ==  Window)
				wind_set( Window, WF_TOP, 0, 0, 0, 0);
			break;
		case WM_REDRAW:
			if (msgbuf[3] == Window)
			{
				wshow(msgbuf[4], msgbuf[5], 
					msgbuf[6], msgbuf[7]);
			}
			break;
			
		case MN_SELECTED:
			switch( msgbuf[4] ) {
			case FILEQUIT:	done = TRUE; break;
			
			case OPTFULL:	Half = FALSE;
					menu_icheck( gaddr, OPTFULL, TRUE );
					menu_icheck( gaddr, OPTHALF, FALSE );
					break;
					
			case OPTHALF:	Half = TRUE;
					menu_icheck( gaddr, OPTFULL, FALSE );
					menu_icheck( gaddr, OPTHALF, TRUE );
					break;
				
			case OPT300:	Rsconf( B300, -1, -1, -1, -1, -1 ); goto Baud_Check;
			case OPT1200:	Rsconf( B1200, -1, -1, -1, -1, -1 ); goto Baud_Check;
			case OPT2400:	Rsconf( B2400, -1, -1, -1, -1, -1 ); goto Baud_Check;
			case OPT4800:	Rsconf( B4800, -1, -1, -1, -1, -1 ); goto Baud_Check;
			case OPT9600:	Rsconf( B9600, -1, -1, -1, -1, -1 ); goto Baud_Check;
			Baud_Check:	if( -1 != Last_Baud )
						menu_icheck( gaddr, Last_Baud, FALSE );
					Last_Baud = msgbuf[4];
					menu_icheck( gaddr, msgbuf[4], TRUE );
					break;

			case OPTNTERM:	ptermcap( n_row, n_col ); break;
			}
			menu_tnormal( gaddr, msgbuf[3], TRUE );
		}
	    }
	} while( !( event & MU_TIMER ) );
	return( done );
}
#endif

clip( handle, x, y, w, h)
int	x,y,w,h;
int	handle;
{
	int	pxy[4];

	pxy[0] = x;
	pxy[1] = y;
	pxy[2] = x+w-1;
	pxy[3] = y+h-1;

	vs_clip( handle, 1, pxy );

}

eraseWindow( handle, x, y, w, h)
int	x,y,w,h;
int	handle;
{
	int	pxy[4];
	pxy[0] = x;
	pxy[1] = y;
	pxy[2] = x+w-1;
	pxy[3] = y+h-1;

	graf_mouse( M_OFF, 0L );
	v_bar( handle, pxy );
	graf_mouse( M_ON, 0L );
}

/* wshow - 
 * 	actual display of the whole window
 */
wshow(x,y,w,h)
int	x,y,w,h;
{
	register int	i, yy;
#ifdef	WINDOW
	int cl_x, cl_y, cl_w, cl_h;
	
	graf_mouse(M_OFF, 0L);		/* get rid of mouse for now */

	/*
	 * Must only do stuff in the rectangle list.  That means
	 * we must clip...
	 */
	
	wind_update( BEG_UPDATE );	/* start updating the window */
	
	wind_get( Window, WF_FIRSTXYWH, &cl_x, &cl_y, &cl_w, &cl_h );
	while( 0 != cl_w && 0 != cl_h ) {
		/*
		 * limit changes to current rectangle by clipping
		 */
		 
		clip( Handle, cl_x, cl_y, cl_w, cl_h );
#endif
		/*
		 * Write from top to bottom
		 */
	 
		yy = Iy - Baseline-1 + CharH;
		for( i = 0; i<=n_row; i++ )
		{
			v_gtext( Handle, Ix, yy, &Screen[i][0] );
			yy += CharH;
		}
#ifdef	WINDOW
		/*
		 * get next rectangle in the list
		 */
		 
		wind_get( Window, WF_NEXTXYWH, &cl_x, &cl_y, &cl_w, &cl_h );
	}
	wind_update( END_UPDATE );	/* ve iss done! */
	graf_mouse(M_ON, 0L);		/* put mouse back there */
#endif
	Cursor();
}

/*
 * show_char
 *
 * Update screen by showing the latest character that has come in.
 */

show_char(c)
char c;
{
	int x, y, w, h;
	char s[2];

	/*
	 * stuff char into string
	 */
	s[0] = c;
	s[1] = EOS;
	
	v_gtext(Handle, Ix + Scr_col*CharW,
			Iy - Baseline - 1 + (Scr_row+1)*CharH,
			s);
}


/*
 * Cursor
 *
 * Either show or hide (toggle) cursor (steady block).
 */

Cursor()
{
	int wr_mode, pxy[8], src[10], des[10];

	/*
	 * Use raster operation to Invert pixels at current 
	 * location
	 */
	Raster( 12, Ix + Scr_col*CharW, Iy + Scr_row*CharH,
		Ix + Scr_col*CharW, Iy + Scr_row*CharH,
		CharW, CharH );
}
Raster(wr_mode, xfrom, yfrom, xto, yto, w, h )
{
	register int i;
	int pxy[8], src[10], des[10];
	pxy[0] = xfrom;
	pxy[1] = yfrom;
	pxy[2] = xfrom+w-1;
	pxy[3] = yfrom+h-1;
	pxy[4] = xto;
	pxy[5] = yto;
	pxy[6] = xto+w-1;
	pxy[7] = yto+h-1;
	for( i=0; i<10; i++ ) {
		src[i] = 0;
		des[i] = 0;
	}
/*	graf_mouse( M_OFF, 0L );*/
	vro_cpyfm( Handle, wr_mode, pxy, src, des );
/*	graf_mouse( M_ON, 0L );*/
}

/*
 * ptermcap
 *
 * print out a new termcap entry...
 */

char Termcap[] = "setenv TERMCAP 'xx|window|window-s:hs:\
ts=\\EN:fs=\\EO:co#77:li#20:nd=\\EC:am:bs:pt:xt:cd=\\EJ:\
ce=\\EK:cl=\\EE:do=\\EB:up=\\EA:cm=\\EY%+\\040%+\\040:\
dl=\\EM:al=\\EL:dc=\\Em:ic=\\El:im=:ei=:ku=\\EA:kl=\\ED:\
kd=\\EB:kr=\\EC:kh=\\EH:kb=^H:so=\\Ep:se=\\Eq:'\n";

#define	ROWPOS	(61)
#define	COLPOS	(55)

ptermcap( row, col )
int row, col;
{
	register char *p;
	register int ret;

	putnum( row, &Termcap[ROWPOS] );
	putnum( col, &Termcap[COLPOS] );
	p = Termcap;
	while( *p != '\0' ) {
		do {
			ret = Cauxos();
		} while( ret == 0 );
		Cauxout( *p++ );
	}
}

/*
 * putnum
 *
 * convert an int to a two digit number in the string passed
 */

char Digits[] = "0123456789";

putnum( x, s )
int x;
char *s;
{
	register int t;
	t = x/10;
	*s++ = Digits[t];
	t = x - t*10;
	*s = Digits[t];
}
@//E*O*F window.c//
chmod u=rw,g=r,o=r window.c
 
echo x - wterm.h
sed 's/^@//' > "wterm.h" <<'@//E*O*F wterm.h//'
/*
 * the first few lines come from RSC...
 */
#define TREE1 0  	/* TREE */
#define TREE2 1  	/* TREE */
#define DESK 3  	/* OBJECT in TREE #0 */
#define DESKINFO 8  	/* OBJECT in TREE #0 */
#define FILE 4  	/* OBJECT in TREE #0 */
#define FILEQUIT 17  	/* OBJECT in TREE #0 */
#define OPTIONS 5  	/* OBJECT in TREE #0 */
#define OPTFULL 19  	/* OBJECT in TREE #0 */
#define OPTHALF 21  	/* OBJECT in TREE #0 */
#define OPT300 22  	/* OBJECT in TREE #0 */
#define OPT1200 23  	/* OBJECT in TREE #0 */
#define OPT2400 24  	/* OBJECT in TREE #0 */
#define OPT4800 25  	/* OBJECT in TREE #0 */
#define OPT9600 26  	/* OBJECT in TREE #0 */
#define OPTNTERM 28  	/* OBJECT in TREE #0 */

#define	RSC_FILE	"wterm.rsc"	/* for resources... */

#define	WINDOW	1
#define NO_WINDOW 	(-1)
#define W_KIND		(NAME | CLOSER | MOVER | SIZER)
#define WINDNAME	"WTerm-II"
#define N_COL		80 /* num of char to be displayed  in window */
#define N_ROW		25 /* how many numbers in stack to display in window */
#define	MIN_COL		20	/* minimum number of columns */
#define	MIN_ROW		 4	/* something reasonable? */

#define	CURSCNT		2 /* how long to wait between displays of cursor */
			   /* has to be done because of slowness of some */
			   /* of the VDI/AES calls... damn. */
/*
 * since the minimum amount of time one can ask for when doing an
 * EVENT_MULTI call (to allow GEM to get control once in a while) is
 * 1 millisecond, we should only do this very infrequently.  GEMCOUNT
 * describes how many noneventful iterations of the main loop in
 * TERM should be done before handing GEM control.
 */
#define	GEMCOUNT	1000

/*
 * The following several defines are used by Tek 4010 mode.
 */
#define GRAPH   1
#define ALPHA   0
#define GS      0x1d
#define US      0x1f

#define ESC	0x1b	/* Terminal Command initiator */
#define	CE	'K'	/* Clear to end of line */
#define	CL	'E'	/* Clear whole screen */
#define CM	'Y'	/* Postion cursor -- followed by two chars */
#define	DO	'B'	/* cursor down */
#define	HO	'H'	/* Home cursor */
#define	LE	'D'	/* cursor left */
#define	ND	'C'	/* cursor right */
#define	UP	'A'	/* cursor up */
#define SC	'j'	/* Save Cursor location */
#define	RC	'k'	/* Restore Cursor */
#define SO	'p'	/* StandOut mode */
#define SE	'q'	/* StandEnd mode */
#define	TS	0x0e	/* Control-N --> to status line */
#define	FS	0x0f	/* Control-O --> from Status line */
#define FF	0x0c	/* Form Feed for TEK 4010 mode */

#define	UNDO	0x61
#define	HELP	0x62
#define	HOME	0x47
#define	UARROW	0x48
#define	LARROW	0x4b
#define	DARROW	0x50
#define	RARROW	0x4d

#define	B300	9
#define	B1200	7
#define	B2400	4
#define	B4800	2
#define	B9600	1

#ifndef EXTERN
extern	int	gl_apid;
extern	int	Window;
extern int	Handle;
extern	int	Ox, Oy, Ow, Oh;	/* outer dimensions of window */
extern int	Ix, Iy, Iw, Ih; /* inner size of window */
extern int	n_col, n_row;	/* number of rows and columns in window */
extern	int	max_col, max_row;	/* maximum allowed by screen */

extern long	gaddr;		/* used by the resource files */

extern int	Xdesk, Ydesk, Wdesk, Hdesk;
extern int	CharW, CharH;	/* character cell width and height */
extern int	Baseline;	/* Bottom line relative to baseline */

extern char	Screen[N_ROW+1][1+N_COL];	/* image of whole screen */
extern int	Scr_col, Scr_row;
extern int	Sysl_row, Sysl_col, Sysline;

extern int	command, comd_pos;
extern int	Half;	/* for half/full duplex */
extern int	T_mode, T_count, T_draw;
extern int	T_x, T_y;

extern int	contrl[12];
extern int	intin[128];
extern int	ptsin[128];
extern int	intout[128];
extern int	ptsout[128];
#endif
@//E*O*F wterm.h//
chmod u=rw,g=r,o=r wterm.h
 
echo x - wterm.inp
sed 's/^@//' > "wterm.inp" <<'@//E*O*F wterm.inp//'
[u] wterm.68k=a:apstart,debug.o,externs.o,main.o,screen.o,tek.o,window.o,a:osbind,a:vdibind,a:aesbind
@//E*O*F wterm.inp//
chmod u=rw,g=r,o=r wterm.inp
 
exit 0
-- 

Eric S Fraga		   ||				   esfraga@water.uucp
Dept of Computer Science   ||			   esfraga@water.Waterloo.edu
U of Waterloo		   ||			 esfraga%water@waterloo.csnet