#ifdef OSK
/* OS- and machine-dependent stuff for OS-9
 * Copyright 1993 Brian A. Lantz, KO4KS
 */
#include <stdio.h>
#include <conio.h>
#include <dir.h>
#include <dos.h>
#include <io.h>
#include <direct.h>
#include <sys/stat.h>
#include <string.h>
#include <process.h>
#include <fcntl.h>
#include <alloc.h>
#include <stdarg.h>
#include <bios.h>
#include "global.h"
#include "config.h"
#include "mbuf.h"
#include "proc.h"
#include "iface.h"
#include "internet.h"
#include "tty.h"
#include "socket.h"
#include "smtp.h"
#include "cmdparse.h"
#include "dirutil.h"
#include "pc.h"
#include <modes.h>
#include "i8250.h"
#include <sgstat.h>
#include <time.h>

#define	CTLC	0x3
#define	DEL	0x7f

static int kbchar __ARGS((void));
extern int Curdisp;
extern struct proc *Display;
FILE *Rawterm;
volatile int Tick;
int32 Clock;
chtype MY_NORMAL;
char Hashtab[256];
extern char Eol[];
extern int _gs_size(), _gs_gfd(), _gs_opt(), spawnvp();
extern void _ss_opt(), clreol(), clrscr();

extern int Tracesession;
extern char **environ;
extern struct session *ScreenOwner;		/* Session currently displayed */
extern struct session *Trace;
extern int SYSback, SYSfore;
extern TERMINAL *curses_in;

int Watchdog = 0;			/* Watch Dog off by default */
int WDTick = 300*(1000 / MSPTICK);	/* 5 minutes watchdog timer */
int WDCurr = 300*(1000 / MSPTICK);	/* Initial count down timer */
short UseCurses = 0;
int FIX1, FIX2;

static char Ttbuf[BUFSIZ];
static char Tsbuf[BUFSIZ];

/* Keyboard input buffer */
#define	KBSIZE	256
static struct {
	int buf[KBSIZE];
	int *wp;
	int *rp;
	int cnt;
} Keyboard;

int
errhandler(errval,ax,bp,si)
int errval,ax,bp,si;
{
	return 3;	/* Fail the system call */
}

struct sgbuf svbuf;

/* Called at startup time to set up console I/O, memory heap */
void
ioinit()
{
struct sgbuf sbuf;

	setbuf(stdout,Tsbuf);

	Rawterm = fdopen (dup(1), "w");
	setbuf(Rawterm,Ttbuf);
	if (UseCurses)	{
		initscr();
		if (has_colors ())
			MY_NORMAL = (COLOR_BLACK <<20) + (COLOR_BLUE <<16);
		else
			MY_NORMAL = A_NORMAL;
		keypad (stdscr, 1);
	}
        _gs_opt(0, &sbuf);
        _gs_opt(0, &svbuf);
        sbuf.sg_case = 0;
        sbuf.sg_backsp = 0;
        sbuf.sg_delete = 0;
        sbuf.sg_echo = 0;
/*        sbuf.sg_alf = 0;	*/
        sbuf.sg_nulls = 0;
        sbuf.sg_pause = 0;
        sbuf.sg_page = 0;
        sbuf.sg_bspch = 0;
        sbuf.sg_dlnch = 0;
        sbuf.sg_eorch = 0;
        sbuf.sg_eofch = 0;
        sbuf.sg_rlnch = 0;
        sbuf.sg_dulnch = 0;
        sbuf.sg_psch = 0;
/*      sbuf.sg_kbich = 0;
        sbuf.sg_kbach = 0;	*/
        sbuf.sg_bsech = 0;
        sbuf.sg_bellch = 0;
/*      sbuf.sg_xon = 0;
        sbuf.sg_xoff = 0;
        sbuf.sg_tabcr = 0;
        sbuf.sg_tabsiz = 0;	*/
        _ss_opt(0, &sbuf);

	/* Initialize keyboard queue */
	Keyboard.rp = Keyboard.wp = Keyboard.buf;

}
/* Called just before exiting to restore console state */
void
iostop()
{
	struct iface *ifp,*iftmp;
	void (**fp)();

        _ss_opt(0, &svbuf);
	for(ifp = Ifaces;ifp != NULLIF;ifp = iftmp){
		iftmp = ifp->next;
		if_detach(ifp);
	}
	/* Call list of shutdown functions */
	for(fp = Shutdown;*fp != NULLVFP;fp++)
		(**fp)();
	if (UseCurses)	{
		wattrset (stdscr,MY_NORMAL);
		clear ();
		wrefresh (stdscr);
		endwin();
		UseCurses = 0;
	}
}
#ifdef SHELL
/* Spawn subshell */
int
doshell(argc,argv,p)
int argc;
char *argv[];
void *p;
{
char *command;
int ret;
char *myargv[3];

	if(argc == 1) {
		if((command = getenv("SHELL")) == NULLCHAR)
			command = "SHELL";
		puts ("Type 'LOGOUT' (or press <ESC>) to return to TNOS");
		myargv[0] = command;
		myargv[1] = "-p=\"\lTNOS-OS9: \"";
		myargv[2] = (char *) 0;
 		ret = spawnvp(P_WAIT,command,myargv);
	} else 
		ret = spawnvp(P_WAIT,argv[1],(argv + 1));
	return ret;
}
#endif

#ifdef ALLCMD
/* Spawn mailer as subshell */
int
dobmail(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	char *command;
	int ret;

	if((command = getenv("MAILER")) == NULLCHAR)
		command = "BM";
	ret = spawnvp(P_WAIT,command,argv);

	smtptick(NULL);		/* tickle smtp to send any mail */
	return ret;
}
#endif /*ALLCMD*/

/* if watch-dog mode is set - make NOS reboot the system if it stalls */
dowatchdog(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	return setbool(&Watchdog,"TNOS Watch Dog",argc,argv);
}

/* Keyboard interrupt handler */
void
kbint()
{
int sig = 0;
int c;

	while((c = kbraw()) != -1 && Keyboard.cnt < KBSIZE){
		sig = 1;
		*Keyboard.wp++ = c;
		if(Keyboard.wp == &Keyboard.buf[KBSIZE])
			Keyboard.wp = Keyboard.buf;
		Keyboard.cnt++;
#ifdef SCREENSAVER
		sskick();
#endif
	}
	if(sig){
		psignal(&Keyboard,0);
	}
}

static int
kbchar()
{
int c;

	while(Keyboard.cnt == 0)
		pwait(&Keyboard);
	Keyboard.cnt--;
	c = *Keyboard.rp++;
	if(Keyboard.rp == &Keyboard.buf[KBSIZE])
		Keyboard.rp = Keyboard.buf;
	return (c);
}
/* Flush the raw terminal output */
void
rflush()
{
	if (!UseCurses)
		fflush(Rawterm);
	else	{
#ifdef SCREENSAVER
		if (!ssenabled())	{
#endif
			if (ScreenOwner->split)
				wrefresh (ScreenOwner->screen->splitwin);
/*			leaveok (ScreenOwner->screen->textwin, 0);	*/
			wrefresh (ScreenOwner->screen->textwin);
			if (ScreenOwner->screen->statline)
				wrefresh (ScreenOwner->screen->statwin);
#ifdef SCREENSAVER
		}
#endif
	}
}

#ifdef ALLCMD
struct funcstr {
	short fkey;
	char alloced;
	char *fvalue;
};

struct funcstr fkeys[] = {
	KEY_BTAB,0,NULLCHAR,		/* tab + shift */
	KEY_F1,1,NULLCHAR,  		/* F1 */
	KEY_F2,1,NULLCHAR,  		/* F2 */
	KEY_F3,1,NULLCHAR,  		/* F3 */
	KEY_F4,1,NULLCHAR,  		/* F4 */
	KEY_F5,0,NULLCHAR,		/* F5 */
	KEY_F6,0,NULLCHAR,		/* F6 */
	KEY_F7,0,NULLCHAR,		/* F7 */
	KEY_F8,0,NULLCHAR,		/* F8 */
	KEY_F9,0,NULLCHAR,		/* F9 */
	KEY_F10,0,NULLCHAR,		/* F10 */
	KEY_HOME,1,NULLCHAR,		/* home*/
	KEY_UP,1,"\033[A",		/* up arrow*/
	KEY_PPAGE,1,NULLCHAR,		/* pgup */
	KEY_LEFT,1,"\033[D",		/* left arrow */
	KEY_RIGHT,1,"\033[C",		/* right arrow */
	KEY_END,1,NULLCHAR,		/* end */
	KEY_DOWN,1,"\033[B",		/* down arrow */
	KEY_NPAGE,1,NULLCHAR,		/* pgdn */
	KEY_IC,1,NULLCHAR,		/* ins */
	KEY_DC,1,NULLCHAR,		/* del */
	KEY_SF1,0,NULLCHAR,		/* F1 + shift*/
	KEY_SF2,0,NULLCHAR,		/* F2 + shift*/
	KEY_SF3,0,NULLCHAR,		/* F3 + shift*/
	KEY_SF4,0,NULLCHAR,		/* F4 + shift*/
	KEY_SF5,0,NULLCHAR,		/* F5 + shift*/
	KEY_SF6,0,NULLCHAR,		/* F6 + shift*/
	KEY_SF7,0,NULLCHAR,		/* F7 + shift*/
	KEY_SF8,0,NULLCHAR,		/* F8 + shift*/
	KEY_SF9,0,NULLCHAR,		/* F9 + shift*/
	KEY_SF10,0,NULLCHAR,		/* F10 + shift*/
	KEY_CTL_F1,0,NULLCHAR,		/* F1 + control*/
	KEY_CTL_F2,0,NULLCHAR,		/* F2 + control*/
	KEY_CTL_F3,0,NULLCHAR,		/* F3 + control*/
	KEY_CTL_F4,0,NULLCHAR,		/* F4 + control*/
	KEY_CTL_F5,0,NULLCHAR,		/* F5 + control*/
	KEY_CTL_F6,0,NULLCHAR,		/* F6 + control*/
	KEY_CTL_F7,0,NULLCHAR,		/* F7 + control*/
	KEY_CTL_F8,0,NULLCHAR,		/* F8 + control*/
	KEY_CTL_F9,0,NULLCHAR,		/* F9 + control*/
	KEY_CTL_F10,0,NULLCHAR,		/* F10 + control*/
	KEY_ALTKBD+KEY_F1,0,NULLCHAR,	/* F1 + alt*/
	KEY_ALTKBD+KEY_F2,0,NULLCHAR,	/* F2 + alt*/
	KEY_ALTKBD+KEY_F3,0,NULLCHAR,	/* F3 + alt*/
	KEY_ALTKBD+KEY_F4,0,NULLCHAR,	/* F4 + alt*/
	KEY_ALTKBD+KEY_F5,0,NULLCHAR,	/* F5 + alt*/
	KEY_ALTKBD+KEY_F6,0,NULLCHAR,	/* F6 + alt*/
	KEY_ALTKBD+KEY_F7,0,NULLCHAR,	/* F7 + alt*/
	KEY_ALTKBD+KEY_F8,0,NULLCHAR,	/* F8 + alt*/
	KEY_ALTKBD+KEY_F9,0,NULLCHAR,	/* F9 + alt*/
	KEY_ALTKBD+KEY_F10,0,NULLCHAR,	/* F10 + alt*/
	KEY_SEND,0,NULLCHAR,		/* end  + ctl */
	KEY_SR,0,NULLCHAR,		/* pgup + ctl */
	KEY_SHOME,0,NULLCHAR,		/* home + ctl */
	KEY_SF,0,NULLCHAR,		/* pgdn + ctl */
	  0,0,NULLCHAR
};

char Leftover = 0;
char *Nextkey;
#endif /*ALLCMD*/

/* Read characters from the keyboard, translating them to "real" ASCII.
 * If none are ready, block. The F-10 key is special; translate it to -2.
 */
#ifdef ALLCMD
int
kbread()
{
int c,i,j;

	if((c = Leftover) != 0)  {
		Leftover = *Nextkey++;
		return c;
	}
	c = kbchar();
	if (c < 256)
		return (c);
	switch (c)	{
		case KEY_UP:    /* UP ARROW key (used as previous history command) */
			if(Current == Command) {   
				c = UPARROW;
				break;
			}
			goto all;
		case KEY_DOWN:    /* DOWN ARROW key (used as next history command) */
			if(Current == Command) {
				c = DNARROW;
				break;
			}
			goto all;
	        case KEY_F10:    /* F-10 key (used as command-mode escape) */
			if(fkeys[10].fvalue == NULLCHAR){
				c = -2;
				break;
			}
		        goto all;
	        case KEY_IC:   /* INSERT key (used as status line toggle) */
			if(fkeys[19].fvalue == NULLCHAR){
				c = -105;
				break;
			}
			goto all;
	        case KEY_DC:   /* DELETE key (used as flow mode toggle) */
			if(fkeys[20].fvalue == NULLCHAR){
				c = -106;
				break;
			}
			goto all;
	        case KEY_HOME:   /* HOME key (used to kick this session) */
			if(fkeys[11].fvalue == NULLCHAR){
				c = -107;
				break;
			}
			goto all;
	        case KEY_END:   /* END key (used to kill this session) */
			if(fkeys[16].fvalue == NULLCHAR){
				c = -108;
				break;
			}
			goto all;
	        case KEY_PPAGE:   /* PGUP key (used to toggle to previous session) */
			if(fkeys[13].fvalue == NULLCHAR){
				c = -109;
				break;
			}
			goto all;
	        case KEY_NPAGE:   /* PGDN key (used to toggle to next session) */
			if(fkeys[18].fvalue == NULLCHAR){
				c = -110;
				break;
			}
			goto all;
#ifdef notyet
		case KEY_BACKSPACE:
			c = '\b';
			goto all;
		case KEY_ENTER:
			c = '\n';
			goto all;
#endif
	        default:    /* Dunno what it is */
all:
            if(c > KEY_F0 && c < KEY_F10) {  /* F1 to F9 */
                if(fkeys[c-KEY_F1+1].fvalue == NULLCHAR) {
                    c = ((c - KEY_F1) + 3) * -1; /* NO fkey defined - WG7J */
                    break;
                }
            }
            for(i=0;(j = fkeys[i].fkey) != 0;i++)
				if(j == c) {
					Nextkey = fkeys[i].fvalue;
					if(Nextkey == NULLCHAR) {
						c = -1;
						return c;
					}
					/* If first char of fvalue is '~'
					 * switch to command session.
					 */
					if((c = *Nextkey++) == '~') {
						c = -2;
						Leftover = *Nextkey++;
					} else {
						if(c != 0)
							Leftover = *Nextkey++;
						else
							c = -1;
					}
					return c;
				}
			c = -1;
		}
	return c;
}
#else /*ALLCMD*/

int
kbread()
{
int c;

	c = kbchar();
	if(Current == Command) {    /* Check for command recall */
		if(c == KEY_UP)     /* UP arrow */
			return UPARROW;
		if(c == KEY_DOWN)     /* DOWN arrow */
			return DNARROW;
	}
	if (c < 256)
		return (c);
	switch(c)	{
		case KEY_F10:        /* F-10 key (used as command-mode escape) */
			c = -2;
			break;
		case KEY_DL:        /* DEL key */
			c = 0x7f;
			break;
		case KEY_BACKSPACE:
			c = '\b';
			break;
		case KEY_ENTER:
			c = '\n';
			break;
		default:        /* Dunno what it is */
			if(c > KEY_F0 && c < KEY_F10)    /* F1 to F9 */
				c = ((c - KEY_F1) + 3) * -1;
			else
				c = -1;
	}
        return c;
}

#endif /*ALLCMD*/

#ifdef ALLCMD
int
dofkey(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int c,i,j;
char *q, *r;
char str[100];

	if(argc == 1) {
	   tprintf("     key   num    key    num    key    num    key    num   key    num\n");
	   tprintf("     f1    265    sf1    281    cf1    297    af1    393   pgup   339\n");
	   tprintf("     f2    266    sf2    282    cf2    298    af2    394   pgdn   338\n");
	   tprintf("     f3    267    sf3    283    cf3    299    af3    395   home   262\n");
	   tprintf("     f4    268    sf4    284    cf4    300    af4    396   end    360\n");
	   tprintf("     f5    269    sf5    285    cf5    301    af5    397   arup   259\n");
	   tprintf("     f6    270    sf6    286    cf6    302    af6    398   ardn   258\n");
	   tprintf("     f7    271    sf7    287    cf7    303    af7    399   ar l   260\n");
	   tprintf("     f8    272    sf8    288    cf8    304    af8    400   ar r   261\n");
	   tprintf("     f9    273    sf9    289    cf9    305    af9    401   ins    331\n");
	   tprintf("     f10   274    sf10   290    cf10   306    af10   402   del    330\n");
	   tprintf("     cpgup 337    cpgdn  336    chome  391    cend   386   stab   353\n\n");
	   tprintf("usage: fkey <key number> [<value> | \"string\"]\n");
	   return 0;
	}

	c = atoi(argv[1]);
	if(c < KEY_BREAK || c > KEY_SF20+KEY_ALTKBD) {
		tprintf("fkey number out of range.\n");
		return 1;
	}

	for(j = 0;(i = fkeys[j].fkey) != 0; j++)
		if(i == c) 
			break;

	if(i == 0){
		tprintf("fkey number not found\n");
		return 1;
	}

	if(argc == 2) {
		q = fkeys[j].fvalue;
		r = str;
		if(q == NULLCHAR)
			tprintf("fkey %d has no assigned value.\n",c);
		else {
			while(*q)
				if(*q < ' ') { /* This is ASCII dependent !! */
					*r++ = '^';
					*r++ = *q++ + 0x40;
				} else
					*r++ = *q++;
			*r = '\0';
			tprintf("fkey = %s\n",str);
		}
		return 0;
	}

	if(argc == 3) {
		if(fkeys[j].alloced)
			fkeys[j].alloced = 0;
		else
			if(fkeys[j].fvalue != NULLCHAR)
				free(fkeys[j].fvalue);

		r = str;
		q = argv[2];
		while(*q){
			if(*q == '^'){	/* ^ gives control char next */
				q++;
				if(*q == '^') {
					*r++ = *q++; /* No, he wants a ^ */
				} else {
					*r++ = *q++ & 0x1f;
				}
			} else
				*r++ = *q++;
		}
		*r = '\0';
		fkeys[j].fvalue = strdup(str);
	}
	return 0;
}
#endif /*ALLCMD*/

/* Called on each NOS clock tick. Signal a clock tick to the timer process.
 */
void
ctick()
{
	if(Watchdog)
		if(WDCurr-- == 0)
			sysreset();	
	Tick++;
	psignal(&Tick,1);
}
/* Called from the timer process on every tick. NOTE! This function
 * can NOT be called at interrupt time because it calls the BIOS
 */
void
pctick()
{
	Clock = clock() / 2;
}

/* Convert a pointer to a long integer */
long
ptol(p)
void *p;
{
	return ((long) p);
}

void *
ltop(l)
long l;
{
	return (l);
}


void
sysreset()
{
#asm
	move.l	0,a7
	move.l	4,a0
	jmp 	(a0)
#endasm
}

extern unsigned char SCREENwidth, SCREENlength;
extern int STATLINE;

void
newscreen(sp)
struct session *sp;
{
struct session *old;

	if(sp != NULLSESSION)	{
		sp->screen = callocw(1,sizeof(struct screen));
		sp->screen->statline = STATLINE;
		sp->screen->attr = MY_NORMAL >> 16;
		if (UseCurses)		{
			sp->screen->win = sp->screen->textwin = newwin (24 - (sp->split * 2), 80, 0, 0);
			if (sp->split)	{
				sp->screen->splitwin = newwin (2, 80, 22, 0);
				leaveok (sp->screen->splitwin, 1);
				if (!has_colors())
					wattrset (sp->screen->splitwin, A_REVERSE);
				else
					wattrset (sp->screen->splitwin, (SYSback >> 4)+(SYSfore << 4));
				werase (sp->screen->splitwin);
				waddch (sp->screen->splitwin, '_');
				wmove (sp->screen->splitwin, 0, 0);
			}
			scrollok (sp->screen->win, 1);
			if (has_colors())
				sp->screen->attr = (SYSback+SYSfore) >> 16;
			wattrset (sp->screen->win, sp->screen->attr << 16);
			wclear (sp->screen->win);
		}
	}
}
void
freescreen(sp)
struct session *sp;
{
	if(sp == NULLSESSION || sp->screen == NULLSCREEN)
		return;
	if (UseCurses)	{
		delwin (sp->screen->textwin);
		if (sp->split)
			delwin (sp->screen->splitwin);
		if (sp->screen->statline)
			delwin (sp->screen->statwin);
	}
	free((char *)sp->screen);
}


/* Save specified session screen and resume console screen */
void
swapscreen(old,new)
struct session *old,*new;
{
	if (old != NULLSESSION && UseCurses)
		rflush ();
	ScreenOwner = new;
	if (new != NULLSESSION && UseCurses)		{
		touchwin (new->screen->textwin);
		if (new->split)
			touchwin (new->screen->splitwin);
		if (new->screen->statwin)
			touchwin (new->screen->statwin);
		displayStatLine (0, 1);
		rflush ();
	}
	alert(Display,1);	/* Wake him up */
}

void
display(i,v1,v2)
int i;
void *v1;
void *v2;
{
	int c;
	struct session *sp;

	/* This is very tricky code. Because the value of "Current" can
	 * change any time we do a pwait, we have to be careful to detect
	 * any change and go back and start again.
	 */
	for(;;){
		sp = Current;

		if(sp->morewait){
			pwait(&sp->row);
			if(sp != Current || sp->row <= 0){
				/* Current changed value, or the user
				 * hasn't really hit a key
				 */
				continue;
			}
			/* Erase the prompt */
			if (UseCurses)	{
#ifdef SCREENSAVER
				sskick();
#endif
				waddstr(ScreenOwner->screen->win,"\b\b\b\b\b\b\b\b        \b\b\b\b\b\b\b\b");
			} else
				fprintf(Rawterm,"\b\b\b\b\b\b\b\b        \b\b\b\b\b\b\b\b");
			rflush();
		}
		sp->morewait = 0;
		if((c = rrecvchar(sp->output)) == -1){
			/* the alert() in swapscreen will cause this to
			 * return -1 when current changes
			 */
			pwait(NULL);	/* Prevent a nasty loop */
			continue;
		}
#ifdef SCREENSAVER
		sskick ();
#endif
		if (c == '\l')
			continue;
		if(c == '\n'){
			cputs(Eol);
/*			clreol();	*/
		} else
			putch(c);
        /* Fix by Ron Murray, vk6zjm */
        if(sp->record != NULLFILE)      /* Don't save CR if ascii mode */
            if (c != '\l' || sockmode(sp->output, -1) != SOCK_ASCII)
                putc(c,sp->record);
        if(sp->flowmode && c == '\n' && --sp->row <= 0){
        	if (!UseCurses)
			fprintf(Rawterm,"--More--");
		else	{
#ifdef SCREENSAVER
			sskick();
#endif
			waddstr(ScreenOwner->screen->win,"--More--");
		}
		sp->morewait = 1;
		}
	}
}
/* Return time since startup in milliseconds. */
int32
msclock()
{
	return Clock * MSPTICK;
}
/* Return clock in seconds */
int32
secclock()
{
	return Clock * MSPTICK / 1000L;
}

/* same as getenv(), but return "" instead of NULL when it does not exist */
char *getnenv (name)
char *name;
{
	char *rv;

	if ((rv = getenv(name)) == NULL)
		 rv = "";			/* NULL replaced by "" */

	return rv;
}

int TNOS_68KAlarm;

int
housekeeping (sig)
int sig;
{
	switch (sig)	{
		case 3:		if (UseCurses)	{
					endwin();
					UseCurses = 0;
					clrscr();
				}
				_ss_opt(0, &svbuf);	
				exit (0);
				break;
		case 6809:	ctick();
		default:	break;
	}
}


void
oskinit()
{
	intercept (housekeeping);
	TNOS_68KAlarm = alm_cycle (6809, 2);
}


_dos_getfileattr (file, attr)
char *file;
unsigned *attr;
{
FILE *fp;
struct fildes b;

	if ((fp = fopen (file, "r")) == NULLFILE)
		if ((fp = fopen (file, "d")) == NULLFILE)
			return -1;
	_gs_gfd (fileno(fp), &b, sizeof (struct fildes));
	fclose (fp);
	*attr = (b.fd_att & 0x80) ? FA_DIREC : 0;
	return 0;
}

int
putch (c)
int c;
{
static short lastwasCR = 0;
	
	if (c == '\l' && !lastwasCR)	{
		FIX1++;
		c = '\n';
	}
	lastwasCR = (c == '\n') ? 1 : 0;
	if (!UseCurses)	{
		if (c != '\l')
			putchar (c);
		return 0;
	}
	if (c == '\007')
		beep ();
	else	{
#ifdef SCREENSAVER
		sskick();
#endif
		waddch (ScreenOwner->screen->win, c);
		if (c == '\n')	{
			waddch (ScreenOwner->screen->win, '\l');
			rflush ();
		}
	}
	return 0;
}

void
highvideo ()
{
int back, fore;

	if (UseCurses && has_colors())	{
#ifdef SCREENSAVER
		sskick();
#endif
		fore = (ScreenOwner->screen->attr & 0x0f);
		fore = (fore) ? fore - 1 : 7;
		fore <<= 16;
		back = (ScreenOwner->screen->attr & 0xf0) << 16;
		wattrset (ScreenOwner->screen->win, back+fore);
	}
}

void
lowvideo()
{
int back, fore;

	if (UseCurses && has_colors())	{
#ifdef SCREENSAVER
		sskick();
#endif
		wattrset (ScreenOwner->screen->win, ScreenOwner->screen->attr << 16);
	}
}

int
cputs (str)
char *str;
{
	while (*str)
		putch (*str++);
	return 0;
}

void
clreol ()
{
	if (UseCurses)	{
#ifdef SCREENSAVER
		sskick ();
#endif
		wclrtoeol (ScreenOwner->screen->win);
	}
}

void
clrscr ()
{
int k;

	if (UseCurses)	{
#ifdef SCREENSAVER
		sskick();
#endif
		werase (ScreenOwner->screen->win);
		wrefresh (ScreenOwner->screen->win);
	} else	{
		for (k = 0; k < 24; k++)
			putchar ('\n');
	}
}

int
wherey ()
{
int y = 0, x;

	if (UseCurses)	{
#ifdef SCREENSAVER
		sskick();
#endif
		getyx (ScreenOwner->screen->win, y, x);
	}
	return y;
}

int
wherex ()
{
int y, x = 0;

	if (UseCurses)	{
#ifdef SCREENSAVER
		sskick();
#endif
		getyx (ScreenOwner->screen->win, y, x);
	}
	return x;
}

void
gotoxy (x, y)
int x, y;
{
	if (UseCurses)	{
#ifdef SCREENSAVER
		sskick();
#endif
		wmove (ScreenOwner->screen->win, y, x);
	}
}

void
hardretn (i)
int i;
{
}

unsigned long
farcoreleft ()
{
	return (coreleft());
}

int
fputc (c, fp)
int c;
FILE *fp;
{
	return (putc (c, fp));
}

void
getdate (datep)
struct date *datep;
{
int time, date, tick;
short day, *sp;
char *cp;

	_sysdate (0, &time, &date, &day, &tick);
	sp = (short *) &date;
	datep->da_year = *sp++;
	cp = (char *) sp;
	datep->da_mon = *cp++;
	datep->da_day = *cp;
}

void
gettime (timep)
struct time *timep;
{
int time, date, tick;
short day;
char *cp;

	_sysdate (0, &time, &date, &day, &tick);
	cp = (char *) &time;
	cp++;
	timep->ti_hour = *cp++;
	timep->ti_min = *cp++;
	timep->ti_sec = *cp;
	cp = (char *) &tick;
	cp += 3;
	timep->ti_hund = *cp;
}

int dirps ()
{
}

void restore (c)
char c;
{
}

int istate()
{
	return (1);
}

int
spawnvp (mode,path,argv)
int mode;
char *path, *argv[];
{
int retval, status, w;
struct sgbuf sbuf;

        _gs_opt(0, &sbuf);
        _ss_opt(0, &svbuf);
	if (UseCurses)
		endwin();
	retval = os9exec(os9forkc, path, argv, environ, 0, 0, 3);
        if (retval)
		while ((w = wait(&status)) != retval && w != -1)
			;
        _ss_opt(0, &sbuf);
        if (UseCurses)	{
#ifdef SCREENSAVER
        	sskick();
#endif
        	touchwin (ScreenOwner->screen->win);
        	wrefresh (ScreenOwner->screen->win);
        }
	return (retval);
}

int
getcbrk()
{
	return 0;
}

int
setcbrk(mode)
int mode;
{
	return mode;
}


void
giveup()
{
}

wready ()
{
int stat;

     stat = curses_in->buf_hi_water - curses_in->buf_lo_water;
     if (!stat)          {
          stat = _gs_rdy (fileno (stdin));
          stat = (stat > 0) ? 1 : 0;
          }
     return (stat);
}


kbraw()
{
unsigned char c;
int ci = -1;
static char sendaLF = 0;

#ifdef notagain
	if (sendaLF)	{
		sendaLF = 0;
		return '\l';
	}
	sendaLF = 0;
#endif
	if (UseCurses)	{
		if (wready ())
			ci = wgetch (stdscr);
		if (ci == KEY_ENTER)	{
			ci = '\n';
			sendaLF = 1;
		}
		if (ci == KEY_BACKSPACE)
			ci = '\b';
		return ci;
	} else	{
		if (_gs_rdy(0) < 0)
			return -1;
		read(0, &c, 1);
		if (c == '\n')
			sendaLF = 1;
		return c;
	}
}

int
FP_SEG (i)
int i;
{
	return i;
}

int
FP_OFF (i)
int i;
{
	return i;
}

void *
mallocw(nb)
unsigned nb;
{
	register void *p;

	while((p = malloc(nb)) == NULL){
		sleep (1);
	}
	return p;
}

void *
callocw(nelem,size)
unsigned nelem;	/* Number of elements */
unsigned size;	/* Size of each element */
{
	register unsigned i;
	register char *cp;

	i = nelem * size;
	cp = mallocw(i);
	memset(cp,0,i);
	return cp;
}

/* Return available memory on our heap plus available system memory */
unsigned long
availmem()
{
	return (coreleft());
}


char *
stpcpy (dest, src)
char *dest, *src;
{
	strcpy (dest, src);
	return (dest+strlen(src));
}


long
dostounix (d, t)
struct date *d;
struct time *t;
{
	return 1L;
}

int
stime (t)
time_t *t;
{
	return 0;
}


void
_strtime (str)
char *str;
{
char *cp;
int k;
time_t tm;

	time (&tm);
	cp = ctime (&tm);
	cp += 11;
	for (k = 0; k < 8; k++)
		*str++ = *cp++;
	*str = 0;
}

void
screendaemon (i,v1,v2)
int i;		/* Args not used */
char *v1;
void *v2;
{
	if (!UseCurses)
		return;
	for(;;){
		mspause(500L);	/* Run displayStatLine every 1/2 second */
		displayStatLine (0, 1);
		mspause(500L);	/* and run the rest every second */
		displayStatLine (0, 0);
#ifdef SCREENSAVER
		screensaver ();
#endif
	}
}

#define SOBUF 256

/* Printf to Trace session screen or file. Doesn't use ANSI vsprintf */
int
traceprintf(fp,fmt,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)
FILE *fp;		/* Trace file stream */
char *fmt;		/* Message format */
int arg1,arg2,arg3;	/* Arguments */
int arg4,arg5,arg6;
int arg7,arg8,arg9;
int arg10,arg11,arg12;
{
int len,withargs;
char *buf;

	if(strchr(fmt,'%') == NULLCHAR){
		/* No args, so we don't need vsprintf() */
		withargs = 0;
		buf = fmt;
		len = strlen(fmt);
	} else {
		/* Use a default value that is hopefully longer than the
		 * biggest output string we'll ever print (!)
		 */
		withargs = 1;
		buf = mallocw(SOBUF);
		if((len=sprintf(buf,fmt,arg1,arg2,arg3,arg4,arg5,arg6,arg7,
		    arg8,arg9,arg10,arg11,arg12)) >= SOBUF) {
			/* It's too late to be sorry. He's dead, Jim. */
			log(-1,"traceprintf() has exceeded the size of it's buffer. Restarting TNOS.");
			where_outta_here(1);
		}
	}
	if (UseCurses && (Current == Trace) && (fp == stdout))
		cputs(buf);
	else
		fprintf (fp, buf);

	if(withargs)
		free(buf);
	return len;
}


int16 *
getstack()
{
#asm
	move.l	a7,d0
	addq.l	#4,d0
#endasm
}

#asm
setjmp:	move.l a0,-(a7)
	movea.l d0,a0
	move.l 4(a7),(a0)
	movem.l d0-d7,4(a0)
	movem.l a1-a7,40(a0)
	move.l (a7)+,36(a0)
	moveq.l #0,d0
	rts

longjmp:
	movea.l d0,a0
	movem.l 4(a0),d0-d7
	movem.l 40(a0),a1-a7
	movea.l (a0),a0
	pea.l (a0)
	movea.l 36(a0),a0
	rts
#endasm

#endif /* OSK */

