/**************************************************************************
 *									  *
 * 		 Copyright (C) 1983, Silicon Graphics, Inc.		  *
 *									  *
 *  These coded instructions, statements, and computer programs  contain  *
 *  unpublished  proprietary  information of Silicon Graphics, Inc., and  *
 *  are protected by Federal copyright law.  They  may  not be disclosed  *
 *  to  third  parties  or copied or duplicated in any form, in whole or  *
 *  in part, without the prior written consent of Silicon Graphics, Inc.  *
 *									  *
 **************************************************************************/

/*
 * Brief description of the philosophy behind the i/o library
 *
 *
 *             HOST COMPUTER            
 * +------------------------------------+
 * |	user's application program	|
 * +------------------------------------+
 * |		lib.f			| set of auto-generated stubs 
 * +------------------------------------+
 * |		io.c			| routines that really do the i/o
 * +------------------------------------+
 *		    ^
 *		    |
 *		    |			  serial line or ethernet
 *		    |
 *		    v
 *
 *	 	  IRIS
 *	+-----------------------+
 *	|  graphics software    |
 *	+-----------------------+
 *
 *	The user's application program calls routines found in lib.f, which
 * in turn call routines in io.c.  Since the routines in io.c have to do
 * alot of bit manipulation, real-time considerations were better preserved
 * by using C instead of Fortran.
 *	Commands that are to be passed to the IRIS are buffered. When the buffer
 * gets full ; or when (flushg,gflush,gexit,greset,gfinis,ginit) are called;
 * and occasionally when (recos,recbs,recfs,recls, recss) are called,
 * the buffer is emptied.
 *	All tokens are passed as a byte stream, but in even multiples of
 * 4 bytes ( i.e. a longword ). If a character string, for example,
 * is not an even multiple of four, extra bytes are tacked onto the end when
 * it is put into the buffer. These extra bytes are ignored when the IRIS
 * receives them, as a count is also passed.
 *	When arrays of ( bytes, characters, longs, floats,...) are sent to
 * the IRIS, they are sent in blocks. Blocks start with a well-known
 * escape character. If running in fastmode( see next paragraph ), 8 longwords
 * of information follow. If slowmode, it is still 8 longwords of information,
 * but because it takes 6 bytes to "encrypt" a longword, there are
 * 6*8 = 48 bytes that follow. In either case, if it is the end of the array,
 * then fewer bytes may follow.
 *	There are two transmission modes: fastmode and slowmode. Fastmode
 * sends 8 bit quantities ( high byte to low byte ), while slowmode sends
 * 6 bit quantities starting with the low byte. Note that slowmode also adds
 * the ascii value of "blank" to the 6 bit entity, so as to make it a printable
 * ( and hence traceable ) character.
 *	Typically slowmode is used for a serial line connection, and fastmode
 * is used for an ethernet connection using the SGI ethernet software.
 */
/*
**		C i/o primitives for remote graphics library
*/
#include <stdio.h>
#include <signal.h>
#ifdef UNIX4_2
#include <sgtty.h>
#endif
#include "rpc.h"
#include <setjmp.h>
#include <sys/ioctl.h>
#include "Xnsioctl.h"
#ifdef SYSTEM5
#include <termio.h>
#endif

#define DEC11                   1

/*
**	System specific defines for unix on dec 11/780
**
*/
#ifdef DEC11
#define longwordelement0        3
#define longwordelement1        2
#define longwordelement2        1
#define longwordelement3        0

#define shortwordelement0       1
#define shortwordelement1       0

#define F2IEEE(value)	D2IEEE(value)
#define IEEE2F(value)   IEEE2DEC(value)
#endif

#ifdef M68000
#define longwordelement0        0
#define longwordelement1        1
#define longwordelement2        2
#define longwordelement3        3

#define shortwordelement0       0
#define shortwordelement1       1

#define F2IEEE(value)	(value)		/* these are not quite right */
#define IEEE2F(value)   (value)
#endif

long D2IEEE();
float IEEE2DEC();

/*
**	End of system specific defines for unix on dec 11/780
*/

long int reco_();
unsigned char recb_();
unsigned short recs_();
unsigned long  recl_();

static short fastmode = 0;
static short netinited = 0;
static short haveether = 0;
static short offbuffend= 0;

	/* OUTBUFFSIZE is the size in bytes of the output buffer for IRIS tokens
	 * If it is large, you will have fewer writes to deal with, but real 
	 * time stuff may appear jerky.  If it is small, real time appearance 
	 * will be better, but the system will have to perform more writes,
	 * and hence "work harder". The point is, you may want to play with
	 * this value and get the right value for your application!
	 */
#define OUTBUFFSIZE		4*1024
#define LONGESTBYTEGROUP 	50

	/* Output buffer for holding the IRIS byte stream */
static char outbuff[OUTBUFFSIZE];
	/* Pointer into the output buffer for inserting the next character */
static char *bp = outbuff;
	/* High water mark, when reached, means the output buffer is full */
static char *highp = outbuff+OUTBUFFSIZE-8;
	/* Indicator that putting another commands worth of info in the output
	 * buffer may overflow
	 */
static char *checkp = outbuff+OUTBUFFSIZE-LONGESTBYTEGROUP;

#ifdef UNIX4_2
static struct sgttyb ttydat;
#endif
#ifdef SYSTEM5
static struct termio ttydat, originalttydat;
#endif
static short tty_save;

/* MACROS */
	/* receive 6 bitsworth of information from the IRIS */
#define rec6()		((getgchar() - ' ') & 077)
	/* send 6 bitsworth of info to the IRIS */
#define send6(n)	putgchar( ((n)&077) + ' ' )
	/* send 8 bitsworth (fastmode) of info to the IRIS */
#define send8(n)	putgchar( n )
	/* Shove another character into the output buffer */
#define putgchar(n)	addchar( n )
	/* See if it's time to send another sync character */
#define dosync(i)	(((i) & 7) == 0)

#define addchar(n)	(*bp++ = (n))		
	/* See if output buffer is full, and if so, flush the buffer */
#define fullcheck();	{ if(bp>highp) { flushg_(); offbuffend++; } }

#ifdef PROTOCOLDEBUG
#define NONE 0
#define READER 1
#define WRITER 2
static isopen = 0, current = NONE, column = 0;
FILE *fopen(), *fp;

char getgchar()
{
unsigned char ch;
ch = getc(stdin);
if (current == WRITER)
    {
    fprintf(fp, "end");
    fprintf(fp, "\nGot from iris:\n");
    current = READER;
    column = 0;
    }
print6char(ch);
return(ch);
}

print6char(ch)
unsigned char ch;
{
if (ch == 0)
    fprintf(fp, " \\0 ");
else if (ch < ' ')
    fprintf(fp, "0%o ", ch);
else if (ch == ' ')
    fprintf(fp, "    ");
else
    fprintf(fp, "  %c ", ch);
if (++column == 16)
    {
    fprintf(fp, "\n");
    column = 0;
    }
}
#else
#define getgchar()	getc(stdin)
#endif

/*
**	gcmd - send the graphics escape and the specified command code
**		The values passed are put into lib.f before lib.f
**		is compiled (for the most part).
**	
*/
gcmd_( comcode )
register short *comcode;
{
    if(!netinited)
	netinit();
    outcheck();
    putgchar(TESC);
    send6(*comcode);
    send6(*comcode>>6);
}


/*
**	sendo - send a boolean 
**		Fortran logicals are 4 bytes wide for the host,
**		and only one byte for the IRIS
**
*/
sendo_( value )
unsigned long *value;
{
	sendb_((unsigned char *)value,1L);
}


/*
** 	sendos - send an array of bytes
**		 We must map long ints into bytes for the IRIS
**
*/
sendos_( values, nvals )
long int *values;
long int *nvals;
{
    register long i, nlongs, nleft;
    long along; 
    register char *ptr = (char *)&along;

    nlongs = *nvals>>2;
    nleft  = *nvals - ( nlongs<<2);
    sendl_(nvals);
    if(fastmode) {
        for(i=0; i<nlongs; i++) {
	    if (dosync(i))
		putgchar(AESC);
	    send8(*values++ ? 1: 0);
	    send8(*values++ ? 1: 0);
	    send8(*values++ ? 1: 0);
	    send8(*values++ ? 1: 0);
	    fullcheck();
	}
    } else {
        for(i=0; i<nlongs; i++) {
	    if (dosync(i))
		putgchar(AESC);
	    ptr[longwordelement0] = *values++ ? 1: 0;	
	    ptr[longwordelement1] = *values++ ? 1: 0;
	    ptr[longwordelement2] = *values++ ? 1: 0;	
	    ptr[longwordelement3] = *values++ ? 1: 0;	
	    sendl_(&along);
        }
    }
    if (nleft){
	if (dosync(i))
	    putgchar(AESC);
	if ( fastmode ) {
	    switch ( nleft ){
		case 3:
		    send8(*values++ ? 1: 0);
		case 2:
		    send8(*values++ ? 1: 0);
		case 1:
		    send8(*values++ ? 1: 0);
		    fullcheck();
		default:
		    break;
		}
	} else {
	    values += ( nleft - 1 );
	    switch ( nleft ) {
		case 3:
		    ptr[longwordelement2] = *values-- ? 1: 0;
		case 2:
		    ptr[longwordelement1] = *values-- ? 1: 0;
		case 1:
		    ptr[longwordelement0] = *values-- ? 1: 0;
		    sendl_(&along);
		default:
		    break;
	    }
	}
    }
    arrayflush();
}

/*
**	sendb - send a byte 
**
*/
sendb_(value ,trash)
register unsigned char *value;
long int trash;		/* If this isn't 1, uh-oh */
{
    if(fastmode)
	send8(*value);
    else {
        send6(*value);
        send6(*value>>6);
    }
    fullcheck();
}


/*
** 	sendbs - send an array of bytes
**
*/
sendbs_( values, nvals, trash )
register char values[];
long *nvals;
long int trash;	/* length of the values array */
{
    register long i, nlongs, nleft;
    long along; 
    register char *ptr = (char *)&along;

    nlongs = *nvals>>2;
    nleft  = *nvals - ( nlongs<<2 );
    sendl_(nvals);
    if(fastmode) {
	for(i=0; i<nlongs; i++) {
	    if (dosync(i))
		putgchar(AESC);
	    send8(*values++);
	    send8(*values++);
	    send8(*values++);
	    send8(*values++);
	    fullcheck();
	}
    } else {
	for(i=0; i<nlongs; i++) {
	    if (dosync(i))
		putgchar(AESC);
	    ptr[longwordelement0] = *values++;	
	    ptr[longwordelement1] = *values++;	
	    ptr[longwordelement2] = *values++;	
	    ptr[longwordelement3] = *values++;	
	    sendl_(&along);
        }
    }
    if ( nleft ){
	if ( dosync(i) )
	    putgchar(AESC);
	if ( fastmode ) {
	    switch ( nleft ){
		case 3:
		    send8(*values++);
		    send8(*values++);
		    send8(*values++);
		    send8(0);
		    fullcheck();
		    break;
		case 2:
		    send8(*values++);
		    send8(*values++);
		    send8(0);
		    send8(0);
		    fullcheck();
		    break;
		case 1:
		    send8(*values++);
		    send8(0);
		    send8(0);
		    send8(0);
		    fullcheck();
		    break;
		default:
		    break;
	    }
	} else {
	    values += ( nleft - 1 );
	    switch ( nleft ){
		case 3:
		    ptr[longwordelement2] = *values--;
		case 2:
		    ptr[longwordelement1] = *values--;
		case 1:
		    ptr[longwordelement0] = *values--;
		    sendl_(&along);
		default:
		    break;
	    }
	}
    }
    arrayflush();
}


/*
** 	sendqs - send an array of Fontchars
**
*/
sendqs_( values, nvals, trash )
register char values[];
long *nvals;
long int trash;		/* This should be the same as nvals */
{
    register long i, nlongs;
    long along, temp; 
    register char *ptr = (char *)&along;

    temp = *nvals<<3;
    sendl_(&temp);
    nlongs = *nvals<<1;
    for(i=0; i<nlongs; i++) {
	if (dosync(i))
            putgchar(AESC);
	ptr[longwordelement1] = *values++;	
	ptr[longwordelement0] = *values++;	
	ptr[longwordelement2] = *values++;	
	ptr[longwordelement3] = *values++;	
	sendl_(&along);
	i++;
	ptr[longwordelement0] = *values++;	
	ptr[longwordelement1] = *values++;	
	ptr[longwordelement3] = *values++;	
	ptr[longwordelement2] = *values++;	
	sendl_(&along);
    }
    arrayflush();
}


/*
**	sendc - send a string
**
*/
sendc_( values, nvals )
register char values[];
long int nvals;
{
    register long i, nlongs, nleft;
    long along; 
    register char *ptr = (char *)&along;

    nlongs = nvals>>2;
    /* Note that the number left to do is not really nleft, but rather
     * nleft - 1, as we need to append a NULL to the end of the string
     * we send to the IRIS. (Turns out that character*1 definitions do
     * not always get terminated by NULLs in the f77 Fortran compiler)
     */
    nleft  = nvals - ( nlongs<<2 );
    nvals++;
    sendl_(&nvals);
    if(fastmode) {
	for(i=0; i<nlongs; i++) {
	    if (dosync(i))
		putgchar(AESC);
	    send8(*values++);
	    send8(*values++);
	    send8(*values++);
	    send8(*values++);
	    fullcheck();
	}
    } else {
	for(i=0; i<nlongs; i++) {
	    if (dosync(i))
		putgchar(AESC);
	    ptr[longwordelement0] = *values++;
	    ptr[longwordelement1] = *values++;	
	    ptr[longwordelement2] = *values++;	
	    ptr[longwordelement3] = *values++;	
	    sendl_(&along);
        }
    }
    if ( dosync(i) )
	putgchar(AESC);
    if ( fastmode ) {
	switch ( nleft ){
	    case 3:
		send8(*values++);
		send8(*values++);
		send8(*values++);
		send8(0);
		fullcheck();
		break;
	    case 2:
		send8(*values++);
		send8(*values++);
		send8(0);
		send8(0);
		fullcheck();
		break;
	    case 1:
		send8(*values++);
		send8(0);
		send8(0);
		send8(0);
		fullcheck();
		break;
	    case 0:
		send8(0);
		send8(0);
		send8(0);
		send8(0);
		fullcheck();
		break;
	    default:
		break;
	}
    } else {
	values += ( nleft - 1 );
	along = 0;			/* insure the last byte sent is zero */
	switch ( nleft ){
	    case 3:
		ptr[longwordelement2] = *values--;
	    case 2:
		ptr[longwordelement1] = *values--;
	    case 1:
		ptr[longwordelement0] = *values--;
	    case 0:
		sendl_(&along);
	    default:
		break;
	}
    }
    arrayflush();
}


/*
**	sends - send a short
**
*/
sends_( value ) 
register unsigned short *value;
{
    if(fastmode) {
  	send8(*value>>8);
  	send8(*value);
    } else {
        send6(*value);
        send6(*value>>6);
        send6(*value>>12);
    }
    fullcheck();
}


/*
** 	sendss - send an array of shorts
**
*/
sendss_( values, nvals )
register short *values;
long *nvals;
{
    register long i, nlongs;
    long along, temp;
    register short *ptr = (short *)&along;

    nlongs = *nvals>>1;
    temp = *nvals<<1;
    sendl_(&temp);
    for(i=0; i<nlongs; i++) {
	if (dosync(i))
            putgchar(AESC);
	ptr[shortwordelement0] = *values++;	
	ptr[shortwordelement1] = *values++;	
	sendl_(&along);
    }
    if ( *nvals - (nlongs<<1) ){
	if (dosync(i))
	    putgchar(AESC);
        ptr[shortwordelement0] = *values++;
        sendl_(&along);
    }
    arrayflush();
}


/*
**	sendl - send a long
**
*/
sendl_( value ) 
unsigned long *value;
{
    register unsigned long val;
    register unsigned char *ptr;

    ptr = (unsigned char *)value;
    if(fastmode) {
	send8(ptr[longwordelement0]);
	send8(ptr[longwordelement1]);
	send8(ptr[longwordelement2]);
	send8(ptr[longwordelement3]);
    } else {
	val = *value;
        send6(val);
        send6(val>>6);
        send6(val>>12);
        send6(val>>18);
        send6(val>>24);
        send6(val>>30);
    }
    fullcheck();
}


/*
** 	sendls - send an array of longs
**
*/
sendls_( values, nvals )
register long *values;
register long *nvals;
{
    register long i;
    long int temp;

    temp = *nvals<<2;
    sendl_(&temp);
    for(i=0; i<*nvals; i++) {
	if (dosync(i))
            putgchar(AESC);
	sendl_(values++);
    }
    arrayflush();
}


/*
**	sendf - send a float
**
*/
sendf_( value ) 
float *value;
{
    unsigned long int temp;

    temp = F2IEEE(*value);
    sendl_(&temp);
}


/*
** 	sendfs - send an array of floats
**
*/
sendfs_( values, nvals )
register float values[];
register long *nvals;
{
    register long i;
    unsigned long int temp;

    temp = *nvals<<2;
    sendl_(&temp);
    for(i=0; i<*nvals; i++) {
	if (dosync(i))
            putgchar(AESC);
	temp = F2IEEE(*values++);
	sendl_(&temp);
    }
    arrayflush();
}


/*
**	reco - receive a boolean
**
*/
long int reco_()
{
    char result[1];

    return recb_(result, 1L);
}


/*
**	recos - receive an array of booleans
**
*/
recos_( values )
register long int *values;
{
    register long i, nleft, nlongs;
    register unsigned long val;
    long nlogics;
    unsigned long along;
    register char *ptr = (char *)&along;

    nlongs = (nlogics=recl_());
    if(getgchar() != RESC) {
	printf("recos: error in array transport\n");
	return;
    }
    for(i=0; i<nlongs; i++) {
        val = rec6();
        val |= rec6()<<6;
        val |= rec6()<<12;
        val |= rec6()<<18;
        val |= rec6()<<24;
        val |= rec6()<<30;
	if(dosync(i)) {
            getgchar();
	    putgchar(AESC);
	    flushg_();
	}
	along = val;
    	*values++ = (long int)ptr[longwordelement0];
    	*values++ = (long int)ptr[longwordelement1];
    	*values++ = (long int)ptr[longwordelement2];
    	*values++ = (long int)ptr[longwordelement3];
    }
    getgchar();
}


/*
**	recb - receive a byte
**
*/
unsigned char recb_(result, length)
char result[];
long int length;
{
    unsigned char val;

    while(getgchar() != RESC) 
	;
    val = rec6();
    val |= rec6()<<6;
    return ( result[0] = val);
}


/*
**	recbs - receive an array of bytes
**
*/
recbs_( values, length )
register char *values;
long int length;
{
    register long i, nlongs, nleft;
    register unsigned long val;
    long nbytes;
    unsigned long along;
    register char *ptr = (char *)&along;

    nlongs = (nbytes=recl_())>>2;
    nleft  = nbytes - (nlongs<<2);
    if(getgchar() != RESC) {
	printf("recbs: error in array transport\n");
	return;
    }
    for(i=0; i<nlongs; i++) {
        val = rec6();
        val |= rec6()<<6;
        val |= rec6()<<12;
        val |= rec6()<<18;
        val |= rec6()<<24;
        val |= rec6()<<30;
	if(dosync(i)) {
            getgchar();
	    putgchar(AESC);
	    flushg_();
	}
	along = val;
    	*values++ = ptr[longwordelement0];
    	*values++ = ptr[longwordelement1];
    	*values++ = ptr[longwordelement2];
    	*values++ = ptr[longwordelement3];
    }
    if (nleft){
        val = rec6();
        val |= rec6()<<6;
        val |= rec6()<<12;
        val |= rec6()<<18;
        val |= rec6()<<24;
        val |= rec6()<<30;
	if(dosync(i)) {
            getgchar();
	    putgchar(AESC);
	    flushg_();
	}
	along = val;
	values += (nleft - 1);
	switch ( nleft ) {
	    case 3:
		*values-- = ptr[longwordelement2];
	    case 2:
		*values-- = ptr[longwordelement1];
	    case 1:
		*values-- = ptr[longwordelement0];
	    default:
		break;
	}
    }
    getgchar();
}


/*
**	recf - receive a float
**
*/
float recf_()
{

    return IEEE2F(recl_());
}


/*
**	recfs - receive an array of floats
**
*/
recfs_( values )
register float *values;
{
    register long i, nlongs;
    register unsigned long val;

    nlongs = recl_();
    if(getgchar() != RESC) {
	printf("recfs: error in array transport\n");
	return;
    }
    for(i=0; i<nlongs; i++) {
        val = rec6();
        val |= rec6()<<6;
        val |= rec6()<<12;
        val |= rec6()<<18;
        val |= rec6()<<24;
        val |= rec6()<<30;
	if(dosync(i)) {
            getgchar();
	    putgchar(AESC);
	    flushg_();
	}
        *values++ = IEEE2F(val);
    }
    getgchar();
}


/*
**	recl - receive a long
**
*/
unsigned long recl_()
{
    register unsigned long val;

    while(getgchar() != RESC) 
	;
    val = rec6();
    val |= rec6()<<6;
    val |= rec6()<<12;
    val |= rec6()<<18;
    val |= rec6()<<24;
    val |= rec6()<<30;
    return val;
}


/*
**	recls - receive an array of longs
**
*/
recls_( values )
register unsigned long *values;
{
    register long i, nlongs;
    register unsigned long val;

    nlongs = recl_();
    if(getgchar() != RESC) {
	printf("recls: error in array transport\n");
	return;
    }
    for(i=0; i<nlongs; i++) {
        val = rec6();
        val |= rec6()<<6;
        val |= rec6()<<12;
        val |= rec6()<<18;
        val |= rec6()<<24;
        val |= rec6()<<30;
	if(dosync(i)) {
	    getgchar();
	    putgchar(AESC);
	    flushg_();
	}
    	*values++ = val;
    }
    getgchar();
}


/*
**	recs - receive a short
**
*/
unsigned short recs_()
{
    register unsigned short val;

    while(getgchar() != RESC) 
	;
    val = rec6();
    val |= rec6()<<6;
    val |= rec6()<<12;
    return val;
}


/*
**	recss - receive an array of shorts
**
*/
recss_( values )
register short *values;
{
    register long i, nlongs, nleft;
    register unsigned long val;
    long nshorts;
    unsigned long along;
    register short *ptr = (short *)&along;

    nlongs = (nshorts=recl_())>>1;
    nleft  = nshorts - (nlongs<<1);
    if(getgchar() != RESC) {
	printf("recss: error in array transport\n");
	return;
    }
    for(i=0; i<nlongs; i++) {
        val =  rec6();
        val |= rec6()<<6;
        val |= rec6()<<12;
        val |= rec6()<<18;
        val |= rec6()<<24;
        val |= rec6()<<30;
	if(dosync(i)) {
            getgchar();
	    putgchar(AESC);
	    flushg_();
	}
	along = val;
    	*values++ = ptr[shortwordelement0];
    	*values++ = ptr[shortwordelement1];
    }
    if ( nleft ) {
        val =  rec6();
        val |= rec6()<<6;
        val |= rec6()<<12;
        val |= rec6()<<18;
        val |= rec6()<<24;
        val |= rec6()<<30;
	if(dosync(i)) {
            getgchar();
	    putgchar(AESC);
	    flushg_();
	}
	along = val;
    	*values++ = ptr[shortwordelement0];
    }
    getgchar();
}


reccr_()
{
    getgchar();
}

endpri_()
{
}


setfas_()
{
    if(!netinited)
        netinit();
    fastmode = 1;
    xsetfa_();
}


setslo_()
{
    if(!netinited)
        netinit();
    fastmode = 0;
    xsetsl_();
}

/*
**	ginit - invokes xginit which takes special action on the terminal
**
*/
ginit_()
{
    if(!netinited)
	netinit();
    xginit_();
    flushg_();
}

/*
**	greset - invokes xgreset which takes special action on the terminal
**
*/
greset_()
{
    if(!netinited)
	netinit();
    xgrese_();
    flushg_();
}

gflush_()
{
    if(!netinited)
	netinit();
    flushg_();
}


gexit_()
{
    if(!netinited)
	netinit();
    xgexit_();
    flushg_();
    ttyrestore();
}


gfinis_()
{
    if(!netinited)
	netinit();
    flushg_();
}


/*
**	C-unix system specific i/o functions for remote graphics library
**
**			  Paul Haeberli - Sept 1983
*/
#ifdef PROTOCOLDEBUG
putgchar( onechar )
char onechar;
{
if (isopen == 0)
    {
    isopen = 1;
    fp = fopen("protsave", "w");
    }
if (current == READER || current == NONE)
    {
    if (current != NONE)
	fprintf(fp, "end");
    fprintf(fp, "\nSent to iris:\n");
    current = WRITER;
    column = 0;
    }
print6char(onechar);
    outbuff[bp++] = onechar;
    if(bp >= OUTBUFFSIZE) {
	flushg_();
	offbuffend++;
    }
}
#endif

/*
**	outcheck - see if we are within LONGESTBYTEGROUP of the the
**		   end of the buffer.  If so, flush output.
*/
outcheck()
{
    if( bp > checkp )
	flushg_();
    offbuffend = 0;
}

/*
**	arrayflush - only flush when needed after array transfer  
**
*/
arrayflush()
{
    if(offbuffend) {
	flushg_();
        offbuffend = 0;
    }
}

/*
**	flushg - flush the graphics stream
**
*/
flushg_()
{
    if ( bp != outbuff ) {
        fflush(stdout);
	if(haveether) 
	    netwrite(1,outbuff,bp-outbuff);
        else
	    write(1,outbuff,bp-outbuff);
        bp = outbuff;
    }
}

netwrite(fd, buf, cc)
int fd;
char *buf;
register cc;
{
    struct xnsio io;

    io.addr = buf;
    io.count = cc;
    io.dtype = 0;
    ioctl(fd, NXWRITE, &io);
    return(io.count);
}

cleanexit()
{
    ttyrestore();
    exit(0);
}

netinit()
{
    register short i;

    netinited = 1;		   	/* careful - the order is important! */	
    for(i=0; i<LONGESTBYTEGROUP; i++) {	/* sure to get out of graphics mode */
	putgchar(0);
	fullcheck();
    }
    if( ioctl(1, NXIOSLOW, 0) == -1 )		/* see if we're on the net */
    	setslo_(); 
    else {
	haveether = 1;
    	setfas_(); 
    }
    ttysave();
    signal(SIGQUIT,cleanexit);
    signal(SIGINT,cleanexit);
    signal(SIGBUS,cleanexit);
    signal(SIGTERM,cleanexit);
}

/*
**	echoff - Turn local echoing off
**
*/
echoff_()
{
    if(!netinited)
	netinit();
#ifdef UNIX4_2
    ttydat.sg_flags = tty_save & ~ECHO;
    stty(0, &ttydat);
#endif
#ifdef SYSTEM5
    ttydat.c_lflag &= ~ECHO;
    ioctl(0,TCSETA,&ttydat);
#endif
}


/*
**	echoon - Turn local echoing on
**
*/
echoon_()
{
#ifdef UNIX4_2
    ttydat.sg_flags = tty_save | ECHO;
    stty(0, &ttydat);
#endif
#ifdef SYSTEM5
    ttydat.c_lflag |= ECHO;
    ioctl(0, TCSETA,&ttydat);
#endif
}

/*
**	ttysave - save the state of the tty
**
*/
ttysave()
{
#ifdef UNIX4_2
    short t_local = LLITOUT;

    gtty(0, &ttydat);
    tty_save = ttydat.sg_flags;
    if(!haveether)
        ioctl(1,TIOCLBIS,&t_local);	/* set literal output mode */
#endif
#ifdef SYSTEM5
    ioctl(0, TCGETA, &originalttydat);
    ioctl(0, TCGETA, &ttydat);
#endif
}

/*
**	ttyrestore - restore the state of the tty
**
*/
ttyrestore()
{
#ifdef UNIX4_2
    short t_local = LLITOUT;

    ttydat.sg_flags = tty_save;
    stty(0, &ttydat);
    if(!haveether)
        ioctl(1,TIOCLBIC,&t_local);	/* clr literal output mode */
#endif
#ifdef SYSTEM5
    ioctl(0,TCSETA,&originalttydat);
#endif
}

/*
** 	D2IEEE - convert from DEC to IEEE floating point formats.  Returns zero
**	         on underflow (instead of denormalized IEEE).  
**
** 		Charles (Herb) Kuta - Aug 1983
*/
long D2IEEE(fn)
float fn;
{
    register unsigned long n;
    						/* if characteristic <= 2 */
    if ( ((n = *(long *)&fn) & (0xff << 7)) <= (0x2 << 7) )   
	return 0;
    else {
        n -= 0x2 << 7;
        return ((n>>16) | (n<<16));
    }
}


/*
** 	IEEE2DEC - convert from IEEE to DEC floating point formats.  Returns 
**		   zero for denormalized IEEE and DECmax on overflow 
**		   (including IEEE infinity).
**
** 		Charles (Herb) Kuta - Aug 1983
*/
float IEEE2DEC(n)
register long n;
{
    register long characteristic;
    long nn;

    n = ((n>>16) & 0xffff) | (n<<16);
    if ((characteristic = n & (0xff << 7)) == 0)
    	return 0.0;
    else if (characteristic >= (0xfe << 7))
    	nn = (n < 0) ? 0xffffffff : 0xffff7fff;
    else
    	nn = n + (0x2 << 7);
    return (*(float *)&nn);
}
