v01i006: xtclient: use a 3b1 as a layers terminal, Part03/04

Merlin J Mathesius merlinm at i88.isc.com
Fri Feb 15 13:16:33 AEST 1991


Submitted-by: merlinm at i88.isc.com (Merlin J Mathesius)
Posting-number: Volume 1, Issue 6
Archive-name: xtclient/part03

---- Cut Here and feed the following to sh ----
#!/bin/sh
# This is part 03 of xtclient
# ============= xtclient/session.c ==============
if test ! -d 'xtclient'; then
    echo 'x - creating directory xtclient'
    mkdir 'xtclient'
fi
if test -f 'xtclient/session.c' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient/session.c (File already exists)'
else
echo 'x - extracting xtclient/session.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient/session.c' &&
/*
X * File name:	
X *
X * Description:	The session layer for the "xt/layers" client system on the
X *		UNIX-PC.
X *		
X *			==> !!! ==> !!! NOTE !!! <== !!! <==
X *		The session layer intentionally "short circuits" the
X *		presentation layer of the ISO model and directly interfaces
X *		to the application layer.  The presentation layer performs
X *		no useful function in this program, so for efficiency it
X *		has been eliminated!
X *		
X * Author:	Merlin J. Mathesius
X *
X * Contents:	SESinit()	initialize the session layer
X *		SESreq()	request for data from the session layer
X *		SESind()	indication there is data for the session layer
X *		SEScontrol()	processes control data for "xt/layers" <local>
X *		SESinform()	indication that user has executed a control cmd
X *		GetReplBuf()	get a control informatoin reply buffer
X *		FreeReplBuf()	release a control information reply buffer
X *
X * Data:	SESready	indicator that control information is ready
X */
X
#include <stdio.h>
#include <memory.h>
X
#include "session.h"
#include "appl.h"
#include "command.h"
#include "xtclient.h"
X
/* the following buffer provides for several outstanding blocks of control */
/* information to be returned */
X
#define NumReplBuf	16	/* number of reply buffers to allocate */
X
struct repl_buf {
X	int	addr;		/* address providing control info */
X	int	cnt;		/* number of bytes of control info */
X	unsigned char buf[32];	/* control information buffer */
X	struct repl_buf *next;	/* pointer to next buffer */
};
X
static struct repl_buf ReplBuf[NumReplBuf];	/* reply buffers */
static struct repl_buf *BufList;		/* list of ready reply bufs */
static struct repl_buf *FreeBuf;		/* list of free reply bufs */
X
/* number of blocks of control info ready */
static int bufs_inuse;
X
static int ses_enable;
X
static int first_reply;
X
/*  this is global so "Wait()" can check it */
int SESready;
X
static int		SEScontrol();
static struct repl_buf	*GetReplBuf();
static void		FreeReplBuf();
X
/*
X * Function name:	SESinit()
X *
X * Description:		Initialize the session layer.
X *
X * Parameters:		None
X *
X * Return values:	None
X */
void
XSESinit()
{
X	struct repl_buf	*p;	/* reply buffer pointer */
X	int	i;
X
X	/* no buffers currently waiting */
X	SESready = 0;
X	BufList = NULL;
X
X	bufs_inuse = 0;
X	ses_enable = 0;
X	first_reply = 1;
X
X	/* initialize free list of reply buffers */
X	FreeBuf = NULL;
X	p = &ReplBuf[0];
X	for (i = 0; i < NumReplBuf; i++)
X	{
X		p->next = FreeBuf;
X		FreeBuf = p++;
X	}
}
X
/*
X * Function name:	SESreq(addr, data, size)
X *
X * Description:		Request for data from the session layer.  If data
X *			or control information is available, it is returned
X *			in the "data" buffer.  The number of bytes and address
X *			providing the data is also returned.
X *
X * Parameters:		addr	pointer to location to return address
X *			data	pointer to data buffer
X *			size	maximum number of bytes of data to return
X *
X * Return values:	0	no data available
X *			else	number of bytes of data actually returned
X */
int
XSESreq(addr, data, size)
int	*addr;	/* returned channel (ie., window number) with data */
char	*data;	/* data buffer in which to placed returned data */
int	size;	/* maximum number of bytes of data to be returned */
{
X	int	rc;
X
X	/* if there is control information, return it */
X	if (SESready)
X	{
X
X		if (first_reply)
X		{
X			sleep(2);
X			first_reply = 0;
X		}
X		/* return information from first element of buffer list */
X		*addr = BufList->addr;
X		/* Incoming "size" is NOT checked, it is assumed to fit! */
X		size = BufList->cnt;
X		(void)memcpy(data, (char *)BufList->buf, size);
X		/* remove the buffer from the ready list */
X		FreeReplBuf();
X		return(size);
X	}
X
X	/* pass request for data to application layer interface function. */
X	/* The one byte offset is to allow room for the "xt/layers" command */
X	/* byte at the beginning of the buffer */
X	rc = APreq(addr, data+1, size-1);
#ifdef EBUG
X	if (rc < 0)
X		(void)fprintf(stderr, "SESreq: bad return from APreq, %d\n", rc);
#endif
X	if (rc <= 0)
X		/* no data */
X		return(0);
X
X	/* we need to store "xt/layers" command in the buffer */
X	if (rc == 1)
X		data[0] = 1;	/* "xt/layers" command for a single char */
X	else
X		data[0] = 7;	/* "xt/layers" command for multiple chars */
X	
X	/* return the number of data bytes plus the command byte */
X	return(rc+1);
}
X
/*
X * Function name:	SESind(addr, data, size)
X *
X * Description:		Deliver data which has arrived for the session layer.
X *
X * Parameters:		addr	address to which data should be delivered
X *			data	pointer to data buffer
X *			size	number of bytes of data to send
X *
X * Return values:	-1	error
X *			0	OK, data successfully accepted
X */
int
XSESind(addr, data, size)
int	addr;	/* channel (ie., window number) to receive data */
char	*data;	/* data to be output */
int	size;	/* number of bytes of data available */
{
X	if (addr == 0)
X	{
X		/* address 0 is control information */
X		return(SEScontrol((unsigned char *)data, size));
X	}
X
X	/* pass indication to application layer interface function. */
X	return(APind(addr, data, size));
}
X
/*
X * Function name:	SEScontrol()
X *
X * Description:		Process control information
X *
X * Return values:	-1	error
X *			0	OK, data successfully accepted
X */
X
static int
XSEScontrol(data, size)
unsigned char	*data;	/* control data (make sure type is "unsigned" here) */
int	size;		/* number of bytes of control data */
{
X	struct repl_buf	*p;			/* pointer to reply buffer */
X	XtCommand	command;		/* host command */
X	long		p1, p2, p3, p4;		/* parms for AGENT commands */
X	int		addr;			/* window for AGENT command */
X	int		r_timeout, x_timeout;	/* scratch timeout variables */
X	int		i;			/* loop index */
X	int		rc;			/* return code */
X
X	/* switch on the first byte (the command byte) of the data */
X	switch (data[0])
X	{
X	case 2:
X		/* this is an order from the host to go unmultiplexed */
X
X		/* unset the multiplexing flag to exit protocol */
X		mpx_flag = 0;
X
X		/* OK, but don't acknowledge this data!!! */
X		return(0);
X
X	case 4:
X		/* set receive/xmit timeout values (in seconds) */
X		r_timeout = data[1];
X		x_timeout = data[2];
X
#ifdef EBUG
X	(void)fprintf(stderr, "SEScontrol: rcv TO = %ds, xmit TO = %ds\n",
X		      r_timeout, x_timeout);
#endif
X		/*
X		 * Now that I've got them, I'll ignore them!  This should be
X		 * corrected some day, but let's keep "lint" happy...
X		 */
X		r_timeout = r_timeout; x_timeout = x_timeout;
X
X		ses_enable = 1;
X
X		if (bufs_inuse)
X			SESready = 1;
X
X		return(0);
X
X	case 6:
X		/* set receive/xmit timeout values (in milliseconds) */
X		r_timeout = data[2] << 8 | data[1];
X		x_timeout = data[4] << 8 | data[3];
X
#ifdef EBUG
X	(void)fprintf(stderr, "SEScontrol: rcv TO = %dms, xmit TO = %dms\n",
X		      r_timeout, x_timeout);
#endif
X		/*
X		 * Now that I've got them, I'll ignore them!  This should be
X		 * corrected some day, but let's keep "lint" happy...
X		 */
X		r_timeout = r_timeout; x_timeout = x_timeout;
X
X		ses_enable = 1;
X
X		if (bufs_inuse)
X			SESready = 1;
X
X		/* OK, acknowledge this data */
X		return(0);
X
X	case 9:
X		/* "agent" control functions */
X
X		/* decode the AGENT command */
X		switch (data[3])
X		{
X		case 1:		/* create a new window (no attached process) */
X			command = XtXcreate; break;
X		case 2:		/* make specified window "current" */
X			command = XtCurrent; break;
X		case 3:		/* delete specified window */
X			command = XtDelete; break;
X		case 4:		/* make specified window "top" */
X			command = XtTop; break;
X		case 5:		/* bury specified window */
X			command = XtBottom; break;
X		case 6:		/* move specified window */
X			command = XtMove; break;
X		case 7:		/* reshape specified window */
X			command = XtReshape; break;
X		case 8:		/* create new window (with attached process) */
X			command = XtCreate; break;
X		case 9:		/* exit multiplexed mode */
X			command = XtExit; break;
X
X		case 20:	/* request for ROM version */
X		default:	/* truly unknown */
#ifdef EBUG
X	(void)fprintf(stderr, "SEScontrol: unsupported AGENT command seq =");
X	for (i = 1; i < size; i++)
X		(void)fprintf(stderr, " %02x", data[i]);
X	(void)fprintf(stderr, "\n");
#endif
X			command = XtUnknown; break;
X		}
X
X		/* initialize the AGENT parameters */
X		p1 = p2 = p3 = p4 = 0L;
X
X		switch (command)
X		{
X		case XtCreate:
X		case XtXcreate:
X		case XtReshape:
X
X			/* extract all 4 additional parameters */
X			p4 = data[12] << 8 | data[13];
X			p3 = data[10] << 8 | data[11];
X
X			/* FALLTHROUGH */
X
X		case XtMove:
X
X			/* extract 2 additional parameters */
X			p2 = data[8] << 8 | data[9];
X			p1 = data[6] << 8 | data[7];
X
X			/* FALLTHROUGH */
X
X		case XtDelete:
X		case XtCurrent:
X		case XtTop:
X		case XtBottom:
X		case XtExit:
X
X			/* extract the address */
X			addr = data[5];
X
X			/* execute the command */
X			rc = APexec(command, addr, p1, p2, p3, p4);
X			break;
X
X		case XtUnknown:
X			rc = -1;
X			break;
X		}
X
X		/* get a reply buffer for the agent command */
X		p = GetReplBuf();
X
X		/* no buffer... */
X		if (p == NULL)
X			return(-1);
X
X		/* copy the source control information to the reply buffer */
X		p->addr = 0;	/* send back to control channel */
X		p->cnt = size;	/* reply is same size as command */
X		memcpy((char *)p->buf, (char *)data, size);
X
X		/* if the command was a successful "create", return new addr */
X		if (rc > 0 && (command == XtCreate || command == XtXcreate))
X		{
X			p->buf[4] = 0;
X			p->buf[5] = rc;
X			rc = 0;
X		}
X
X		p->buf[2] = p->buf[3] = (rc == -1) ? 0xff : 0;
X
X		return(0);
X
X	default:
X		/* ignore this control code */
#ifdef EBUG
X	(void)fprintf(stderr, "SEScontrol: don't know what to do with %d\n", data[0]);
#endif
X		/* error */
X		return(-1);
X	}
}
X
/*
X * Function name:	SESinform(command, addr, p1, p2, p3, p4)
X *
X * Description:		Called by application layer when user has executed
X *			a control command.
X *
X *			Control information will be packaged and returned
X *			to the "xt/layers" host.
X *
X * Parameters:		command	user command
X *			addr	address on which command was executed
X *			p1	extra parameter when needed
X *			p2	extra parameter when needed
X *			p3	extra parameter when needed
X *			p4	extra parameter when needed
X *
X * Return values:	0	command accepted
X *			-1	error
X */
int
XSESinform(command, addr, p1, p2, p3, p4)
XXtCommand	command;	/* user command */
int		addr;		/* address on which command was executed */
long		p1, p2, p3, p4;	/* extra parameters when needed */
{
X	struct repl_buf	*p;		/* pointer to reply buffer */
X
X	/* get a reply buffer for the user command */
X	p = GetReplBuf();
X
X	/* no buffer, can't process */
X	if (p == NULL)
X		return(-1);
X
X	/* assemble the control sequence for the command */
X	switch (command)
X	{
X	case XtCreate:
X	case XtReshape:
X		if (command == XtCreate)
X			p->buf[0] = 2;	/* "xt/layers" command for "create" */
X		else
X			p->buf[0] = 8;	/* "xt/layers" command for "reshape" */
X		/* the extra parameters are: */
X		/*  p1 - width (in chars) of window */
X		/*  p2 - height (in chars) of window */
X		/*  p3 - width (in bits) of window */
X		/*  p4 - height (in bits) of window */
X		p->buf[1] = p1;		/* width (in chars) of window */
X		p->buf[2] = p2;		/* height (in chars) of window */
X		p->buf[3] = p3 & 0xff;	/* width (in bits) - low order byte */
X		p->buf[4] = (p3 >> 8) & 0xff;	/* width - high order byte */
X		p->buf[5] = p4 & 0xff;	/* height (in bits) - low order byte */
X		p->buf[6] = (p4 >> 8) & 0xff;	/* height - high order byte */
X
X		p->addr = addr;		/* new/affected channel */
X		p->cnt = 7;
X
X		break;
X
X	case XtDelete:	/* window deleted */
X		p->buf[0] = 4;		/* "xt/layers" command for "delete" */
X		p->addr = addr;		/* affected channel */
X		p->cnt = 1;
X
X		break;
X
X	case XtExit:	/* exiting multiplexed mode */
X		p->buf[0] = 5;		/* "xt/layers" command for "exit" */
X		p->addr = 0;		/* control channel gets exit */
X		p->cnt = 1;
X
X		break;
X
X	case XtUnknown:
X	default:
#ifdef EBUG
X		(void)fprintf(stderr, "SESinform: unknown command (%d)\n", command);
#endif
X		p->cnt = 0;		/* we really don't have a reply... */
X		p->addr = 0;
X		return(-1);
X	}
X
X	return(0);
}
X
/*
X * Function name:	GetReplBuf()
X *
X * Description:		Returns an available reply buffer.
X *
X * Parameters:		None
X *
X * Return values:	NULL	no buffers available
X *			else	reply buffer to use
X *
X * WARNING:		Although highly unlikely, race conditions may
X *			occur in this function if the user reshapes a window 
X *			(ie., a "signal" has been caught) while the main
X *			thread of execution is within this function.
X */
static struct repl_buf *
GetReplBuf()
{
X	struct repl_buf *f, **l;
X
X	/* if free list is empty, return NULL */
X	if (FreeBuf == NULL)
X	{
#ifdef EBUG
X		(void)fprintf(stderr, "GetReplBuf: No free buffers!!\n");
#endif
X		return(NULL);
X	}
X
X	/* save head of the free list */
X	f = FreeBuf;
X
X	/* remove the first buffer */
X	FreeBuf = FreeBuf->next;
X
X	/* clear out the final "next" pointer */
X	f->next = NULL;
X
X	/* place this buffer at the end of the ready list */
X	l = &BufList;
X	while (*l != NULL)
X		l = &((*l)->next);
X	*l = f;
X
X	/* increment count of ready buffer */
X	bufs_inuse++;
X
X	if (ses_enable)
X		SESready = 1;
X
X	/* return the pointer to the free buffer */
X	return(f);
}
X
/*
X * Function name:	FreeReplBuf()
X *
X * Description:		Remove the buffer on the head of the ready list and
X *			and place it on the free list.
X *
X * Parameters:		None
X *
X * Return values:	None
X */
static void
FreeReplBuf()
{
X	struct repl_buf *f;
X
X	/* save pointer to head of ready list */
X	f = BufList;
X
X	/* remove the buffer from the ready list */
X	BufList = BufList->next;
X
X	/* put the buffer at the head of the free list */
X	f->next = FreeBuf;
X	FreeBuf = f;
X
X	/* decrement number of ready buffers */
X	bufs_inuse--;
X
X	if (bufs_inuse == 0)
X		SESready = 0;
}
SHAR_EOF
chmod 0644 xtclient/session.c ||
echo 'restore of xtclient/session.c failed'
Wc_c="`wc -c < 'xtclient/session.c'`"
test 13449 -eq "$Wc_c" ||
	echo 'xtclient/session.c: original size 13449, current size' "$Wc_c"
fi
# ============= xtclient/session.h ==============
if test -f 'xtclient/session.h' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient/session.h (File already exists)'
else
echo 'x - extracting xtclient/session.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient/session.h' &&
/*
X * File name:	session.h
X *
X * Description:	External function and data declarations for session.c
X *
X * Author:	Merlin J. Mathesius
X */
X
Xextern void	SESinit();
Xextern int	SESreq(), SESind();
Xextern int	SESinform();
X
Xextern int	SESready;
SHAR_EOF
chmod 0644 xtclient/session.h ||
echo 'restore of xtclient/session.h failed'
Wc_c="`wc -c < 'xtclient/session.h'`"
test 239 -eq "$Wc_c" ||
	echo 'xtclient/session.h: original size 239, current size' "$Wc_c"
fi
# ============= xtclient/window.c ==============
if test -f 'xtclient/window.c' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient/window.c (File already exists)'
else
echo 'x - extracting xtclient/window.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient/window.c' &&
/*
X * File name:	window.c
X *
X * Description:	Windowing interface specific routines for the "xt/layers"
X *		system for the UNIX-PC.
X *
X * Author:	Merlin J. Mathesius
X *
X * Contents:	Winit()		initialize windowing system
X *		Wshutdown()	shutdown windowing system
X *		Wmpx()		indication that multiplexed mode is starting
X *		Wunmpx()	indication that multiplexed mode is ending
X *		Wcreate()	create a new window
X *		Wdestroy()	destroy an existing window
X *		Wselect()	make a specified window current
X *		Wshape()	reshape/move a window
X *		Wtop()		pop a window to the top of window stack
X *		Wbottom()	push a window to the bottom of window stack
X *		Winput()	grab keyboard input from a window
X *		Woutput()	send output to a window
X *		sigwind()	process window signals <local>
X *		findwnum()	find window corresponding to file descr <local>
X *
X * Data:	wind_fds	bit map with current window file descriptor
X *		Wready		indicates unprocessed keyboard data remains
X *				(used by mgrwindow.c - unused in this version)
X */
X
#include <stdio.h>
#include <tam.h>
#include <wind.h>
#include <termio.h>
#include <sys/window.h>
#include <sys/font.h>
#include <signal.h>
#include <string.h>
X
#include "xtclient.h"
#include "window.h"
#include "appl.h"
#include "command.h"
X
/* location of default font to use for new windows */
#define DEFAULT_FONT	"/usr/local/lib/xtclient.f"
X
/* globally accessible data */
X
int wind_fds;		/* bit map with current window file descriptor */
int Wready;		/* indicates unprocessed keyboard data remains */
struct termio	orig_termio;	/* initial saved termio for control dev */
X
/* locally accessible data */
X
static int Wcurrent;	/* current window number */
static int curw_fd;	/* file descriptor corresponding to Wcurrent */
X
struct _w_info {
X	int	num;	/* window number, same as array index */
X	int	fd;	/* file descriptor, device to access */
X
X	/* the following fields are so sigwind() can detect changes */
X	struct	uwdata	uw;	/* window information */
X	int	inform;	/* 0 = don't call APinform() if changes occur */
};
X
static struct _w_info w_info[MAXW+1]; /* NOTE: element 0 is unused */
X
X
/* save area so initial window configuration can be saved */
static struct uwdata save_uw;
static struct utdata save_utlab;
X
static int sigwind();	/* window signal handler */
static int findwnum();
X
/*
X * Function name:	Winit()
X *
X * Description:		Initialize the windowing system.
X *
X * Parameters:		None
X *
X * Return values:	None
X */
void
Winit()
{
X	int i;
X
X	/* clear out all window data structures */
X	for (i = 1; i <= MAXW; i++)
X	{
X		w_info[i].num = i;
X		w_info[i].fd  = -1;
X		w_info[i].inform = 0;
X	}
X
X	/* clear bit map of window file descriptors */
X	wind_fds = 0;
X
X	/* get initial termio modes for use in subshells */
X	if (ioctl(1, TCGETA, &orig_termio) < 0)
X	{
X		perror("ioctl(TCGETA)");
X
X		/* exit with error */
X		exit(1);
X	}
X
X	/* get initial window data and save it */
X	(void)ioctl(1, WIOCGETD, &save_uw);
X	save_utlab.ut_num = WTXTLABEL;
X	(void)ioctl(1, WIOCGETTEXT, &save_utlab);
X
X	/* initialize OS windowing system */
X	winit();
X	keypad(0, 1);
X
X	/* capture window signals */
X	(void)signal(SIGWIND, sigwind);
X
X	/* create initial window */
X	(void)Wcreate(1, 0L, 0L, 0L, 0L, 0, 0);
X
X	/* call window signal handler to do it's thing with the first window */
X	sigwind(SIGWIND);
}
X
/*
X * Function name:	Wshutdown()
X *
X * Description:		Shutdown the windowing system.
X *
X * Parameters:		None
X *
X * Return values:	Never returns!!!!!!
X */
void
Wshutdown()
{
X	struct ufdata uf;	/* user font data */
X	int	wd;		/* file descriptor of primary window */
X	int	i;		/* loop index */
X
X	/* close any open windows (except the primary window) */
X	for (i = 2; i <= MAXW; i++)
X	{
X		if (w_info[i].fd != -1)
X			(void)Wdestroy(i);
X	}
X
X	/* get file descriptor of primary window */
X	wd = w_info[1].fd;
X
X	/* clear out the command and prompt areas of the window */
X	wcmd(wd, "");
X	wprompt(wd, "");
X
X	/* clear the window */
X	wgoto(wd, 0, 0);
X	wprintf(wd, "\033[2J");
X	wrefresh(wd);
X
X	/* restore the original font */
X	uf.uf_slot = 0;
X	(void)ioctl(wd, WIOCUFONT, &uf);
X
X	/* restore initial window data (size, location, etc.) */
X	(void)ioctl(wd, WIOCSETD, &save_uw);
X	(void)ioctl(wd, WIOCSETTEXT, &save_utlab);
X
X	/* restore blocking input mode for window */
X	wndelay(wd, 0);
X
X	/* exit with successful return code */
X	wexit(0);
X
X	/* NOTREACHED */
}
X
/*
X * Function name:	Wmpx()
X *
X * Description:		Perform whatever is necessary for windowing routines
X *			to go into "multiplexed" (ie., multi window) mode.
X *
X *			This will relabel the primary window to indicate that
X *			it is multiplexed, and send a message back to the host
X *			telling them about our size.
X *
X * Parameters:		None
X *
X * Return values:	None
X */
void
Wmpx()
{
X	struct uwdata *uwp;
X
X	/* relabel the primary window */
X	wlabel(w_info[1].fd, "Window #1");
X
X	/* send information back to application layer about our window */
X	/* tell it our width and height in both characters */
X	/* and pixels */
X	uwp = &w_info[1].uw;
X	(void)APinform(XtCreate, 1,
X		       (long)(uwp->uw_width/uwp->uw_hs),
X		       (long)(uwp->uw_height/uwp->uw_vs),
X		       (long)uwp->uw_width,
X		       (long)uwp->uw_height);
}
X
/*
X * Function name:	Wunmpx()
X *
X * Description:		Perform whatever is necessary for windowing routines
X *			to return to "unmultiplexed" (ie., single window)
X *			mode.
X *
X *			This will destroy all but the primary window and
X *			re-label the primary window to indicate that we are
X *			unmultiplexed.  It is assumed that the "mpx_flag"
X *			has been reset prior to calling this function.
X *
X * Parameters:		None
X *
X * Return values:	None
X */
void
Wunmpx()
{
X	int i;	/* loop index */
X
X	/* close all but the primary window */
X	for (i = 2; i <= MAXW; i++)
X	{
X		if (w_info[i].fd != -1)
X			(void)Wdestroy(i);
X	}
X
X	/* relabel the primary window */
X	wlabel(w_info[1].fd, "Not Multiplexed");
}
X
/* User mouse data structure.  This configuration causes any button */
/* depressions on the mouse to be reported */
static struct umdata mstat =
X	{
X		MSDOWN,
X		0,0,0,0,
X		NULL
X	};
X
/*
X * Function name:	sigwind(sig)
X *
X * Description:		Handler for changes to windows.
X *
X *			This function will be called by the operating system
X *			whenever the is a change to a window (ie., resize,
X *			window select, etc.)
X *
X *			It is also called by other routines in this file to
X *			reset the window information when something changes.
X *
X * Parameters:		sig	signal number causing call (SIGWIND)
X *
X * Return values:	None
X */
/* ARGSUSED */
static int
sigwind(sig)
int sig;	/* signal number */
{
X	struct uwdata uw;	/* window data structure */
X
X	/* reset the signal */
X	(void)signal(SIGWIND, sigwind);
X
X	/* get file descriptor of currently selected window */
X	curw_fd = wgetsel();
X
X	/* set file descriptor bit map */
X	wind_fds = 1 << curw_fd;
X
X	/* grab current window number corresponding to descriptor */
X	Wcurrent = findwnum(curw_fd);
X
X	/* capture mouse "squeaks" in this window */
X	wsetmouse(curw_fd, &mstat);
X
X	/* get current copy of the window data */
X	(void)ioctl(curw_fd, WIOCGETD, &uw);
X
X	/* see if we need to inform the application layer about something... */
X	if (mpx_flag && w_info[Wcurrent].inform)
X	{
X		if (w_info[Wcurrent].uw.uw_width != uw.uw_width
X		 || w_info[Wcurrent].uw.uw_height != uw.uw_height)
X		{
X
X			/* inform application layer of our reshaping. */
X			/* tell it our width and height in both characters */
X			/* and pixels */
X			(void)APinform(XtReshape, Wcurrent,
X				       (long)(uw.uw_width/uw.uw_hs),
X				       (long)(uw.uw_height/uw.uw_vs),
X				       (long)uw.uw_width,
X				       (long)uw.uw_height);
X		}
X	}
X
X	/* save updated copy of data */
X	w_info[Wcurrent].uw = uw;
}
X
/*
X * Function name:	Wcreate(n, orig_x, orig_y, corn_x, corn_y, inform, sc)
X *
X * Description:		Creates a new window.  The window number to create
X *			is passed in.
X *
X * Parameters:		n	window number to create, -1 if unknown
X *			orig_x	x-coordinate to place upper left corner
X *			orig_y	y-coordinate to place upper left corner
X *			corn_x	x-coordinate to place lower right corner
X *			corn_y	y-coordinate to place lower right corner
X *			inform	if not 0, inform application layer about
X *				create, else keep quiet
X *			nc	if not 0, don't make the new window current
X *
X * Note:		If all of the above coordinates are 0, a default
X *			window location will be chosen.
X *
X * Return values:	-1	unable to create window
X *			else	window number
X */
int
Wcreate(n, orig_x, orig_y, corn_x, corn_y, inform, nc)
int	n;
long	orig_x, orig_y, corn_x, corn_y;
int	inform, nc;
{
X	int		Ocurrent;	/* copy of old Wcurrent */
X	struct ufdata	uf;		/* user font data */
X	struct uwdata	uw;		/* user window data */
X	unsigned short	wflags;		/* window configuration flags */
X	register int	wd;		/* file descriptor of window created */
X	int		rc;		/* return code storage */
X	char	buf[80];		/* text string buffer */
X
X	if (nc)
X		Ocurrent = Wcurrent;	/* save for later use */
X
X	/* if window number is unknown, try to find one */
X	if (n == -1)
X		n = findwnum(-1);
X
X	if (n < 1 || n > MAXW)
X		/* invalid window number, can't create */
X		return(-1);
X
X	if (w_info[n].fd != -1)
X		/* window already exists */
X		return(n);
X
X	/* set flag to allow window to be resized */
X	wflags = BORDRESIZE;
X
X	/* if this is not the primary window, allow window to be deleted */
X	if (n != 1)
X		wflags |= BORDCANCEL;
X
X	/* create a small window (2 lines by 20 columns) at a default */
X	/* location based upon the window number */
X	wd = wcreate(2+2*(n-1), 4*(n-1), 2, 20, wflags);
X	if (wd < 0)
X		/* couldn't create requested window */
X		return(-1);
X
X	/* window created, store in info structure */
X	w_info[n].fd = wd;
X
X	/* clear indicator to avoid telling application layer about us (yet) */
X	w_info[n].inform = 0;
X
X	/* supply a window name */
X	if (n == 1)
X		/* window 1 is created before being multiplexed */
X		(void)sprintf(buf, "Not Multiplexed");
X	else
X		/* windows other than 1 can only be created when multiplexed */
X		(void)sprintf(buf, "Window #%d", n);
X	wlabel(wd, buf);
X
X	/* zap "command" and "prompt" areas for window */
X	wcmd(wd, "");
X	wprompt(wd, "");
X
X	/* load the default font into the default slot */
X	uf.uf_slot = 0;
X	(void)strcpy(uf.uf_name, DEFAULT_FONT);
X	rc = ioctl(wd, WIOCLFONT, &uf);
X	if (rc < 0)
X	{
X		wprintf(wd, "couldn't load mini font (rc=%d)\n", rc);
X	}
X
X	/* switch to the new font */
X	wputc(wd, '\016');
X
X	(void)ioctl(wd, WIOCGETD, &uw);
X	if (orig_x || orig_y || corn_x || corn_y)
X	{
X		/* use the specified coordinates */
X		uw.uw_width = corn_x - orig_x;
X		uw.uw_height = corn_y - orig_y;
X		uw.uw_x = orig_x;
X		uw.uw_y = orig_y;
X	}
X	else
X	{
X		/* shape the window to 16 lines x 80 columns */
X		uw.uw_height = uw.uw_vs * 16;
X		uw.uw_width = uw.uw_hs * 80;
X	}
X	(void)ioctl(wd, WIOCSETD, &uw);
X
X	/* "home" the cursor and clear the window */
X	wgoto(wd, 0, 0);
X	wprintf(wd, "\033[2J");
X	wrefresh(wd);
X
X	/* set non-blocking input mode for window */
X	wndelay(wd, 1);
X
X	/* call signal handler */
X	sigwind(SIGWIND);
X
X	/* get a final copy of the window information */
X	(void)ioctl(wd, WIOCGETD, &uw);
X
X	/* save a copy of the window information for later reference */
X	w_info[n].uw = uw;
X
X	/* inform application layer about our creation now */
X	if (inform)
X	{
X		/* inform application layer of our creation. */
X		/* tell it our width and height in both characters */
X		/* and pixels */
X		(void)APinform(XtCreate, n,
X			       (long)(uw.uw_width/uw.uw_hs),
X			       (long)(uw.uw_height/uw.uw_vs),
X			       (long)uw.uw_width,
X			       (long)uw.uw_height);
X	}
X
X	/* set indicator for informing application layer about later changes */
X	w_info[n].inform = 1;
X
X	if (nc)		/* if requested, restore old Wcurrent */
X		Wselect(Ocurrent);
X
X	/* all done creating window */
X	return(n);
}
X
/*
X * Function name:	Wdestroy(n)
X *
X * Description:		Destroy the requested window.
X *
X * Parameters:		n	window number to destroy
X *
X * Return values:	-1	error
X *			0	requested window destroyed (or already gone)
X */
int
Wdestroy(n)
int	n;
{
X	int wd;
X
X	if (n < 2 || n > MAXW)
X		/* invalid window number, can't delete */
X		return(-1);
X
X	/* grab file descriptor of this window */
X	wd = w_info[n].fd;
X
X	if (wd == -1)
X		/* window doesn't exist */
X		return(0);
X
X	/* don't inform application layer about our destruction (yet) */
X	w_info[n].inform = 0;
X
X	/* tell OS to kill window */
X	wdelete(wd);
X
X	/* remove entry from table */
X	w_info[n].fd = -1;
X
X	/* call signal handler */
X	sigwind(SIGWIND);
X
X	/* inform application layer of our destruction. */
X	if (mpx_flag)
X		(void)APinform(XtDelete, n, 0L, 0L, 0L, 0L);
X
X	/* window destroyed */
X	return(0);
}
X
/*
X * Function name:	Wselect(n)
X *
X * Description:		select the specified window as the current
X *			input window.
X *
X * Parameters:		n	window number to select
X *
X * Return values:	0	succesfully selected
X *			-1	error
X */
X
int
Wselect(n)
int	n;	/* window number to select */
{
X	if (n == Wcurrent)
X		/* If selecting the window already current, we're done! */
X		return(0);
X
X	if (n < 1 || n > MAXW)
X		/* invalid window number, can't select */
X		return(-1);
X
X	if (w_info[n].fd == -1)
X		/* window doesn't exist */
X		return(-1);
X
X	/* select the window */
X	wselect(w_info[n].fd);
X
X	/* call the signal handler to do its thing */
X	sigwind(SIGWIND);
X
X	return(0);
}
X
/*
X * Function name:	Wshape(n, orig_x, orig_y, corn_x, corn_y)
X *
X * Description:		Shape/move the specified window
X *
X * Parameters:		n	window number to shape/move
X *			orig_x	x-coordinate to place upper left corner
X *			orig_y	y-coordinate to place upper left corner
X *			corn_x	x-coordinate to place lower right corner,
X *				if -1 width will remain unaffected
X *			corn_y	y-coordinate to place lower right corner,
X *				if -1 height will remain unaffected
X *
X * Return values:	0	succesfully shaped/moved
X *			-1	error
X *			
X */
X
int
Wshape(n, orig_x, orig_y, corn_x, corn_y)
int	n;
long	orig_x, orig_y, corn_x, corn_y;
{
X	struct uwdata	uw;	/* user window data */
X	int	Ocurrent;	/* original current window number */
X	int	wd;		/* window file descriptor */
X
X	if (n < 1 || n > MAXW)
X		/* invalid window number, can't select */
X		return(-1);
X
X	wd = w_info[n].fd;
X
X	if (wd == -1)
X		/* window doesn't exist */
X		return(-1);
X
X	/* save the current window number */
X	Ocurrent = Wcurrent;
X
X	/* read, set, and update the window parameters */
X	(void)ioctl(wd, WIOCGETD, &uw);
X	if (corn_x != -1) uw.uw_width = corn_x - orig_x;
X	if (corn_y != -1) uw.uw_height = corn_y - orig_y;
X	uw.uw_x = orig_x;
X	uw.uw_y = orig_y;
X	(void)ioctl(wd, WIOCSETD, &uw);
X
X	/* call the signal handler to do its thing */
X	sigwind(SIGWIND);
X
X	/* if the current window number changed during the reshaping, */
X	/* restore the old window as the current window */
X	if (Wcurrent != Ocurrent)
X		(void)Wselect(Ocurrent);
X
X	return(0);
}
X
/*
X * Function name:	Wtop(n)
X *
X * Description:		Pop specified window to the top of the window stack
X *
X * Parameters:		n	window number to pop
X *
X * Return values:	0	succesfully popped to top
X *			-1	error
X */
X
int
Wtop(n)
int	n;
{
X	if (n < 1 || n > MAXW)
X		/* invalid window number, can't select */
X		return(-1);
X
X	if (w_info[n].fd == -1)
X		/* window doesn't exist */
X		return(-1);
X
X	/* We can't do this:  Popping the window to the top also selects it. */
X
X	return(-1);
}
X
/*
X * Function name:	Wbottom(n)
X *
X * Description:		Push specified window to bottom of window stack.
X *
X * Parameters:		n	window number to push
X *
X * Return values:	0	succesfully pushed to bottom
X *			-1	error
X *			
X */
X
int
Wbottom(n)
int	n;
{
X	if (n < 1 || n > MAXW)
X		/* invalid window number, can't select */
X		return(-1);
X
X	if (w_info[n].fd == -1)
X		/* window doesn't exist */
X		return(-1);
X
X	/* We have no way to do this! */
X
X	return(-1);
}
X
/*
X * Function name:	Winput(n, buf, nbytes)
X *
X * Description:		Return any available input from current window.
X *
X * Parameters:		n	pointer to store window number providing data
X *			buf	buffer in which to store data
X *			nbytes	maximum number of bytes return
X *
X * Return values:	number of bytes of input returned
X *			
X */
int
Winput(n, buf, nbytes)
int	*n;	/* returned window with available data */
char	*buf;	/* buffer in which to place data */
int	nbytes;	/* max number of bytes to read */
{
X	int	c;	/* single character buffer */
X	int	count;	/* number of characters read */
X	int	xloc, yloc, buttons, reason;	/* mouse data */
X	int	wd, wn;	/* window descriptor and number */
X
X	/* no characters read yet */
X	count = 0;
X
X	/* save current window file descriptor and number */
X	wd = curw_fd;
X	wn = Wcurrent;
X
X	/* loop while we still want more data */
X	while (count < nbytes)
X	{
X		c = wgetc(wd);
X
X		switch (c)
X		{
X		case -1:
X			/* no more data */
X			goto done;
X
X		case s_Exit:	/* shift-EXIT button on keyboard */
X
X			/* user wants to EXIT */
X
X			/* if user has already requested to exit but */
X			/* we are still multiplexed, something is hung. */
X			/* force multiplex flag to false. */
X			if (user_exit && mpx_flag)
X				mpx_flag = 0;
X
X			/* set flag to request exit */
X			user_exit = 1;
X
X			/* if we are still multiplexed, inform application */
X			/* layer that we wish to go down! */
X			if (mpx_flag)
X				(void)APinform(XtExit, wn, 0L, 0L, 0L, 0L);
X
X			goto done;
X		
X		case Mouse:
X			/* mouse has been clicked, see what's up */
X			wreadmouse(wd, &xloc, &yloc, &buttons, &reason);
X
X			/* if the right button has been pressed... */
X			if ((buttons & 1) && (reason & MSDOWN))
X			{
X				/* if multiplexed, try to create a new window */
X				if (mpx_flag)
X					(void)Wcreate(-1, 0L, 0L, 0L, 0L, 1, 0);
X				goto done;
X			}
X			break;
X
X		case s_Cancl:	/* shift-CANCL or "close" icon */
X
X			/* user wants to delete current window */
X			if (wn == 1)
X			{
X				wprintf(wd, "Can't delete primary window!\n");
X				break;
X			}
X			(void)Wdestroy(wn);
X			/* can't do anything else with this window! */
X			goto done;
X
X		default:
X
X			/* save the key if it is a normal ASCII Char */
X			if (c >= 0 && c < 128)
X			{
X				*buf++ = c;
X				count++;
X			}
X			break;
X		}
X	}
X
done:
X	/* return window number and count of characters */
X	*n = wn;
X	return(count);
}
X
/*
X * Function name:	Woutput(n, buf, nbytes)
X *
X * Description:		Output information in window.
X *
X * Parameters:		n	window to receive output
X *			buf	buffer of data to output
X *			nbytes	number of bytes to output
X *
X * Return values:	-1	- unsuccessful output
X *			1	- successful output
X */
int
Woutput(n, buf, nbytes)
int	n;	/* window number in which to output data */
char	*buf;	/* data to output */
int	nbytes;	/* number of bytes from "buf" to output */
{
X	int	wd;	/* file descriptor for window */
X
X	if (n < 1 || n > MAXW)
X		/* invalid window number */
X		return(-1);
X
X	wd = w_info[n].fd;
X
X	/* window not opened, let's try to open it! */
X	if (wd == -1)
X	{
X		(void)Wcreate(n, 0L, 0L, 0L, 0L, 1, 1);
X
X		wd = w_info[n].fd;
X
X		if (wd == -1)
X			/* can't create it, give up */
X			return(-1);
X	}
X
X	/* output data 1 character at a time */
X	while (nbytes-- > 0)
X		wputc(wd, *(buf++));
X
X	/* refresh the window */
X	wrefresh(wd);
X
X	return(1);
}
X
/*
X * Function name:	findwnum(wfd)
X *
X * Description:		Finds the window number corresponding to the window
X *			file descriptor passed in.  If a -1 is passed in as
X *			the file descriptor, an unused but available window
X *			number is returned.
X *
X * Parameters:		wfd	file descriptor to locate
X *
X * Return values:	-1	- cannot locate requested information
X *			n	- window number corresponding to "wfd"
X */
static int
findwnum(wfd)
int	wfd;	/* file descriptor to locate */
{
X	register int i;	/* loop index */
X
X	/* locate requested window */
X	for (i = 1; i <= MAXW; i++)
X		if (w_info[i].fd == wfd) return(i);
X
X	return(-1);
}
SHAR_EOF
chmod 0644 xtclient/window.c ||
echo 'restore of xtclient/window.c failed'
Wc_c="`wc -c < 'xtclient/window.c'`"
test 19471 -eq "$Wc_c" ||
	echo 'xtclient/window.c: original size 19471, current size' "$Wc_c"
fi
# ============= xtclient/window.h ==============
if test -f 'xtclient/window.h' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient/window.h (File already exists)'
else
echo 'x - extracting xtclient/window.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient/window.h' &&
/*
X * File name:	window.h
X *
X * Description:	External function and data declarations for window.c
X *
X * Author:	Merlin J. Mathesius
X */
X
#define MAXW 7	/* maximum allowable window number (numbers start at 1) */
X
Xextern void	Winit(), Wshutdown();
Xextern int	Wcreate(), Wdestroy();
Xextern int	Winput(), Woutput();
Xextern int	Wselect(), Wshape(), Wtop(), Wbottom();
Xextern void	Wmpx(), Wunmpx();
X
Xextern int	wind_fds; /* bit map with current window file descriptor */
Xextern int	Wready;   /* indicates unprocessed keyboard data remains */
SHAR_EOF
chmod 0644 xtclient/window.h ||
echo 'restore of xtclient/window.h failed'
Wc_c="`wc -c < 'xtclient/window.h'`"
test 536 -eq "$Wc_c" ||
	echo 'xtclient/window.h: original size 536, current size' "$Wc_c"
fi
# ============= xtclient/xtclient.c ==============
if test -f 'xtclient/xtclient.c' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient/xtclient.c (File already exists)'
else
echo 'x - extracting xtclient/xtclient.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient/xtclient.c' &&
/*
X * File name:	xtclient.c
X *
X * Description:	High level control for UNIX-PC "xt/layers" system.
X *
X * Author:	Merlin J. Mathesius
X *
X * Contents:	main()		main routine
X *		non_mpx()	manage unmultiplexed connection
X *
X * Data:	ilog_fd		input log file descriptor
X * 		olog_fd		output log file descriptor
X *		mpx_flag	multiplexing flag
X *		user_exit	user exit flag
X */
X
#include <stdio.h>
#include <fcntl.h>
#include <select.h>
X
#include "xtclient.h"
#include "phone.h"
#include "phys.h"
#include "datalink.h"
#include "network.h"
#include "session.h"
#include "appl.h"
#include "window.h"
X
int	ilog_fd = -1;	/* input log file descriptor (-1 = not logging) */
int	olog_fd = -1;	/* output log file descriptor (-1 = not logging) */
int	mpx_flag = 0;	/* multiplexing flag (1 = multiplexed) */
int	user_exit = 0;	/* user exit flag (1 = user requested exit) */
X
static int	non_mpx();
static void	usage();
X
Xextern void	exit();		/* not declared in any header file */
Xextern unsigned sleep();	/* not declared in any header file */
X
Xextern int	optind;		/* not declared in any header file */
Xextern char	*optarg;	/* not declared in any header file */
Xextern int	readfds;	/* bit map of read file descriptors */
X
/*
X * Function name:	main()
X *
X * Description:		"xt/layers" main control and argument processing.
X */
X
main(argc, argv)
int	argc;
char	*argv[];
{
X	char	*line = NULL;	/* alternate device to use for connection */
X	char	*speed = NULL;	/* alternate line speed for connection */
X	int	c;		/* getopt() return character */
X	int	log = 0;	/* logging flag */
X
X	/* process the arguments */
X	while ((c = getopt(argc, argv, "l:s:x")) != EOF)
X	{
X		switch (c)
X		{
X		case 'l':
X			line = optarg;
X			break;
X		case 's':
X			speed = optarg;
X			break;
X		case 'x':
X			log = 1;
X			break;
X		case '?':
X			usage(argv[0]);
X			break;
X		}
X	}
X
X	/* there must be exactly 1 argument left (the phone number) */
X	if (argc - optind != 1)
X		usage(argv[0]);
X
X	/* has logging been requested? */
X	if (log)
X	{
X		(void)printf("Logging is ON!\n");
X		ilog_fd = open(".input_log", O_WRONLY|O_CREAT|O_TRUNC, 0644);
X		olog_fd = open(".output_log", O_WRONLY|O_CREAT|O_TRUNC, 0644);
X	}
X
X	/* initialize the application layer routines */
X	APinit();
X
X	(void)APind(1, "Dialing \"", -1);
X	(void)APind(1, argv[optind], -1);
X	(void)APind(1, "\"\n", -1);
X
X	/* attempt to call the specified phone number */
X	if (connect(argv[optind], line, speed) < 0)
X	{
X		(void)APind(1, "Failed to connect,  Exiting...\n", -1);
X		(void)sleep((unsigned)5);
X		APterm();
X	}
X
X	(void)APind(1, "Connected!\n", -1);
X
X	/* enter main loop for duration of connection */
X	while (isconnected() && !user_exit)
X	{
X		/* if we are not multiplexed, use the basic routine */
X		if (!mpx_flag)
X		{
X			non_mpx();
X		}
X		else
X		{
X			/* switch over to multiplexed mode */
X
X			(void)APind(1, "Going multiplexed...\n", -1);
X
X			/* initialize all the network layers... */
X			PHinit();
X			DLinit();
X			SESinit();
X			NETinit();
X
X			/* inform application layer we are multiplexed */
X			APmpx();
X
X			/* Call the Data Link Layer.
X			 * This does not return until the user requests
X			 * to exit multiplexed mode, or the phone connection
X			 * is terminated.
X			 */
X			DataLinkLayer();
X
X			(void)APind(1, "Exiting multiplexed mode...\n", -1);
X
X			/* make sure multiplexing flag really is unset */
X			mpx_flag = 0;
X
X			/* inform application layer we are unmultiplexed */
X			APunmpx();
X
X			/* reset user exit flag since we are only exiting */
X			/* multiplexed mode (next "exit" will shut us down) */
X			user_exit = 0;
X		}
X	}
X
X	if (isconnected())
X	{
X		(void)APind(1, "\nDisconnecting...\n", -1);
X	}
X	else
X	{
X		(void)APind(1, "\nDisconnected...\n", -1);
X	}
X
X	/* force the phone connection to hang up (if it hasn't already) */
X	(void)disconnect();
X
X	/* if the log files were opened, close them */
X	if (ilog_fd != -1) (void)close(ilog_fd);
X	if (olog_fd != -1) (void)close(olog_fd);
X
X	/* tell the application layer exit - this will not return */
X	APterm();
X
X	/* NOTREACHED */
X
X	exit(0);
}
X
/*
X * Function name:	non_mpx()
X *
X * Description:		Simplistic terminal emulator mode.  Allows user to
X *			to communicate with host computer prior to invoking
X *			the "xt/layers" protocol.  No error detection is
X *			possible.
X *
X * Return values:	None.
X *			
X */
static int
non_mpx()
{
X	struct timeval timeout;	/* timeout value structure */
X	int phonemsk;		/* bit map of phone device only */
X	int rc;			/* return code */
X	int wn;			/* window number */
X	char buf[128];		/* I/O buffer */
X
X	/* set timeout every 10 seconds to check phone connection */
X	timerclear(&timeout);
X	timeout.tv_sec = 10;
X
X	/* set the bit corresponding to the phone's file descriptor */
X	phonemsk = 1 << phone_fd;
X
X	do {
X		/* "or" the bit masks for the phone device and */
X		/* window/keyboard devices */
X		readfds = phonemsk | wind_fds;
X
X		/* pass the read bit masks and timeout structure to */
X		/* select().  this system call will return if any */
X		/* of the file descriptors in the bit mask have data */
X		/* available for reading, or if the timeout occurs */
X
X		rc = select(16, &readfds, 0, 0, &timeout);
X		if (rc < 0) continue;	/* select() caught an interrupt */
X
X		/* at this point, the bit mask has been modified by select() */
X		/* to contain only those file descriptors that have data */
X		/* ready for reading */
X
X		/* check if input coming from phone */
X		if (readfds & phonemsk)
X		{
X			/* grab input from phone line */
X			rc = read(phone_fd, buf, 128);
X			if (rc > 0)
X			{
X				/* log input if logging is turned on */
X				if (ilog_fd != -1)
X					(void)write(ilog_fd, buf, (unsigned)rc);
X
X				/* send data to screen */
X				(void)APind(1, buf, rc);
X			}
X		}
X
X		/* check if input coming from keyboard, or a reply */
X		/* is pending from the application layer */
X		if (readfds & wind_fds || APreply_cnt)
X		{
X			/* request pending data from the application layer */
X			rc = APreq(&wn, buf, 128);
X			if (rc > 0)
X			{
X				/* send data to phone */
X				(void)write(phone_fd, buf, (unsigned)rc);
X
X				/* log output if logging is turned on */
X				if (olog_fd != -1)
X					(void)write(olog_fd, buf, (unsigned)rc);
X			}
X		}
X
X	/* continue looping while the following are all true: */
X	/*  1. the phone connection is still up */
X	/*  2. the user has not requested to exit */
X	/*  3. we have not yet entered multiplexed mode */
X	} while (isconnected() && !user_exit && !mpx_flag);
X
X	return;
}
X
/*
X * Function name:	usage()
X *
X * Description:		Display a "usage" message and exit.  Called when
X *			user has invoked xtclient incorrectly.
X *
X * Parameters:		progname	- name of program
X *
X * Return values:	Never returns.
X */
static void
usage(progname)
char	*progname;
{
X	(void)fprintf(stderr,
X		"Usage: %s [ -x ] [ -l <line> ] [ -s <speed> ] phone-number\n",
X		progname);
X	exit(1);
}
SHAR_EOF
chmod 0644 xtclient/xtclient.c ||
echo 'restore of xtclient/xtclient.c failed'
Wc_c="`wc -c < 'xtclient/xtclient.c'`"
test 6728 -eq "$Wc_c" ||
	echo 'xtclient/xtclient.c: original size 6728, current size' "$Wc_c"
fi
# ============= xtclient/xtclient.h ==============
if test -f 'xtclient/xtclient.h' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient/xtclient.h (File already exists)'
else
echo 'x - extracting xtclient/xtclient.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient/xtclient.h' &&
/*
X * File name:	xtclient.h
X *
X * Description:	External data declarations for xtclient.c
X *
X * Author:	Merlin J. Mathesius
X */
X
Xextern int ilog_fd, olog_fd;	/* input and output log file descriptors */
Xextern int mpx_flag;		/* multiplexing flag */
Xextern int user_exit;		/* user has selected "exit"... */
SHAR_EOF
chmod 0644 xtclient/xtclient.h ||
echo 'restore of xtclient/xtclient.h failed'
Wc_c="`wc -c < 'xtclient/xtclient.h'`"
test 304 -eq "$Wc_c" ||
	echo 'xtclient/xtclient.h: original size 304, current size' "$Wc_c"
fi
# ============= pty/Files ==============
if test ! -d 'pty'; then
    echo 'x - creating directory pty'
    mkdir 'pty'
fi
if test -f 'pty/Files' -a X"$1" != X"-c"; then
	echo 'x - skipping pty/Files (File already exists)'
else
echo 'x - extracting pty/Files (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'pty/Files' &&
XSize
Name
Remove
Install
Files
MKflop
Makefile
pty.o
README.3b1
READ_ME
Remove.orig
Version
number-ptys.h
pty.c
pty.h
SHAR_EOF
chmod 0644 pty/Files ||
echo 'restore of pty/Files failed'
Wc_c="`wc -c < 'pty/Files'`"
test 118 -eq "$Wc_c" ||
	echo 'pty/Files: original size 118, current size' "$Wc_c"
fi
# ============= pty/Install ==============
if test -f 'pty/Install' -a X"$1" != X"-c"; then
	echo 'x - skipping pty/Install (File already exists)'
else
echo 'x - extracting pty/Install (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'pty/Install' &&
# Eric H. Herrin II
# University of Kentucky Mathematical Sciences
# eric at ms.uky.edu, !cbosgd!ukma!eric
#
# Install script for System V Pty driver
X
MODULE=pty
X
./Reinstall || exit 1
X
./Makedev
X
if grep -l ${MODULE} /etc/lddrv/InstDrv
then
X	echo "Entry already in InstDrv"
X	exit 1
Xelse
X	echo "Putting entry into InstDrv"
fi
X
# put an entry in /etc/lddrv/InstDrv for ${MODULE}
V=`cat Version`
Xecho "Name=${MODULE} driver: Version ${V}" 	>> /etc/lddrv/InstDrv
Xecho "File=${MODULE}"     			>> /etc/lddrv/InstDrv
Xecho "Comment=Pseudo tty driver (ptys!!)" 	>> /etc/lddrv/InstDrv
X
# load the ${MODULE} at boot time
Xecho ${MODULE} >> /etc/lddrv/drivers
X
Xecho "Pseudo tty drivers are now installed"
Xexit 0
X
X
SHAR_EOF
chmod 0755 pty/Install ||
echo 'restore of pty/Install failed'
Wc_c="`wc -c < 'pty/Install'`"
test 699 -eq "$Wc_c" ||
	echo 'pty/Install: original size 699, current size' "$Wc_c"
fi
# ============= pty/MKflop ==============
if test -f 'pty/MKflop' -a X"$1" != X"-c"; then
	echo 'x - skipping pty/MKflop (File already exists)'
else
echo 'x - extracting pty/MKflop (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'pty/MKflop' &&
Xecho "Insert floppy disk and press return"
read junk
/usr/bin/fdfmt.nl
find `cat Files` -print | cpio -oBc > /dev/fp021
SHAR_EOF
chmod 0755 pty/MKflop ||
echo 'restore of pty/MKflop failed'
Wc_c="`wc -c < 'pty/MKflop'`"
test 120 -eq "$Wc_c" ||
	echo 'pty/MKflop: original size 120, current size' "$Wc_c"
fi
# ============= pty/Makedev ==============
if test -f 'pty/Makedev' -a X"$1" != X"-c"; then
	echo 'x - skipping pty/Makedev (File already exists)'
else
echo 'x - extracting pty/Makedev (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'pty/Makedev' &&
MODULE=pty
MODULEDEVNO=`/etc/masterupd -c ${MODULE}`
if [  ! ${MODULEDEVNO} ]
then 
X	echo "${MODULEDEVNO} not in /etc/master file"
X	exit 1
fi
# NOTE!!!!!!!!!!!!!!
# To change the number of ptys, change the value in number-ptys.h.
# VVVVVVV
# get the assigned device number
PTYCNT=`grep NUMBER_OF_PTYS number-ptys.h | \
sed -e "s/#define//" -e "s/NUMBER_OF_PTYS//" -e "s/ //g"`
Xecho "PTYCNT=$PTYCNT" > Remove
cat Remove.orig >> Remove
# make the pty device files
Xecho "Making pty pseudo device files"
cnt=0
for x in p q r s t u v w x y z
do
X	for y in 0 1 2 3 4 5 6 7 8 9 a b c d e f
X	do
X		i=$x$y
X		if [ $cnt -ge ${PTYCNT} ] 
X		then 
X			break
X		fi
X		/etc/mknod /dev/pty$i c ${MODULEDEVNO}\
X `expr $cnt + $PTYCNT` || :
X		/etc/mknod /dev/tty$i c ${MODULEDEVNO} $cnt || :
X		chown root /dev/tty$i /dev/pty$i
X		chgrp root /dev/tty$i /dev/pty$i
X		chmod 0666 /dev/tty$i /dev/pty$i
X		cnt=`expr $cnt + 1`
X	done
done
SHAR_EOF
chmod 0755 pty/Makedev ||
echo 'restore of pty/Makedev failed'
Wc_c="`wc -c < 'pty/Makedev'`"
test 905 -eq "$Wc_c" ||
	echo 'pty/Makedev: original size 905, current size' "$Wc_c"
fi
# ============= pty/Makefile ==============
if test -f 'pty/Makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping pty/Makefile (File already exists)'
else
echo 'x - extracting pty/Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'pty/Makefile' &&
#       Eric H. Herrin II
#	University of Kentucky Mathematical Sciences Laboratories
# 	915 Patterson Office Tower
#	University of Kentucky
#	Lexington, KY 40506
#	eric at ms.uky.edu, ..!cbosgd!ukma!eric 
DEFS= -DSELECT # -DDEBUGD
CFLAGS= -O -c ${DEFS}
XSHELL= /bin/sh
X
.c.o:
X	${CC} ${CFLAGS} $<
X
all: pty.o
X
spty.o:	pty.c
X	${CC} ${CFLAGS} pty.c
X	mv pty.o spty.o
X
pty.o:	interface.o linesw.o spty.o select.o
X	ld -r -n -o pty.o interface.o linesw.o spty.o select.o
X
X
install: all
X	${SHELL} ./Install
X
clean: 
X	rm -f pty.o
X
clobber: clean
X	${SHELL} ./Remove
X
remove: clobber
SHAR_EOF
chmod 0644 pty/Makefile ||
echo 'restore of pty/Makefile failed'
Wc_c="`wc -c < 'pty/Makefile'`"
test 570 -eq "$Wc_c" ||
	echo 'pty/Makefile: original size 570, current size' "$Wc_c"
fi
# ============= pty/Name ==============
if test -f 'pty/Name' -a X"$1" != X"-c"; then
	echo 'x - skipping pty/Name (File already exists)'
else
echo 'x - extracting pty/Name (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'pty/Name' &&
Pty Driver Version 2.1 
SHAR_EOF
chmod 0644 pty/Name ||
echo 'restore of pty/Name failed'
Wc_c="`wc -c < 'pty/Name'`"
test 24 -eq "$Wc_c" ||
	echo 'pty/Name: original size 24, current size' "$Wc_c"
fi
# ============= pty/README.3b1 ==============
if test -f 'pty/README.3b1' -a X"$1" != X"-c"; then
	echo 'x - skipping pty/README.3b1 (File already exists)'
else
echo 'x - extracting pty/README.3b1 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'pty/README.3b1' &&
README: Eric H. Herrin II
X	University of Kentucky Mathematical Sciences Laboratories
X 	915 Patterson Office Tower
X	University of Kentucky
X	Lexington, KY 40506
X	eric at ms.uky.edu, ..!cbosgd!ukma!eric 
X
Version 2.1
X
Thanks to 
1.  Mike "Ford" Ditto
X    kenobi!ford at crash.CTS.COM, ...!crash!kenobi!ford
X    for his bug fix in the ptyrelease routine.
2.  Michael Bloom 
X    mb at ttidca.tti.com
X    for his bug fix to the master read routine in the original driver.
X    I incorporated this fix and it seems to work fine.
X
This directory contains the PD pty driver for System V, modified for
use with the AT&T UnixPC or Convergent Technologies Safari 4 computers,
running Version 3.51 of the UNIX System V OS (it may also work on
Xearlier versions, but I have no way of verifying this).  Anyone using
this driver should have no problems, but I will provide little support.
Questions should be sent to the above address, either with ground mail
or real (e-)mail.
X
X
This README is intended to mark the changes made to the PD pty driver to
satisfy the author's request.  It was not easy or feasible to clearly mark
Xevery change in the code, thus it was decided that an explanation of the
procedure would probably be enough.  A brief introduction to UnixPC 
device drivers is followed by the list of changes made.  A couple of
hacks will also be explained.
X
NOTE: The #ifdef DEBUG statements use eprintf() instead of printf().
X      This puts any messages into the error icon's queue of system 
X      errors (the icon is the !! icon at the top of the console).
X
X
UnixPC device drivers:
X
X	The UnixPC has a different kind of device driver from other 
XSystem V machines.  They can be loaded while the machine is running or
at boot time, but are always linked into the OS while the kernel is
active.  However nice this may be, there ARE some problems.  
X
X	1.  Loadable device drivers CANNOT communicate with one another.
X	    That is, one driver cannot use a data structure defined in 
X	    another driver (IE. they are not in the same identifier
X	    name space).  
X	2.  Conf.c doesn't exist, it is redone by the /etc/lddrv -av 
X	    program and relinked into the kernel.  Thus, one can't
X	    declare common structures this way.
X	
X
Changes to the PD pty driver:
X
X	The following changes (hacks?) were made to the PD pty driver for
the purpose of making it usable on the UnixPC.
X
X	   Problem 1 & 2 influenced me to try to make a single driver
X	   (there were two, ptm and pts).  How could one do this?
X	   My solution (and I would be very interested if you can
X	   think of a better one) was to create the slave devices
X	   /dev/tty[p-z][0-f] with minor numbers 0-(PTYCNT/2-1) and
X	   master devices /dev/pty[p-z][0-f] with minor numbers 
X	   (PTYCNT/2)-(PTYCNT-1).  Major numbers of both types of devices
X	   are the same. I can then simply define a macro to determine 
X	   whether the dev_t passed to the driver was a slave or master 
X	   pty.  Once determined, I can perform the appropriate duties.  
X	   Also, it was more readable to merge the ptm and pts modules 
X	   into a single set of pty[open, close, ioctl, read, write]
X	   routines.  I added a release routine so that the kernel will
X	   know the device has properly released if one deallocates
X	   the driver. 
X	   Another modification was the addition of ptystate[], which
X	   holds the MRWAIT, MWWAIT, MOPEN flags.  This was necessary
X	   because the original author insisted upon using 3 UNUSED
X	   bits in the t_state field of the tty.  The UnixPC does not
X	   have any free bits here.
X	   A check for TTIOW was added due to the fix by Michael
X	   Bloom in the master section of the ptyread() routine.  Note 
X	   his original fixes were for the original pty driver and
X	   most of the changes were already incorporated into this driver.
X
Making alterations to the number of ptys, etc.
X	   The number of ptys is defined in the file number-ptys.h.  This 
X	   number should not exceed the maximum minor device number divided by
X	   two.  Ie. a maximum minor device number of 128 would allow
X	   a maximum of 64 ptys.  It is currently defined at only 32, but
X	   I believe this is quite liberal, especially for a machine as
X	   small as a 3b1.  One could load the driver multiple times by
X	   calling it a different name in the /etc/master file.  One could
X	   have the first 64 ptys with major number 10, the next 64 with
X	   major number 11, etc.  I think 64 should do fine for any reasonable
X	   UNIX PC user (good grief, how would one use 64 ptys on a max
X   	   5 user machine?  Better yet, how would one get 5 users on the
X  	   thing?  Yuch!).  At any rate, we don't use that many ptys on
X	   a large system with lots of users.... so I really don't see this
X	   as a problem.
X	   
X
Pty driver generation and installation procedure.
X	   Put the number of ptys you want in the file number-ptys.h.
X	   Type "make"
X	   Type "/bin/sh MKflop"
X	   Insert a floppy diskette.
X	   Use the UA to install the diskette.
X	   (you can skip the floppy part and simply run the Install script 
X	   in the same directory the pty.o object is located.  But you
X	   won't be able to uninstall it from the UA.  There is a
X	   Remove script to do this which you will have to run manually.)
X
Acknowledgement:  I realize the usage of a single major device number is
a supreme hack, and I welcome any improvements/solutions.  I do not assume
any responsibility for the changes I have made, nor do I imply any 
liability on the part of the original author.  I include a complete set
of {Install, Remove, etc, etc} scripts so that binary floppies may be
made to be installed by the UnixPC user agent.  I do not assume any
responsibility for these either.  I don't assume any responsibility for
anything even remotely related to this stuff.
X
X
X	    Eric H. Herrin II
X	    University of Kentucky Mathematical Sciences Laboratories
X	    eric at ms.uky.edu, !cbosgd!ukma!eric
X
SHAR_EOF
chmod 0644 pty/README.3b1 ||
echo 'restore of pty/README.3b1 failed'
Wc_c="`wc -c < 'pty/README.3b1'`"
test 5891 -eq "$Wc_c" ||
	echo 'pty/README.3b1: original size 5891, current size' "$Wc_c"
fi
# ============= pty/READ_ME ==============
if test -f 'pty/READ_ME' -a X"$1" != X"-c"; then
	echo 'x - skipping pty/READ_ME (File already exists)'
else
echo 'x - extracting pty/READ_ME (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'pty/READ_ME' &&
This is a pseudo tty driver for system V machines. It works very
similar to ptys on BSD, for instance emacs works fine. To install this
driver you will need to modify your `master' and `dfile' file which
contains your driver specifications. As these vary from machine to machine,
you will have to look up in your manual how to do that. Here is an example
for a sperry s5050 alias ncr tower 32 :
X
Add the following two lines to the driver description section in master:
pts	0	237	244	pts	0	0	28	32	0	tty
ptm	0	37	344	ptm	0	0	29	0	0
X
This says there are max 32 pts devices at major number 28 having associated
tty structures and 0 ptm devices having major number 29 with no associated
data. The number of ptm devices is not configurable, as this depends on the
number of pts's.
X
The following two lines go in the dfile:
pts	0	0	0
ptm	0	0	0
X
Probably you will also want to increase the NCLIST parameter.
X
If your configuration procedure is different, you must change the shell
script mkpty, which is used to create the device nodes in /dev.
X
The ptm devices (/dev/pty[p-z][0-9a-f]) are the controlling ones, everything
written there will show up at the associated pts device
(/dev/tty[p-z][0-9a-f]), as well as erverything which is written on the pts
device will show up on the ptm device. The pts side will accept the usual
termio ioctl calls. The master side is a bit different, as ioctl calls which
normally wait for output to drain flush output. The reason for this funny
behaviour is that otherwise the master side will hang. Also the master side
may be opened only once, further open calls will result in an EBUSY error.
SHAR_EOF
chmod 0644 pty/READ_ME ||
echo 'restore of pty/READ_ME failed'
Wc_c="`wc -c < 'pty/READ_ME'`"
test 1624 -eq "$Wc_c" ||
	echo 'pty/READ_ME: original size 1624, current size' "$Wc_c"
fi
# ============= pty/Reinstall ==============
if test -f 'pty/Reinstall' -a X"$1" != X"-c"; then
	echo 'x - skipping pty/Reinstall (File already exists)'
else
echo 'x - extracting pty/Reinstall (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'pty/Reinstall' &&
# Eric H. Herrin II
# University of Kentucky Mathematical Sciences
# eric at ms.uky.edu, !cbosgd!ukma!eric
#
# Reinstall script for System V Pty driver
set -e
X
MODULE=pty
X
# put the module in the appropriate place
cp ${MODULE}.o /etc/lddrv/${MODULE}.o
X
cd /etc/lddrv
X
# remove the driver if it's already running
# Note that we must call lddrv with the -d twice since it will fail with
# EAGAIN the first time.  This first call removes the system call hooks.
# The second call unloads the driver.
./lddrv -q ${MODULE} && ( ./lddrv -d ${MODULE} || ./lddrv -d ${MODULE} )
X
# delete the old entry in /etc/master
/etc/masterupd -d ${MODULE} 2>/dev/null || :
X
# add the entry to the /etc/master file
/etc/masterupd -a char init release open close read write ioctl ${MODULE}
X
# allocate and load the module
Xecho "Allocating pty module with lddrv"
X
if ./lddrv -av -o ${MODULE}.o ${MODULE}
then
X	echo "Driver ${MODULE} successfully loaded"
Xelse
X	echo "Error: Driver ${MODULE} failed loading stage"
X	exit 1
fi
X
Xecho "Pseudo tty driver reinstalled"
Xexit 0
SHAR_EOF
chmod 0755 pty/Reinstall ||
echo 'restore of pty/Reinstall failed'
Wc_c="`wc -c < 'pty/Reinstall'`"
test 1042 -eq "$Wc_c" ||
	echo 'pty/Reinstall: original size 1042, current size' "$Wc_c"
fi
# ============= pty/Remove ==============
if test -f 'pty/Remove' -a X"$1" != X"-c"; then
	echo 'x - skipping pty/Remove (File already exists)'
else
echo 'x - extracting pty/Remove (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'pty/Remove' &&
PTYCNT=32
# Eric H. Herrin II
# University of Kentucky Mathematical Sciences
# eric at ms.uky.edu, eric at ms.uky.csnet, !cbosgd!ukma!eric
#
# Remove script for pty driver.
MODULE=pty
Xecho "Removing /etc/lddrv entries and /etc/master entries"
/etc/lddrv/lddrv -d ${MODULE}
/etc/masterupd -d ${MODULE}
# remove the pty device files
cnt=0
Xecho "Removing the pty device files"
for x in p q r s t u v w x y z
do
X	for y in 0 1 2 3 4 5 6 7 8 9 a b c d e f
X	do
X		i=$x$y
X		if [ ${cnt} -ge ${PTYCNT} ] 
X		then 
X			break
X		fi
X		/bin/rm -f /dev/pty$i
X		/bin/rm -f /dev/tty$i
X		cnt=`expr ${cnt} + 1`
X	done
done
# get rid of stuff in /etc/lddrv
Xecho "removing InstDrv entries, etc."
/bin/rm -f /etc/lddrv/${MODULE}.o /etc/lddrv/${MODULE} \
X	/etc/lddrv/ifile.${MODULE}
grep -v "^${MODULE}" /etc/lddrv/drivers > /tmp/XXX$$
mv /tmp/XXX$$ /etc/lddrv/drivers
grep -v "${MODULE}" /etc/lddrv/InstDrv > /tmp/XXX$$
mv /tmp/XXX$$ /etc/lddrv/InstDrv
chmod +r /etc/lddrv/drivers /etc/lddrv/InstDrv
chmod go-w /etc/lddrv/drivers /etc/lddrv/InstDrv
chown root /etc/lddrv/drivers /etc/lddrv/InstDrv
SHAR_EOF
chmod 0644 pty/Remove ||
echo 'restore of pty/Remove failed'
Wc_c="`wc -c < 'pty/Remove'`"
test 1065 -eq "$Wc_c" ||
	echo 'pty/Remove: original size 1065, current size' "$Wc_c"
fi
# ============= pty/Remove.orig ==============
if test -f 'pty/Remove.orig' -a X"$1" != X"-c"; then
	echo 'x - skipping pty/Remove.orig (File already exists)'
else
echo 'x - extracting pty/Remove.orig (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'pty/Remove.orig' &&
# Eric H. Herrin II
# University of Kentucky Mathematical Sciences
# eric at ms.uky.edu, eric at ms.uky.csnet, !cbosgd!ukma!eric
#
# Remove script for pty driver.
MODULE=pty
Xecho "Removing /etc/lddrv entries and /etc/master entries"
/etc/lddrv/lddrv -d ${MODULE}
/etc/masterupd -d ${MODULE}
# remove the pty device files
cnt=0
Xecho "Removing the pty device files"
for x in p q r s t u v w x y z
do
X	for y in 0 1 2 3 4 5 6 7 8 9 a b c d e f
X	do
X		i=$x$y
X		if [ ${cnt} -ge ${PTYCNT} ] 
X		then 
X			break
X		fi
X		/bin/rm -f /dev/pty$i
X		/bin/rm -f /dev/tty$i
X		cnt=`expr ${cnt} + 1`
X	done
done
# get rid of stuff in /etc/lddrv
Xecho "removing InstDrv entries, etc."
/bin/rm -f /etc/lddrv/${MODULE}.o /etc/lddrv/${MODULE} \
X	/etc/lddrv/ifile.${MODULE}
grep -v "^${MODULE}" /etc/lddrv/drivers > /tmp/XXX$$
mv /tmp/XXX$$ /etc/lddrv/drivers
grep -v "${MODULE}" /etc/lddrv/InstDrv > /tmp/XXX$$
mv /tmp/XXX$$ /etc/lddrv/InstDrv
chmod +r /etc/lddrv/drivers /etc/lddrv/InstDrv
chmod go-w /etc/lddrv/drivers /etc/lddrv/InstDrv
chown root /etc/lddrv/drivers /etc/lddrv/InstDrv
SHAR_EOF
chmod 0644 pty/Remove.orig ||
echo 'restore of pty/Remove.orig failed'
Wc_c="`wc -c < 'pty/Remove.orig'`"
test 1055 -eq "$Wc_c" ||
	echo 'pty/Remove.orig: original size 1055, current size' "$Wc_c"
fi
# ============= pty/Size ==============
if test -f 'pty/Size' -a X"$1" != X"-c"; then
	echo 'x - skipping pty/Size (File already exists)'
else
echo 'x - extracting pty/Size (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'pty/Size' &&
61
SHAR_EOF
chmod 0644 pty/Size ||
echo 'restore of pty/Size failed'
Wc_c="`wc -c < 'pty/Size'`"
test 3 -eq "$Wc_c" ||
	echo 'pty/Size: original size 3, current size' "$Wc_c"
fi
# ============= pty/Version ==============
if test -f 'pty/Version' -a X"$1" != X"-c"; then
	echo 'x - skipping pty/Version (File already exists)'
else
echo 'x - extracting pty/Version (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'pty/Version' &&
2.1
SHAR_EOF
chmod 0644 pty/Version ||
echo 'restore of pty/Version failed'
Wc_c="`wc -c < 'pty/Version'`"
test 4 -eq "$Wc_c" ||
	echo 'pty/Version: original size 4, current size' "$Wc_c"
fi
true || echo 'restore of pty/interface.c failed'
echo End of part 3, continue with part 4
exit 0
-- 
David H. Brierley
Home: dave at galaxia.newport.ri.us; Work: dhb at quahog.ssd.ray.com
Send comp.sources.3b1 submissions to comp-sources-3b1 at galaxia.newport.ri.us
%% Can I be excused, my brain is full. **



More information about the Comp.sources.3b1 mailing list