/*
 * Copyright (C) 1992 by Rush Record
 * Copyright (C) 1993 by Charles Sandmann (sandmann@clio.rice.edu)
 * 
 * This file is part of ED.
 * 
 * ED is free software; you can redistribute it and/or modify it under the terms
 * of the GNU General Public License as published by the Free Software Foundation.
 * 
 * ED is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with ED
 * (see the file COPYING).  If not, write to the Free Software Foundation, 675
 * Mass Ave, Cambridge, MA 02139, USA.
 */
#include "opsys.h"

#include <stdio.h>
#include <string.h>

extern void cleanup();
static Int restored = 1;	/* flag to control behavior of ttyend(). it does restoration only if restored == 0. */

#ifdef VMS
#include <ssdef.h>
#include <ttdef.h>
#include <iodef.h>

static short chan = 0;
extern void ttyend();
static int desblk[4] = {0,(int)ttyend,0,(int)&desblk[3]};
static Char sysinput[] = {"SYS$COMMAND"};
static struct {unsigned short length,class;Char *string;} desc = {11,0x010e,sysinput};
typedef struct mode_str *mode_ptr;
typedef struct mode_str
{
	Uchar class,type;
	unsigned short buffersize;
	union
	{
		unsigned int characteristics;
		Uchar page[4];
	} u;
	unsigned int extended;
} mode_node;
static mode_node old_mode;
static unsigned int newmask = 0x02100000,oldmask;	/* disable interrupts */
static Char ctrlc_typed = 0;

/******************************************************************************\
|Routine: ttysetsize
|Callby: init_term
|Purpose: Handles defaults for terminal size.
|Arguments:
|    NROW,NCOL - the number of rows and columns on the screen.
\******************************************************************************/
void ttysetsize(nrow,ncol)
Int *nrow,*ncol;
{
	if(!*nrow)
		*nrow = 24;
	if(!*ncol)
		*ncol = 80;
}

/******************************************************************************\
|Routine: ttygetsb
|Callby: put
|Purpose: Null routine.
|Arguments:
|    ptr - physical video frame buffer base pointer.
\******************************************************************************/
void ttygetsb(ptr)
short **ptr;
{
}

/******************************************************************************\
|Routine: ttyscreen
|Callby: put
|Purpose: Null routine.
|Arguments:
|    row, col - where to position the cursor on the screen, zero based.
\******************************************************************************/
void ttyscreen(row,col)
Int row,col;
{
}

/******************************************************************************\
|Routine: ring_bell
|Callby: init_term
|Purpose: Handles special bell-ringing for brain-dead terminals.
|Arguments:
|    none
\******************************************************************************/
void ring_bell()
{
}

/******************************************************************************\
|Routine: ttyend
|Callby: init_term ttyput
|Purpose: Terminates connection with the terminal.
|Arguments:
|    none
\******************************************************************************/
void ttyend()
{
	unsigned short iosb[4],temp;
	
	if(temp = chan)
	{
		chan = 0;
		SYS$CANEXH(desblk);
		SYS$QIOW(0,temp,IO$_SETMODE,iosb,0,0,&old_mode,12,0,0,0,0);
		SYS$DASSGN(temp);
		LIB$ENABLE_CTRL(&oldmask);
	}
}

/******************************************************************************\
|Routine: ttyioerr
|Callby: ttyput
|Purpose: Handles i/o errors with the terminal.
|Arguments:
|    status is the VMS status of the i/o.
|    iosb is the VMS i/o status block.
\******************************************************************************/
void ttyioerr(status,iosb)
Int status;
unsigned short iosb;
{
	if(!(status & 1))
	{
		if(status != SS$_TIMEOUT)
			goto report_error;
	}
	else
	{
		if(!((status = iosb) & 1))
		{
			if(status != SS$_TIMEOUT)
				goto report_error;
		}
	}
	return;
report_error: 
	printf("An I/O error occurred (error #%08X).\r\n",status);
	cleanup(-1);
}

/******************************************************************************\
|Routine: ttyput
|Callby: put
|Purpose: Puts characters to the terminal.
|Arguments:
|    c is the string to send to the terminal.
\******************************************************************************/
void ttyput(c)
Char *c;
{
	Int i,status;
	unsigned short iosb[4];

	if(!(i = strlen(c)))
		return;
	while(i > 64)
	{
		status = SYS$QIOW(0,chan,IO$_WRITEVBLK | IO$M_NOFORMAT,iosb,0,0,c,64,0,0,0,0);
		ttyioerr(status,iosb[0]);
		c += 64;
		i -= 64;
	}
	if(i)
	{
		status = SYS$QIOW(0,chan,IO$_WRITEVBLK | IO$M_NOFORMAT,iosb,0,0,c,i,0,0,0,0);
		ttyioerr(status,iosb[0]);
	}
}

/******************************************************************************\
|Routine: ttychk
|Callby: load_file
|Purpose: Null routine.
|Arguments:
|    none
\******************************************************************************/
Int ttychk()
{
	if(ctrlc_typed)
	{
		ctrlc_typed = 0;
		return(3);
	}
	return(0);
}

/******************************************************************************\
|Routine: setctrlc
|Callby: ttystart
|Purpose: AST routine to set the ctrlc-has-been-typed flag.
|Arguments:
|    none
\******************************************************************************/
void setctrlc()
{
	unsigned short iosb[4];
	
	ctrlc_typed = 1;
	SYS$QIOW(0,chan,IO$_SETMODE | IO$M_CTRLCAST,iosb,0,0,setctrlc,0,0,0,0,0);
}

/******************************************************************************\
|Routine: ttyget
|Callby: cfg init_term
|Purpose: Gets a character from the terminal.
|Arguments:
|    c is the returned character.
\******************************************************************************/
void ttyget(c)
Schar *c;
{
	static Char buf[128],*next = buf;
	static int terms[8] = {0,0,0,0,0,0,0,0};
	static struct {int nbytes,*terminators;} term_desc = {0,terms};
	static Int remain = 0;
	Int status;
	unsigned short iosb[4];

	if(!remain)
	{
		status = SYS$QIOW(0,chan,IO$_TTYREADALL | IO$M_NOECHO | IO$M_NOFILTR | IO$M_TIMED,iosb,0,0,buf,sizeof(buf) - 3,0,&term_desc,0,0);
		ttyioerr(status,iosb[0]);
		if(!(remain = iosb[1]))
		{
			status = SYS$QIOW(0,chan,IO$_TTYREADALL | IO$M_NOECHO,iosb,0,0,c,1,0,0,0,0);
			ttyioerr(status,iosb[0]);
			return;
		}
		else
			next = buf;
	}
	*c = *((Schar *)next++);
	remain--;
}

/******************************************************************************\
|Routine: ttystart
|Callby: init_term
|Purpose: Initializes communication with the terminal.
|Arguments:
|    none
\******************************************************************************/
void ttystart()
{
	mode_node new_mode;
	Int status;
	unsigned short iosb[4];

	if(!chan)
	{
		LIB$DISABLE_CTRL(&newmask,&oldmask);
		status = SYS$ASSIGN(&desc,&chan,0,0);
		if(!(status & 1))
		{
			printf("Unable to assign a channel to SYS$COMMAND (error #%08X).\r\n",status);
			exit(-1);
		}
		SYS$QIOW(0,chan,IO$_SENSEMODE,iosb,0,0,&old_mode,12,0,0,0,0);
		new_mode = old_mode;
		new_mode.u.characteristics |= TT$M_HOSTSYNC|TT$M_TTSYNC|TT$M_NOBRDCST|TT$M_NOECHO;
		SYS$QIOW(0,chan,IO$_SETMODE,iosb,0,0,&new_mode,12,0,0,0,0);
		if(!((status = SYS$DCLEXH(desblk)) & 1))
		{
			ttyend();
			printf("Unable to declare exit handler, status = %08X\n",status);
			cleanup(0);
		}
		SYS$QIOW(0,chan,IO$_SETMODE | IO$M_CTRLCAST,iosb,0,0,setctrlc,0,0,0,0,0);
	}
}

#else	/* VMS */

#ifdef GNUOS2
#define  INCL_KBD		/* Define Kbd routines in os2.h */
#define  INCL_VIO		/* Define Vio routines in os2.h */
#define  INCL_NOPM		/* Don't define PM routines in os2.h */
#include <os2.h>
static short *screen_base = 0;	/* pointer to PC screen area */
static short saveshift = 0;	/* shift flags from previous keystroke */
static unsigned short lenLVB = 0; /* length of screen */

/******************************************************************************\
|Routine: ttygetsb
|Callby: put
|Purpose: Returns video buffer base.
|Arguments:
|    ptr - logical video frame buffer base pointer.
\******************************************************************************/
void ttygetsb(ptr)
short **ptr;
{
	*ptr = screen_base;
}

/******************************************************************************\
|Routine: ttysetsize
|Callby: init_term
|Purpose: Handles defaults for terminal size.
|Arguments:
|    nrow, ncol - the number of rows and columns on the screen.
\******************************************************************************/
void ttysetsize(nrow,ncol)
Int *nrow,*ncol;
{
	VIOMODEINFO viomi;

	viomi.cb = sizeof(viomi);
	VioGetMode(&viomi, 0);

	if(*ncol > viomi.col)		/* User wants more columns, set to 132 (max) */
	{
/*		viomi.col = 132; 
		VioSetMode(&viomi, 0);
		VioGetMode(&viomi, 0); */
	}

	if(*nrow > viomi.row)		/* User wants more rows, use 8x8 font */
	{
/*		viomi.row = *nrow; */
		viomi.row = 50;
		VioSetMode(&viomi, 0);
		VioGetMode(&viomi, 0);
	}

	/* Indicate final resolution (may or may not change from above) */
	*nrow = viomi.row;
	*ncol = viomi.col;
	lenLVB = viomi.row * viomi.col * sizeof(short);
	screen_base = (short *)imalloc(lenLVB);
}

/******************************************************************************\
|Routine: ttyscreen
|Callby: put
|Purpose: Updates screen buffer and positions cursor (DOS & OS2 only).
|Arguments:
|    row, col - where to position the cursor on the screen, zero based.
\******************************************************************************/
void ttyscreen(row,col)
Int row,col;
{
	short i;
	
	if((i = VioWrtCellStr((Char *)screen_base, lenLVB, 0, 0, 0)))
	{
		printf("VioWrtCellStr failure %d.\n",i);
		cleanup(-1);
	}
		
	if((i = VioSetCurPos((unsigned short)row, (unsigned short)col, 0)))
	{
		printf("VioSetCurPos failure %d.\n",i);
		cleanup(-1);
	}
}

/******************************************************************************\
|Routine: ring_bell
|Callby: init_term
|Purpose: Handles special bell-ringing for non-terminal PC terminals.
|Arguments:
|    none
\******************************************************************************/
void ring_bell()
{
	DosBeep(320,100);
}

/******************************************************************************\
|Routine: ttyput
|Callby: put
|Purpose: Puts characters to the terminal.
|Arguments:
|    c is the string to send to the terminal.
\******************************************************************************/
void ttyput(c)
Char *c;
{
}

/******************************************************************************\
|Routine: ttychk
|Callby: load_file
|Purpose: Null routine.
|Arguments:
|    none
\******************************************************************************/
Int ttychk()
{
	return(0);
}

/******************************************************************************\
|Routine: ttyget
|Callby: cfg init_term
|Purpose: Gets a character from the terminal.
|Arguments:
|    c is the returned character.
\******************************************************************************/
void ttyget(c)
Schar *c;
{
	static Char buf[2],*next = buf;
	static Int remain = 0;
	short shift;
	Int evtcode,scan,asci;
	Uchar thischar;
	KBDKEYINFO keyinf;

	while(!remain)
	{
		next = buf;
		if(KbdCharIn(&keyinf, IO_WAIT, 0))
		{
			printf("KbdCharIn failed!\n");
			cleanup(-1);
		}
		shift = keyinf.fsState;
		if(NUMLOCK_ON & (shift ^ saveshift))
		{
			*next++ = 0xaf;		/* NumLock */
			remain++;
		}
		saveshift = shift;
		evtcode = (keyinf.chScan << 8) | keyinf.chChar;
		scan = keyinf.chScan;
		asci = keyinf.chChar;
		if( evtcode == 0x0e08 )
			thischar = 127;		/* Rubout */
		else if( (asci > 0) && (scan <= 0x35) )
		{
			/* If Caps Lock on then it is Caps! */
			if((CAPSLOCK_ON & shift) && 
				(asci >= 'a') && (asci <= 'z') )
					asci = asci - 0x20;
			thischar = asci;
		}
		else if( scan == 0x39)
			thischar = ' ';		/* Space */
		/* 13 characters between 0x00 and 0x0c (Keypad & Arrows) */
		else if( (scan >= 0x47) && (scan <= 0x53) )
		{
			if( asci == 0xe0 )
				thischar = 0xa0 + (scan - 0x47);
			else
				thischar = 0xb0 + (scan - 0x47);
		}
		else if( evtcode == 0xe00d )
			thischar = 0xbd;	/* KpEnter */
		else if( evtcode == 0xe02f )
			thischar = 0xbe;	/* PF2 */
		else if( evtcode == 0x372a )
			thischar = 0xbf;	/* PF3 */
		else if( evtcode == 0x0300 )
			thischar = 0;		/* Null */
		/* 10 characters between 0x00 and 0x09 (F1 to F10) */
		else if( (scan >= 0x3b) && (scan <= 0x44) )
			thischar = 0xc0 + (scan - 0x3b);
		else if( evtcode == 0x8500 )
			thischar = 0xca;	/* F11 */
		else if( evtcode == 0x8600 )
			thischar = 0xcb;	/* F12 */
		else
			thischar = 0xff;		/* indicate not set */

		if(thischar >= 0xb0 && thischar <= 0xbf) /* shift special */
			if(KB_SHIFT & shift) thischar -= 0x10;

		if(thischar != 0xff)
		{
			*next++ = thischar;
			remain++;
		}
		next = buf;
	}
	*c = *((Schar *)next++);
	remain--;
	return;
}

/******************************************************************************\
|Routine: ttyend
|Callby: init_term ttyput
|Purpose: Terminates connection with the terminal.
|Arguments:
|    none
\******************************************************************************/
void ttyend()	/* this is a handler that restores the terminal settings at image exit */
{
	if(restored++)
		return;
	return;
}

void ttystart()
{
	KBDINFO kbstInfo;

	kbstInfo.cb = sizeof(kbstInfo);		/* Length of status buffer */
	if(KbdGetStatus(&kbstInfo, 0))
	{
		printf("KbdGetStatus failed!\n");
		cleanup(-1);
	}
	saveshift = kbstInfo.fsState;
	restored = 0;
}

#else		/* !GNUOS2 */

#ifdef GNUDOS
#include <stdlib.h>
#include <pc.h>
#include <dos.h>
#include <eventque.h>

#define Qsize 100		/* number of interrupt events to queue */
EventQueue *q = 0;
static short *screen_base = NULL;
static short saveshift = 0;	/* shift flags from previous keystroke */
static char setnumlk = 1;	/* reset NumLock */
extern long __transfer_buffer;	/* Can we directly touch hardware? */

/******************************************************************************\
|Routine: ttygetsb
|Callby: put
|Purpose: Returns video buffer base.
|Arguments:
|    ptr - physical video frame buffer base pointer.
\******************************************************************************/
void ttygetsb(ptr)
short **ptr;
{
	*ptr = screen_base;
}

/******************************************************************************\
|Routine: ttyscreen
|Callby: put
|Purpose: Updates screen buffer and positions cursor (DOS & OS2 only).
|Arguments:
|    row, col - where to position the cursor on the screen, zero based.
\******************************************************************************/
void ttyscreen(row,col)
Int row,col;
{
	if(!__transfer_buffer)		/* then protected mode, copy LVB */
		ScreenUpdate(screen_base);
	ScreenSetCursor(row,col);
}

/******************************************************************************\
|Routine: ttysetsize
|Callby: init_term
|Purpose: Handles defaults for terminal size.
|Arguments:
|    NROW,NCOL - the number of rows and columns on the screen.
\******************************************************************************/
void ttysetsize(nrow,ncol)
Int *nrow,*ncol;
{
	Uchar pcrow,pccol;
	union REGS regs;
	char *numlkt;

	pcrow = ScreenRows();
	pccol = ScreenCols();

	if(*ncol > pccol)		/* User wants more columns, set to 132 (max) */
	{
		regs.x.ax = 0x23;		/* Try Pro II 132x25 mode */
		int86(0x10, &regs, &regs);
	}

	if(*nrow > pcrow)		/* User wants more rows, use 8x8 font */
	{
		regs.x.ax = 0x1202;
		regs.x.bx = 0x30;
		int86(0x10, &regs, &regs);	/* Set 400 scan lines */

		regs.x.ax = 0x1112;
		regs.x.bx = 0;
		int86(0x10, &regs, &regs);	/* Set font and reprogram */
	}

	/* Indicate final resolution (may or may not change from above) */
	*nrow = ScreenRows();
	*ncol = ScreenCols();
	if(__transfer_buffer)		/* direct access OK */
		screen_base = ScreenPrimary;	/* From pc.h (short *)0xe00b8000L; */
	else						/* Protected mode need buffer */
		screen_base = (short *)imalloc( *nrow * *ncol * sizeof(short) );

	if((numlkt = getenv("ED_NUMLK")) && *numlkt == 'N') setnumlk = 0;
}

/******************************************************************************\
|Routine: ring_bell
|Callby: init_term
|Purpose: Handles special bell-ringing for non-terminal PC terminals.
|Arguments:
|    none
\******************************************************************************/
void ring_bell()
{
	sound(320);			/* Frequency 320 Hz */
	delay(100);			/* 100 ms duration */
	nosound();
}

/******************************************************************************\
|Routine: ttyput
|Callby: put
|Purpose: Null routine.
|Arguments:
|    c is the string to send to the terminal.
\******************************************************************************/
void ttyput(c)
Char *c;
{
}

/******************************************************************************\
|Routine: ttychk
|Callby: load_file
|Purpose: Null routine.
|Arguments:
|    none
\******************************************************************************/
Int ttychk()
{
	return(0);
}

/******************************************************************************\
|Routine: ttyget
|Callby: cfg init_term
|Purpose: Gets a character from the terminal.
|Arguments:
|    c is the returned character.
\******************************************************************************/
void ttyget(c)
Schar *c;
{
	static Char buf[2],*next = buf;
	static Int remain = 0;

	EventRecord e;
	short shift, bshift, keyqptr[2];
	unsigned evtcode,scan,asci;
	Uchar thischar;

	while(!remain)
	{
		next = buf;
		if(q) {
			while(!EventQueueNextEvent(q,&e) || e.evt_type != EVENT_KEYBD);	/* Another event */
			shift = e.evt_kbstat;
			if(KB_NUMLOCK & (shift ^ saveshift))		/* NumLock */
			{
				*next++ = 0xaf;
				remain++;
			}
			dosmemget(0x417,2,&bshift);
			if(setnumlk && !q->evq_cursize && !(KB_NUMLOCK & bshift)) {
				saveshift = KB_NUMLOCK | bshift;
				dosmemput(&saveshift,2,0x417);
			} else
				saveshift = shift;
			evtcode = (e.evt_scancode & 0xffff);
		} else {
			union REGS regs;
			
			regs.x.ax = 0x1000;
			int86(0x16, &regs, &regs);	/* Read a character, wait */
			evtcode = (regs.x.ax & 0xffff);
			dosmemget(0x417,2,&shift);	/* Assumes curr shift state for press */
			if(KB_NUMLOCK & (shift ^ saveshift))		/* NumLock */
			{
				*next++ = 0xaf;
				remain++;
			}
			dosmemget(0x41a,4,keyqptr);
			if(setnumlk && (keyqptr[0] == keyqptr[1])&& !(KB_NUMLOCK & shift)) {
				saveshift = KB_NUMLOCK | shift;
				dosmemput(&saveshift,2,0x417);
			} else
				saveshift = shift;
		}
		scan = evtcode >> 8;
		asci = evtcode & 0xff;
		if(evtcode == 0x0e08)		/* Rubout */
			thischar = 127;
		else if(asci > 0 && scan <= 0x35)	/* If Caps Lock on then it is Caps! */
		{
			if((KB_CAPSLOCK & shift) && asci >= 'a' && asci <= 'z')
				asci -= 0x20;
			thischar = asci;
		}
		else if(scan == 0x39)		/* Space */
			thischar = ' ';
		else if(scan >= 0x47 && scan <= 0x53)	/* 13 characters between 0x00 and 0x0c (Keypad & Arrows) */
			thischar = ((asci == 0xe0)? 0xa0 : 0xb0) + (scan - 0x47);
		else if(evtcode == 0xe00d)	/* KpEnter */
			thischar = 0xbd;
		else if(evtcode == 0xe02f)	/* PF2 */
			thischar = 0xbe;
		else if(evtcode == 0x372a)	/* PF3 */
			thischar = 0xbf;
		else if(evtcode == 0x0300)	/* Null */
			thischar = 0;
/* 10 characters between 0x00 and 0x09 (F1 to F10) */
		else if(scan >= 0x3b && scan <= 0x44)
			thischar = 0xc0 + (scan - 0x3b);
		else if(evtcode == 0x8500)	/* F11 */
			thischar = 0xca;
		else if(evtcode == 0x8600)	/* F12 */
			thischar = 0xcb;
		else
			thischar = 0xff;		/* indicate not set */

		if(thischar >= 0xb0 && thischar <= 0xbf) /* shift special */
			if(KB_SHIFT & shift) thischar -= 0x10;

		if(thischar != 0xff)
		{
			*next++ = thischar;
			remain++;
		}
		next = buf;
	}
	*c = *((Schar *)next++);
	remain--;
	return;
}

/******************************************************************************\
|Routine: ttyend
|Callby: init_term ttyput
|Purpose: Terminates connection with the terminal.
|Arguments:
|    none
\******************************************************************************/
void ttyend()	/* this is a handler that restores the terminal settings at image exit */
{
	if(restored++)
		return;
	EventQueueDeInit();
	return;
}

void ttystart()
{
	q = EventQueueInit(Qsize,320,NULL);
	if(q) q->evq_drawmouse = 0;
	dosmemget(0x417,2,&saveshift);
	restored = 0;
}

#else		/* !GNUDOS */

#include "unistd.h"
#ifdef NeXT
#include <sgtty.h>
static struct sgttyb savetty;
#else
#include <termios.h>
static struct termios savetty;
#endif
#include <fcntl.h>
#include <signal.h>

static Int ttyfd;

/******************************************************************************\
|Routine: ttygetsb
|Callby: put
|Purpose: Null routine.
|Arguments:
|    ptr - physical video frame buffer base pointer.
\******************************************************************************/
void ttygetsb(ptr)
short **ptr;
{
}

/******************************************************************************\
|Routine: ttyscreen
|Callby: put
|Purpose: Null routine.
|Arguments:
|    row, col - where to position the cursor on the screen, zero based.
\******************************************************************************/
void ttyscreen(row,col)
Int row,col;
{
}

/******************************************************************************\
|Routine: ttysetsize
|Callby: init_term
|Purpose: Handles defaults for terminal size.
|Arguments:
|    nrow, ncol - the number of rows and columns on the screen.
\******************************************************************************/
void ttysetsize(nrow,ncol)
Int *nrow,*ncol;
{
	if(!*nrow)
		*nrow = 34;
	if(!*ncol)
		*ncol = 80;
}

/******************************************************************************\
|Routine: ring_bell
|Callby: init_term
|Purpose: Handles special bell-ringing for brain-dead terminals.
|Arguments:
|    none
\******************************************************************************/
void ring_bell()
{
}

/******************************************************************************\
|Routine: ttyput
|Callby: put
|Purpose: Puts characters to the terminal.
|Arguments:
|    c is the string to send to the terminal.
\******************************************************************************/
void ttyput(c)
Char *c;
{
	Int i;

	if(!(i = strlen(c)))
		return;
	while(i > 64)
	{
		write(ttyfd,c,64);
		c += 64;
		i -= 64;
	}
	if(i)
		write(ttyfd,c,i);
}

/******************************************************************************\
|Routine: ttyget
|Callby: cfg init_term
|Purpose: Gets a character from the terminal.
|Arguments:
|    c is the returned character.
\******************************************************************************/
void ttyget(c)
Schar *c;
{
	static Char buf[8],*next = buf;
	static Int remain = 0;

	if(!remain)
	{
		remain = read(ttyfd,buf,8);
		next = buf;
	}
	*c = *((Schar *)next++);
	remain--;
}

/******************************************************************************\
|Routine: ttyend
|Callby: init_term ttyput
|Purpose: Terminates connection with the terminal.
|Arguments:
|    none
\******************************************************************************/
void ttyend()	/* this is a handler that restores the terminal settings at image exit */
{
	if(restored++)
		return;
#ifdef NeXT
	ioctl(ttyfd,TIOCSETP,&savetty);
#else
	tcsetattr(ttyfd,TCSANOW,&savetty);
#endif
	close(ttyfd);
	signal(SIGINT,SIG_DFL);
	return;
}

/******************************************************************************\
|Routine: ttystart
|Callby: init_term ttyput
|Purpose: Initiates connection with the terminal.
|Arguments:
|    none
\******************************************************************************/
void ttystart()
{
#ifdef NeXT
	struct sgttyb newtty;
#else
	struct termios newtty;
	Char termname[L_ctermid];
#endif
	Int i;

#ifdef NeXT
	if((ttyfd = open("/dev/tty",O_RDWR)) < 0)
	{
		printf("Unable to open terminal /dev/tty.\n");
#else
	if((ttyfd = open(ctermid(termname),O_RDWR)) < 0)
	{
		printf("Unable to open terminal %s.\n",termname);
#endif
		exit(1);
	}
#ifdef NeXT
	if(ioctl(ttyfd,TIOCGETP,&savetty) == -1)
#else
	if(tcgetattr(ttyfd,&savetty) == -1)
#endif
	{
		printf("Unable to read terminal characteristics.\n");
		exit(1);
	}
	newtty = savetty;
#ifdef NeXT
	newtty.sg_flags |= RAW | CBREAK;
	newtty.sg_flags &= ~(CRMOD | ECHO);
	if(ioctl(ttyfd,TIOCSETP,&newtty) == -1)
#else
	newtty.c_lflag &= ~(ICANON | ISIG | ECHO);
	newtty.c_oflag &= ~OPOST;
	newtty.c_iflag &= ~(INLCR | ICRNL | IUCLC | ISTRIP | BRKINT);
	newtty.c_cflag |= HUPCL;
/*	newtty.c_cflag &= ~CLOCAL;*/
	for(i = 0;i < 16;i++)
		newtty.c_cc[i] = 0;
	newtty.c_cc[VMIN] = 5;	/* terminate io if 5 chars arrive... */
	newtty.c_cc[VTIME] = 1;	/* ...or 10 ms elapse */
	if(tcsetattr(ttyfd,TCSANOW,&newtty) == -1)
#endif
	{
		printf("Unable to set terminal to raw mode.\r\n");
		perror("ttyput");
		exit(1);
	}
	signal(SIGINT,ttyend);
	restored = 0;
}

/******************************************************************************\
|Routine: ttychk
|Callby: load_file
|Purpose: Checks for a character waiting, and returns it.
|Arguments:
|    none
\******************************************************************************/
Int ttychk()
{
	Int flags,retval;
	Char buf;
	
	retval = -1;
	if((flags = fcntl(ttyfd,F_GETFL,0)) != -1)
		if(fcntl(ttyfd,F_SETFL,flags | O_NDELAY) != -1)
		{
			if(read(ttyfd,&buf,1) == 1)
				retval = buf;
			fcntl(ttyfd,F_SETFL,flags);
		}
	return(retval);
}

#endif		/* GNUDOS */

#endif		/* GNUOS2 */

#endif		/* VMS */

/******************************************************************************\
|Routine: cleanup
|Callby: cfg imalloc init_term journal main parse_fnm restore_par slip_message
|Purpose: Does all cleanup on image exit.
|Arguments:
|    STATUS - the value to pass to exit().
\******************************************************************************/
void cleanup(status)
Int status;
{
	ttyend();
#ifdef VMS
	exit((status < 0)? 0 : 1);
#else
	exit(status);
#endif
}

