/****************************************************************************
*                                                                           *
*	st.c - System routines for Atari by David Nash (dnash@chaos.demon.co.uk) *
*                                                                           *
*  This version includes code provided by:-                                 *
*  	Walter Doerr, DG2KK (dg2kk@cup.portal.com) and Rob Janssen PE1CHL     *
*                                                                           *
*	00.01.93 DFN - Initial version														 *
*  28.08.94 DFN - Cleanup, redundent functions deleted.							 *
*						rflush, ptol & ltop now defined as macros in global.h		 *
*                                                                           *
****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <dos.h>		
#include <ext.h>
#include <osbind.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/except.h>

#ifdef OVERSCAN
#include <overscan.h>
#endif

#include "global.h"
#include "session.h"
#include "config.h"
#include "mbuf.h"
#include "internet.h"
#include "iface.h"
#include "st.h"
#include "st_asy.h"
#include "cmdparse.h"
#include "asy.h"
#include "socket.h"

/*
	increase default stacksize
*/

unsigned long _STACK = 16536;

/* Interface list header */

struct iface *ifaces;

static	int32		clksec(void);
static   int32 	iss(void);
volatile int 		Tick = 0;					/* updated by timer interrupt	*/
volatile int32		Clock = 0;					/* updated by timer interrupt */
void		(*etv_timer)();
void     st_tick(void);
static   int Virtual_Interrupt_Enable = 0;

extern int Escape;					/* Escape character - enter command mode	*/
extern struct proc *Display;

/* Prototypes for functions defined in st.c */

void 	ioinit(void);
void 	iostop(void);
void 	__saveds sys_tick(void);
void 	restore_vec(void);
int32 secclock(void);
int32 msclock(void);
int 	kbread(void);
int 	istate(void);
int 	dirps(void);
void 	restore(int foo);
int 	disable(void);
void  dispscreen(int flag);
void  outscreen(int flag);
void 	doshell(int argc, char **argv);
void 	memstat(void);
void 	iosize(int i);
void 	sysreset(void);
void 	set_stdout(int mode);
#if 0
long 	ptol(void *ptr);
void 	*ltop(long l);
void 	rflush(void);
#endif
void 	display(int i, void *v1, void *v2);
void 	*mallocw(unsigned int n);
void 	*callocw(unsigned int n, unsigned int size);
unsigned long availmem(void);


/*---------------------------------------------------------------------------
	define function keys
---------------------------------------------------------------------------*/

struct funcstr {
	char fkey;
	char alloced;
	char *fvalue;
	int  special;
};

static far struct funcstr fkeys[] = {
	{ 15,0,NULLCHAR, 0 },		/* tab + shift 	*/
	{ 59,1,NULLCHAR, 0 },  		/* F1 				*/
	{ 60,1,NULLCHAR, 0 },  		/* F2 				*/
	{ 61,1,NULLCHAR, 0 },  		/* F3 				*/
	{ 62,1,NULLCHAR, 0 },  		/* F4 				*/
	{ 63,0,NULLCHAR, 0 },		/* F5 				*/
	{ 64,0,NULLCHAR, 0 },		/* F6 				*/
	{ 65,0,NULLCHAR, 0 },		/* F7 				*/
	{ 66,0,NULLCHAR, 0 },		/* F8 				*/
	{ 67,0,NULLCHAR, 0 },		/* F9 				*/
	{ 68,0,NULLCHAR, 0 },		/* F10 				*/
	{ 71,1,NULLCHAR, 0 },		/* home				*/
	{ 72,1,NULLCHAR, 0 },		/* up arrow			*/
	{ 73,1,NULLCHAR, 0 },		/* pgup 				*/
	{ 75,1,NULLCHAR, 0 },		/* left arrow 		*/
	{ 77,1,NULLCHAR, 0 },		/* right arrow 	*/
	{ 79,1,NULLCHAR, 0 },		/* end 				*/
	{ 80,1,NULLCHAR, 0 },		/* down arrow 		*/
	{ 81,1,NULLCHAR, 0 },		/* pgdn 				*/
	{ 82,1,NULLCHAR, 0 },		/* ins 				*/
	{ 83,1,NULLCHAR, 0 },		/* del 				*/
	{ 84,0,NULLCHAR, 0 },		/* F1 + shift		*/
	{ 85,0,NULLCHAR, 0 },		/* F2 + shift		*/
	{ 86,0,NULLCHAR, 0 },		/* F3 + shift		*/
	{ 87,0,NULLCHAR, 0 },		/* F4 + shift		*/
	{ 88,0,NULLCHAR, 0 },		/* F5 + shift		*/
	{ 89,0,NULLCHAR, 0 },		/* F6 + shift		*/
	{ 90,0,NULLCHAR, 0 },		/* F7 + shift		*/
	{ 91,0,NULLCHAR, 0 },		/* F8 + shift		*/
	{ 92,0,NULLCHAR, 0 },		/* F9 + shift		*/
	{ 93,0,NULLCHAR, 0 },		/* F10 + shift		*/
	{ 94,0,NULLCHAR, 0 },		/* F1 + control	*/
	{ 95,0,NULLCHAR, 0 },		/* F2 + control	*/
	{ 96,0,NULLCHAR, 0 },		/* F3 + control	*/
	{ 97,0,NULLCHAR, 0 },		/* F4 + control	*/
	{ 98,0,NULLCHAR, 0 },		/* F5 + control	*/
	{ 99,0,NULLCHAR, 0 },		/* F6 + control	*/
	{ 100,0,NULLCHAR, 0 },		/* F7 + control	*/
	{ 101,0,NULLCHAR, 0 },		/* F8 + control	*/
	{ 102,0,NULLCHAR, 0 },		/* F9 + control	*/
	{ 103,0,NULLCHAR, 0 },		/* F10 + control	*/
	{ 104,0,NULLCHAR, 0 },		/* F1 + alt			*/
	{ 105,0,NULLCHAR, 0 },		/* F2 + alt			*/
	{ 106,0,NULLCHAR, 0 },		/* F3 + alt			*/
	{ 107,0,NULLCHAR, 0 },		/* F4 + alt			*/
	{ 108,0,NULLCHAR, 0 },		/* F5 + alt			*/
	{ 109,0,NULLCHAR, 0 },		/* F6 + alt			*/
	{ 110,0,NULLCHAR, 0 },		/* F7 + alt			*/
	{ 111,0,NULLCHAR, 0 },		/* F8 + alt			*/
	{ 112,0,NULLCHAR, 0 },		/* F9 + alt			*/
	{ 113,0,NULLCHAR, 0 },		/* F10 + alt		*/
	{ 114,0,NULLCHAR, 0 },		/* PrtSc + ctl		*/
	{ 117,0,NULLCHAR, 0 },		/* end	+ ctl 	*/
	{ 118,0,NULLCHAR, 0 },		/* pgup + ctl 		*/
	{ 119,0,NULLCHAR, 0 },		/* home + ctl 		*/
	{ 132,0,NULLCHAR, 0 },		/* pgdn + ctl 		*/
	{   0,0,NULLCHAR,0 }
};

char Leftover = 0;
char *Nextkey;

/* #ifdef SCREEN */

void *newscr, *newscradr;	/* 32k memory allocated to 2nd video screen */
void *old_logscr, *old_physcr;
void *new_logscr, *new_physcr;

int toggle = 0;			/* toggle between normal and trace screen */
int printtrace = 0;		/* send trace to printer (controlled by F2) */
/*  #endif */

char  *shell,*getenv();		/* Name of command shell for exec 				*/
int	rows=25;					/* Number of text rows on screen (may be 50) */
FILE	*Rawterm = stdout;	/* console for ttydriv etc							*/


/*---------------------------------------------------------------------------
	ioinit - This routine handles the machine specific setup tasks
---------------------------------------------------------------------------*/

void ioinit()
{
#ifdef OVERSCAN	
unsigned long ptr;
#endif

#define lmalloc(s) malloc(s) 

#ifdef SCREEN
#ifdef OVERSCAN
	if (__sxv(4200) != 4200) {			/* Is OverScan active			*/
		OSCAN_SCREEN	*oscan_scr;
		oscan_scr = (OSCAN_SCREEN *)__pxs(4201, -1);		/* xbios 4201		*/
		newscradr = malloc((oscan_scr->length_of_screen) + 256);

		if (newscradr == NULL)	{
			printf("st.c/ioinit: malloc failed \n");
			exit(-1);
		}
		ptr = (unsigned long)newscradr;
		new_logscr = (void *)(((ptr+256)&0xffffff00L)+ oscan_scr->logbase_offset);
		new_physcr = (void *)(((ptr+256)&0xffffff00L)+ oscan_scr->physbase_offset);
	} 
	else {
		newscradr = malloc(32*1024L);
		ptr = (unsigned long)newscradr;
		new_physcr = (void *)((ptr+255) & 0xffffff00L);	/* 256 byte boundary */
		new_logscr = new_physcr;
	}  
#else
	newscradr = lmalloc(32*1024L);	/* allocate 32k for 2nd video screen */ 	
	ptr = (unsigned long)newscradr;
	new_physcr = (void *)((ptr+255) & 0xffffff00L);	/* 256 byte boundary */
	new_logscr = new_physcr;
#endif   /* OVERSCAN */

	old_physcr = Physbase();					/* remember displayed screen address */
	old_logscr = Logbase();						/* remember output screen address */
	Cconws("\033j");								/* Save cursor position */

	(void) Vsync();								/* wait for vsync */
	(void) Setscreen(new_logscr, new_physcr, -1);	/* switch to 2nd screen */

	Cconws("\033H\033J");						/* cursor home, clear screen */
	Cconws("\033k");								/* restore cursor position */

	(void) Vsync();								/* wait for vsync						*/
	(void) Setscreen(old_logscr, old_physcr , -1);	/* restore old screen */
#endif

	Cconws("\033v\033e\n");		/* Autowrap on, Cursor on */
	(void) Cursconf(2,0);		/* make the cursor blink (3=steady) */


	shell = getenv("NROWS");
	if (shell != NULL)
		rows = atoi(shell);

	shell = getenv("SHELL");
	if (shell == NULL)
		shell="\\bin\\gulam.prg";

	etv_timer = Setexc(0x100, st_tick);	  	/* re-vector etv_timer to st_tick	*/
}

	
/*---------------------------------------------------------------------------
	iostop - Called just before exiting. 
---------------------------------------------------------------------------*/

void iostop(void)
{
	struct iface *ifp, *iftmp;

	for (ifp = Ifaces; ifp != NULLIF; ifp = iftmp) {
		iftmp = ifp->next;
		if_detach(ifp);							/* issue detatch for active i/f	*/
	}

	(void)Setexc(0x100, etv_timer); 			/* restore etv_timer vector		*/
	
#ifdef SCREEN
	dispscreen(0);									/* switch back to original screen*/
	toggle = 0;
	free(newscradr);
#endif

}

/****************************************************************************
*                                                                           *
*	System Timer functions																	 *
*                                                                           *
****************************************************************************/

/*---------------------------------------------------------------------------
	mfp_tick - process ticks from MFP Timer A - called by etv_timer interrupt
---------------------------------------------------------------------------*/

void __saveds sys_tick(void)
{	
	Tick++;
	Clock++;
	if (Virtual_Interrupt_Enable)
  		psignal((void *)&Tick, 1); 
}


/*---------------------------------------------------------------------------
	secclock - returns number of seconds since startup 
---------------------------------------------------------------------------*/

int32 secclock(void)
{
	return Clock / TICKSEC;
}


/*---------------------------------------------------------------------------
	msclock - return number of milli-seconds since startup
---------------------------------------------------------------------------*/

int32 msclock(void)
{
	return Clock * MSTICK;
}


/****************************************************************************
*                                                                           *
*	System keyboard functions																 *
*                                                                           *
****************************************************************************/

/*---------------------------------------------------------------------------
	kbread - get a key press.  GEMDOS functions used to provide type-ahead
---------------------------------------------------------------------------*/
 
int kbread()
{
	int 	c, i, j;
	long	raw;

	if ((c = Leftover) != 0)  {
		Leftover = *Nextkey++;					/* get next character from str	*/
		return c;									/* return char from FN key str	*/
	}

	while (Cconis() == 0) 
		pwait(NULL);								/* no key waiting, release CPU	*/
	
	raw = Crawcin();								/* get ASCII & scan code from		*/
	c = raw & 0x7f;								/* remove scan codes 				*/

	if (c != 0)
		return c;									/* return normal character			*/

	/* process function keys 																*/

	c = (raw >> 16) & 0xff;						/* get key code						*/
	
	if (c == Escape)								/* escape character ?				*/
		return -2;									/* switch to command line			*/

	for (i=0; (j = fkeys[i].fkey) != 0; i++)
		if (j == c) {								/* look for function key code		*/	
			Nextkey = fkeys[i].fvalue;			/* point to FN key string			*/

			if (fkeys[i].special == 1)	{		/* special key ?						*/
				Leftover = *Nextkey++;			/* point to next char in string  */
				return -2;							/* switch to command line			*/
			}

			if (Nextkey == NULLCHAR) {			
			/*	c = -1;         */				/* no more characters				*/
				return c + 255; 
			}

			if ((c = *Nextkey++) != 0)
				Leftover = *Nextkey++;			/* get netx character				*/
			else
				c = -1;								/* no more characters				*/
			return c;								/* return character					*/
		}
}

/*---------------------------------------------------------------------------
	dofkey - setup function key strings
---------------------------------------------------------------------------*/

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

	if (argc == 1) {
	   tprintf("key num    key  num    key  num    key  num   key   num\n");
	   tprintf("f1   59    sf1   84    cf1   94    af1  104   undo   97\n");
	   tprintf("f2   60    sf2   85    cf2   95    af2  105   help   98\n");
	   tprintf("f3   61    sf3   86    cf3   96    af3  106   home   71\n");
	   tprintf("f4   62    sf4   87    cf4   97    af4  107            \n");
	   tprintf("f5   63    sf5   88    cf5   98    af5  108   arup   72\n");
	   tprintf("f6   64    sf6   89    cf6   99    af6  109   ardn   80\n");
	   tprintf("f7   65    sf7   90    cf7  100    af7  110   ar l   75\n");
	   tprintf("f8   66    sf8   91    cf8  101    af8  111   ar r   77\n");
	   tprintf("f9   67    sf9   92    cf9  102    af9  112   ins    82\n");
	   tprintf("f10  68    sf10  93    cf10 103    af10 113   del    83\n");
	   tprintf("usage: fkey <key number> [<value> | \"string\"]\n");
	   return 0;
	}

	c = atoi(argv[1]);
	if (c == 0 || c > 255) {
		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';

			switch (fkeys[j].special) {
				case 1:
					special = "[command]";
					break;
				default:
					special = "";
				break;
			}

			tprintf("fkey = %s%s\n", special, str);
		}
		return 0;
	}

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

		r = str;
		q = argv[2];
		
		if (strncmp(argv[2], "[command]", 9) == 0) {
			q += 9;
			fkeys[j].special = 1;
		}

		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;
}


/****************************************************************************
*                                                                           *
*	Virtual Interrupt handling functions                                     *
*                                                                           *
****************************************************************************/

/*---------------------------------------------------------------------------
	istate - return the current virtual interrupt sataus
---------------------------------------------------------------------------*/

int istate(void)
{
   return (int)Virtual_Interrupt_Enable;
}


/*---------------------------------------------------------------------------
	dirps - disable Virtual Interrupts and return the previous status
---------------------------------------------------------------------------*/

int dirps(void)
{
   int prior = Virtual_Interrupt_Enable;

   if (Virtual_Interrupt_Enable) 
      Virtual_Interrupt_Enable = 0;

   return prior;
}


/*---------------------------------------------------------------------------
	restore - restore the Virtual Interrupt sataus
---------------------------------------------------------------------------*/
	
void restore(int foo)
{
   if (foo && !Virtual_Interrupt_Enable) {
      Virtual_Interrupt_Enable = 1;
   }
}


/*---------------------------------------------------------------------------
	disable -
---------------------------------------------------------------------------*/
	
int disable()
{
	return 1;
}


/*--------------------------------------------------------------------------
	doshell - function not currently used
---------------------------------------------------------------------------*/	

void doshell(int argc, char *argv[])
{
#if 0
#ifdef SCREEN
	/* make sure that we are on the right (main) screen */
	dispscreen(0);
	toggle = 0;
#endif /* SCREEN */
	if (argc < 2) {
		args[0]="shell";
		args[1]=NULL;
		execstat = exec(shell,args);
	} else
		execstat = exec(argv[1],&argv[1]);

	if (execstat != 0)
		printf("Pexec: errorcode: %ld\n",execstat);

	printf("\n");
	(void)Cursconf(1,0);		/* cursor on */
	(void)Cursconf(2,0);		/* cursor blink */
#endif
}


/*---------------------------------------------------------------------------
	memstat - Report on memory status
---------------------------------------------------------------------------*/

void	memstat()
{

/*	long size;  */
	void *size;

	size = Malloc(-1L);
	printf("\nFree memory: %ld bytes.\n\n",size);

	printf("AUX:");
	iosize(0);
#if 0
	printf("MIDI:");
	iosize(2);
#endif
}


/*---------------------------------------------------------------------------
	iosize - report the I/O buffer size
---------------------------------------------------------------------------*/

void iosize(int i)
{
	struct iorec *rsbuffer;

	rsbuffer = (struct iorec*) Iorec(i);		/* get iorec */
	printf("\tIorec:  %08lx\n", rsbuffer);
	printf("\tBuffer: %08x\n", rsbuffer->ibuf);
	printf("\tSize:   %d bytes\n", rsbuffer->ibufsiz);
}


/****************************************************************************
*                                                                           *
*	Display handling functions                                               *
*                                                                           *
****************************************************************************/

/*---------------------------------------------------------------------------
	display - the main display task, it sucks output from the "active" session
				 and displays it.
---------------------------------------------------------------------------*/

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

	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 '--More--' prompt */
	 		cputs("\r        \r");
			sp->morewait = 0;
		}

		if ((c = recvchar(sp->output)) == -1){
			/* the alert() in swapscreen will cause this to
			 * return -1 when current changes
			 */
			pwait(NULL);
			continue;
		}

		if (sp->record != NULLFILE) {				/* log character if required */
			if (c != '\r')
				fputc(c, sp->record);
		}
		
/*		cputc((char)c); */
			Bconout(2, (char)c);						/* write character to console	*/

		if (c == '\n') {								/* if newline found				*/
/*			cputc('\r'); */
			Bconout(2, '\r');							/* write CR							*/
			
			if(sp->flowmode && --sp->row <= 0) {
				cputs("--More--");
				sp->morewait = 1;
			}
		}
	}
}

#ifdef SCREEN

/*---------------------------------------------------------------------------
 dispscreen selects the screen to be displayed by the video hardware.
 * this routine is called from within kbread()
 * flag:  =0: display normal screen
 *       <>0: display trace screen
---------------------------------------------------------------------------*/ 

void dispscreen(int flag)
{
	if (flag == 0) {
		(void) Setscreen(old_logscr, old_physcr, -1);
		(void) Vsync();
		printf("\033e");	/* turn on cursor */
	} else {
		(void) Setscreen(new_logscr, new_physcr, -1);
		(void) Vsync();
		printf("\033f");	/* turn off cursor */
	}
}


/*---------------------------------------------------------------------------
	outscreen - outscreen selects one of two screens where display output
               (printf's) should go to.  outscreen is called from trace.c
               before/after trace output is done
---------------------------------------------------------------------------*/

void outscreen(int flag)
{
	if (flag == 0) {
		(void) Setscreen(old_logscr, old_physcr, -1);
		(void) Vsync();
		printf("\033k");	/* restore cursor pos on main screen */
	} else {
		(void) Setscreen(new_logscr, new_physcr, -1);
		(void) Vsync();
		printf("\033j");	/* save cursor pos on main screen */
		printf("\033Y%c%c",rows+31,32);
	}
}
#endif


/*---------------------------------------------------------------------------
	set_stdout - set console output to binary or ascii mode (raw or cooked...)
					 mode == 1 means raw, anything else means cooked.
---------------------------------------------------------------------------*/

void set_stdout(int mode)
{
	fmode(stdout, mode);
	fflush(stdout);
	setbuf(stdout, NULL);  /* disable all buffering */
}

#if 0
long ptol(void *ptr)
{
   return (long) ptr;
}

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

/*---------------------------------------------------------------------------
	domem - memory reporting function
---------------------------------------------------------------------------*/

int domem(int argc,
          void *argv[],
          void *p )
{
	tprintf("Coreleft = %x \n", coreleft());

	return 0;
}


/*---------------------------------------------------------------------------
	clear - clear the screen and home the cursor
---------------------------------------------------------------------------*/

int doclear(int argc,
				void *argv[],
				void *p )
{
	tprintf("\033E");
	tflush();
}

          
/****************************************************************************
*                                                                           *
*	Dummy and mapping functions                                              *
*                                                                           *
****************************************************************************/

#if 0

/*---------------------------------------------------------------------------
	rflush - Flush the raw terminal output
---------------------------------------------------------------------------*/

void rflush()
{
	fflush(stdout);
}
#endif

/*---------------------------------------------------------------------------
	mallocw - all malloc calls run through here
---------------------------------------------------------------------------*/
	
void *mallocw(unsigned n)
{
	return malloc((size_t)n);
}


/*---------------------------------------------------------------------------
	callocw - all calloc calls run through here
---------------------------------------------------------------------------*/
	
void *callocw(unsigned n, unsigned size)
{
	return calloc((size_t)n, (size_t)size);
}


/*---------------------------------------------------------------------------
	availmem - report on available memory
---------------------------------------------------------------------------*/
	
unsigned long availmem(void)
{
	return 16535;
}

/****************************************************************************
*                                                                           *
*   T H E   E N D                                                           *
*                                                                           *
****************************************************************************/
