/*
 *	Runtime support routines for T3 and T3X.
 *	Copyright (C) 1997,1998,1999 Nils M Holm.
 *	See ../compiler/txtrn.t for details.
 *	See the file LICENSE for conditions of use.
 *
 *	-DBASIC_EXT
 *		enable the T3X standard procedures. This is
 *		mandatory when compiling TXX or LIBTX.
 *	-DVIO_EXT
 *		enable the terminal driver routines.
 *	-DGRAPHICS_EXT
 *		enable the graphics support routines (device
 *		independant drawing primitives and vector
 *		fonts). Graphics support is currently available
 *		on Plan9, FreeBSD/X11, and DOS (with VGA).
 */

#ifdef plan9
#include <u.h>
#include <libc.h>
#define lseek           seek
#define unlink          remove
#define creat(F, P)     create(F, ORDWR, P)
#define off_t	long
#define O_RDONLY	OREAD
#define O_WRONLY	OWRITE
#define O_RDWR		ORDWR
#else	/* !plan9 */
#include <sys/types.h>
#include <fcntl.h>
#ifdef __TURBOC__
#include <io.h>
#define off_t	long
#endif
#define uchar	unsigned char
#define ushort	unsigned short
#define uint	unsigned int
#endif /* !plan9 */


#ifdef GRAPHICS_EXT
#include "gfx.h"
#endif


#define BPW	2
#define BUFLEN	1024
#define STRLEN	256


int		Input, Output;
extern ushort	*Ustack;
extern short	*Stack;
extern ushort	Sp;
extern uchar	*Data;
extern short	Acc;
extern ushort	Edata;


void libinit() {
	Input = 0;
	Output = 1;
#ifdef msdos
	setmode(0, O_BINARY);
	setmode(1, O_BINARY);
#endif
}


pack_(v, s)
unsigned short	*v;
unsigned char	*s;
{
	int	i;

	for (i=0; v[i]; i++) s[i] = v[i];
	s[i] = 0;
	return((i+BPW)/BPW);
}


unpack_(s, v)
unsigned char	*s;
unsigned short	*v;
{
	int	i;

	for (i=0; s[i]; i++) v[i] = s[i];
	v[i] = 0;
	return(i);
}


length_(v)
short	*v;
{
	int	i = 0;

	while (v[i]) i++;
	return(i);
}


aton_(s)
short	*s;
{
	int	k, v = 0, g = 0;

	k = 0;
	while (	s[k] == ' ' || s[k] == '\t' || s[k] == '\n' ||
		s[k] == '\r' || s[k] == '\f'
	)
		k++;
	if (s[k] == '-' || s[k] == '%') {
		g = 1;
		k++;
	}
	else if (s[k] == '+') {
		k++;
	}
	while ('0' <= s[k] && s[k] <= '9') {
		v = v*10 + (s[k]-'0');
		k++;
	}
	return(g? -v: v);
}


ntoa_(pv, w)
short	pv, w;
{
	short		*n = (short *) &Data[Edata];
	/* short might get extended to int in argument list */
	short		v = pv;
	int		i, g = 0;
	unsigned	u;

	if (v<0) {
		g = 1;
		v = -v;
	}
	u = v;
	n[STRLEN] = 0;
	i = STRLEN-1;
	while (u || i == STRLEN-1) {
		n[i--] = u%10+'0';
		u = u/10;
		w--;
	}
	if (g) {
		n[i--] = '-';
		w--;
	}
	while (w>0) {
		n[i--] = ' ';
		w--;
	}
	return(Edata+(i<<1)+2);
}


open_(file, mode)
short	*file, mode;
{
	char	name[256];
	int	fd;

	pack_(file, name);
	if (mode == 1)
		fd = creat(name, 0666);
	else if (mode == 0 || mode == 2 || mode == 3)
		fd = open(name, mode==3? O_WRONLY: mode==2? O_RDWR:
			O_RDONLY);
	else
		return(-1);
#ifdef msdos
	setmode(fd, O_BINARY);
#endif
	if (fd > 0 && mode == 3) lseek(fd, 0L, 2);
	return(fd);
}


close_(fd) {
	return(close(fd));
}


erase_(file)
short	*file;
{
	char	name[256];

	pack_(file, name);
	return(unlink(name));
}


select_(port, new) {
	int	old;

	if (port) {
		old = Output;
		Output = new;
	}
	else {
		old = Input;
		Input = new;
	}
	return(old);
}


reads_(s, n)
unsigned short	*s;
int		n;
{
	unsigned char	IOBuf[BUFLEN+1];
	int		k, i;

	k = read(Input, IOBuf, n);
	if (k<0) return(k);
	for (i=0; i<k; i++) s[i] = IOBuf[i];
	s[i] = 0;
	return(k);
}


writes_(s)
short	*s;
{
	char	IOBuf[BUFLEN+1];

	pack_(s, IOBuf);
	return(write(Output, IOBuf, length_(s)));
}


rename_(old, new)
short	*old, *new;
{
	char	oldp[256], newp[256];

	pack_(old, oldp);
	pack_(new, newp);
	return(rename(oldp, newp));
}


void newline_() {
#ifdef msdos
	write(Output, "\r\n", 2);
#else
	write(Output, "\n", 1);
#endif
}


void p_open() { Acc = open_(&Data[Ustack[Sp+1]], Ustack[Sp]); }
void p_close() { Acc = close_(Ustack[Sp]); }
void p_erase() { Acc = erase_(&Data[Ustack[Sp]]); }
void p_select() { Acc = select_(Ustack[Sp+1], Ustack[Sp]); }
void p_reads() { Acc = reads_(&Data[Ustack[Sp+1]], Ustack[Sp]); }
void p_writes() { Acc = writes_(&Data[Ustack[Sp]]); }
void p_newline() { newline_(); }
void p_aton() { Acc = aton_(&Data[Ustack[Sp]]); }
void p_ntoa() { Acc = ntoa_(Stack[Sp+1], Stack[Sp]); }
void p_pack() { Acc = pack_(&Data[Ustack[Sp+1]], &Data[Ustack[Sp]]); }
void p_unpack() {
	Acc = unpack_(&Data[Ustack[Sp+1]], &Data[Ustack[Sp]]); }
#ifdef BASIC_EXT
void p_readpacked() {
	Acc = read(Stack[Sp+2], &Data[Ustack[Sp+1]], Stack[Sp]); }
void p_writepacked() {
	Acc = write(Stack[Sp+2], &Data[Ustack[Sp+1]], Stack[Sp]); }
void p_reposition() {
	Acc = (int) lseek(Stack[Sp+3],
		(off_t) (((long) Ustack[Sp+2]<<16) | Ustack[Sp+1]),
		Stack[Sp]); }
void p_rename() {
	Acc = rename_(&Data[Ustack[Sp+1]], &Data[Ustack[Sp]]); }
void p_memcopy() { memmove(&Data[Ustack[Sp+2]], &Data[Ustack[Sp+1]],
	Ustack[Sp]); Acc = 0; }
void p_memcomp() { Acc = memcmp(&Data[Ustack[Sp+2]], &Data[Ustack[Sp+1]],
	Ustack[Sp]); }
#endif
#ifdef VIO_EXT
void p_vio_init() { vio_init(); Acc = 0; }
void p_vio_sync() { vio_sync(); Acc = 0; }
void p_vio_end() { vio_end(); Acc = 0; }
void p_vio_reinit() { vio_reinit(); Acc = 0; }
void p_vio_putc() { Acc = vio_putc(Stack[Sp]); }
void p_vio_puts() { vio_puts(&Data[Ustack[Sp]]); Acc = 0; }
void p_vio_clear() { vio_clear(); Acc = 0; }
void p_vio_clreol() { vio_clreol(); Acc = 0; }
void p_vio_color() { vio_color(Stack[Sp]); Acc = 0; }
void p_vio_query() { Acc = vio_query(); }
void p_vio_getc() { Acc = vio_getc(); }
void p_vio_move() { vio_move(Stack[Sp+1], Stack[Sp]); Acc = 0; }
void p_vio_index() { vio_index(Stack[Sp+1], Stack[Sp]); Acc = 0; }
void p_vio_revind() { vio_revind(Stack[Sp+1], Stack[Sp]); Acc = 0; }
#endif
#ifdef GRAPHICS_EXT
void p_g_init() { g_init(); Acc = 0; }
void p_g_end() { g_end(); Acc = 0; }
void p_g_event() { Acc = g_event(&Data[Ustack[Sp+1]], Stack[Sp]); }
void p_g_wait() { Acc = g_wait(Stack[Sp]); }
void p_g_clear() {
	g_clear(Stack[Sp]); Acc = 0; }
void p_g_point() {
	g_point(Stack[Sp+2], Stack[Sp+1], Stack[Sp]); Acc = 0; }
void p_g_line() {
	g_line(Stack[Sp+4], Stack[Sp+3], Stack[Sp+2], Stack[Sp+1],
	Stack[Sp]); Acc = 0; }
void p_g_box() {
	g_box(Stack[Sp+4], Stack[Sp+3], Stack[Sp+2], Stack[Sp+1],
	Stack[Sp]); Acc = 0; }
void p_g_sync() { g_sync(); Acc = 0; }
void p_g_reshaped() { Acc = g_reshaped(); }
void p_g_putc() {
	g_putc(Stack[Sp+4], Stack[Sp+3], Stack[Sp+2], Stack[Sp+1],
	Stack[Sp]); Acc = 0; }
void p_g_puts() {
	g_puts(Stack[Sp+4], Stack[Sp+3], Stack[Sp+2], Stack[Sp+1],
	&Data[Ustack[Sp]]); Acc = 0; }
void p_g_fontsize() { g_fontsize(Stack[Sp+1], &Data[Ustack[Sp]]); Acc = 0; }
void p_g_putv() {
	g_putv(Stack[Sp+4], Stack[Sp+3], Stack[Sp+2], Stack[Sp+1],
	&Data[Ustack[Sp]]); Acc = 0; }
void p_g_copyfont() { Acc = g_copyfont(&Data[Ustack[Sp+1]],
	&Data[Ustack[Sp]]); }
#endif
