/*
 *	Runtime support routines for compiled T3X programs.
 *	Copyright (C) 1997,1998 Nils M. Holm.
 *	See txtrn.t for details.
 *	See the file LICENSE for conditions of use.
 *
 *	Currently, this module will only compile on FreeBSD
 *	when the VIO or GRAPHICS extensions are enabled, since
 *	it uses OS dependant code to access environment
 *	variables.
 *	1998-Apr-03: The runtime support libraries have been
 *	ported to DOS.
 */

#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 _exit(x)	exits(x? "error": 0)
#else
#include <sys/types.h>
#ifndef off_t
 #define off_t	long
#endif
#endif
#include "gfx.h"
#include "vio.h"

#ifdef msdos
#define BPW	2
#else
#define BPW	4
#endif
#define BUFLEN	1024
#define STRLEN	256

#ifndef plan9
#define uchar	unsigned char
#define ushort	unsigned short
#define uint	unsigned int
#endif

#define STATIC static


int		Input, Output;


int	open_(), close_(), erase_(), select_(), reads_(), writes_(),
	newline_(), aton_(), ntoa_(), pack_(), unpack_(), readpacked_(),
	writepacked_(), reposition_(), rename_(), memcopy_(), memcomp_();

int	(*GV_[100])();


#ifdef VIO_EXT
#define CRT0_EXTERNALS
STATIC w_vio_init() { vio_init(); }
STATIC w_vio_end() { vio_end(); }
STATIC w_vio_reinit() { vio_reinit(); }
STATIC w_vio_putc(c) { return vio_putc(c); }
STATIC w_vio_puts(s) char *s; { vio_puts(s); }
STATIC w_vio_sync() { vio_sync(); }
STATIC w_vio_clear() { vio_clear(); }
STATIC w_vio_clreol() { vio_clreol(); }
STATIC w_vio_color(c) { vio_color(c); }
STATIC w_vio_query() { return vio_query(); }
STATIC w_vio_getc() { return vio_getc(); }
STATIC w_vio_move(y, x) { vio_move(x, y); }
STATIC w_vio_index(b, t) { vio_index(t, b); }
STATIC w_vio_revind(b, t) { vio_revind(t, b); }
#endif


#ifdef GRAPHICS_EXT
#define CRT0_EXTERNALS
STATIC w_g_init() { return g_init(); }
STATIC w_g_end() { g_end(); }
struct e32 { int x, y, buttons, key; };
STATIC w_g_event(b, e) int b; struct e32 *e; {
	int		r;
	struct event	t;

	r = g_event(&t, b);
	e->x = t.x;
	e->y = t.y;
	e->buttons = t.buttons;
	e->key = t.key;
	return(r);
}
STATIC w_g_wait(n) { return g_wait(n); }
STATIC w_g_clear(m) { g_clear(m); }
STATIC w_g_point(m, y, x) { g_point(x, y, m); }
STATIC w_g_line(m, dy, dx, y, x) { g_line(x, y, dx, dy, m); }
STATIC w_g_box(m, dy, dx, y, x) { g_box(x, y, dx, dy, m); }
STATIC w_g_sync() { return g_sync(); }
STATIC w_g_reshaped() { return g_reshaped(); }
STATIC w_g_putc(c, m, sc, y, x) { return g_putc(x, y, sc, m, c); }
STATIC w_g_puts(s, m, sc, y, x) char *s; int m, sc, y, x; {
	return g_puts(x, y, sc, m, s); }
STATIC w_g_fontsize(v, sc) int *v, sc; {
	short t[2];

	g_fontsize(sc, &t);
	v[0] = t[0];
	v[1] = t[1];
}
STATIC w_g_copyfont(b, a) int *a, *b; {
	ushort	t[128];
	int	i;

	g_copyfont(t, b);
	for (i=0; i<128; i++) a[i] = t[i];
}
STATIC w_g_putv(v, m, sc, y, x) char *v; int m, sc, y, x; {
	return g_putv(x, y, sc, m, v); }
#endif


#ifdef USE_CRT0
#undef CRT0_EXTERNALS
#endif

#ifdef CRT0_EXTERNALS
#ifdef unix
char	**environ = 0L;
char	*__progname = "Unknown T3X program";
#endif
#endif


int badgv() {
	write(2, "LIBTX: uninitialized interface\n", 31);
	_exit(-1);
}


void TXINIT() {
	register int	i;
#ifdef CRT0_EXTERNALS
#ifdef unix
	/* ----------------------------------------------
	 * This part has been shamelessly taken from the
	 * FreeBSD startup module crt0.c
	 */
	struct kframe {
		int	kargc;
		char	*kargv[1];	/* size depends on kargc */
		char	kargstr[1];	/* size varies */
		char	kenvstr[1];	/* size varies */
	};
	/*
	 *	ALL REGISTER VARIABLES!!!
	 */
	register struct kframe	*kfp;
	register char		**targv;
	register char		**argv;

	/* Above the frame pointer AND the return addess */
	asm ("lea 8(%%ebp), %0" : "=r" (kfp) );
	for (argv = targv = &kfp->kargv[0]; *targv++;)
		;
	if (targv >= (char **)(*argv)) --targv;
	environ = targv;
	/*
	 * ----------------------------------------------
	 */
#endif
#endif
	Input = 0;
	Output = 1;
	for (i=0; i<100; i++) GV_[i] = badgv;
	GV_[0] = open_;
	GV_[1] = close_;
	GV_[2] = erase_;
	GV_[3] = select_;
	GV_[4] = reads_;
	GV_[5] = writes_;
	GV_[6] = newline_;
	GV_[7] = aton_;
	GV_[8] = ntoa_;
	GV_[9] = pack_;
	GV_[10] = unpack_;
	GV_[11] = readpacked_;
	GV_[12] = writepacked_;
	GV_[13] = reposition_;
	GV_[14] = rename_;
	GV_[15] = memcopy_;
	GV_[16] = memcomp_;
#ifdef VIO_EXT
	GV_[30] = w_vio_init;
	GV_[31] = w_vio_end;
	GV_[32] = w_vio_reinit;
	GV_[33] = w_vio_sync;
	GV_[34] = w_vio_putc;
	GV_[35] = w_vio_puts;
	GV_[36] = w_vio_clear;
	GV_[37] = w_vio_clreol;
	GV_[38] = w_vio_color;
	GV_[39] = w_vio_query;
	GV_[40] = w_vio_getc;
	GV_[41] = w_vio_move;
	GV_[42] = w_vio_index;
	GV_[43] = w_vio_revind;
#endif
#ifdef GRAPHICS_EXT
	GV_[50] = w_g_init;
	GV_[51] = w_g_end;
	GV_[52] = w_g_event;
	GV_[53] = w_g_wait;
	GV_[54] = w_g_clear;
	GV_[55] = w_g_point;
	GV_[56] = w_g_line;
	GV_[57] = w_g_box;
	GV_[58] = w_g_sync;
	GV_[59] = w_g_reshaped;
	GV_[60] = w_g_putc;
	GV_[61] = w_g_puts;
	GV_[62] = w_g_fontsize;
	GV_[63] = w_g_putv;
	GV_[64] = w_g_copyfont;
#endif
}


#ifndef msdos
pack_(s, v)
unsigned char	*s;
unsigned int	*v;
{
	int	i;

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


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

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


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

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


aton_(s)
int	*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);
}


int ntoa_(w, v)
int	w, v;
{
	static int	n[STRLEN+1];
	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((int)&n[i+1]);
}


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

	pack_(name, file);
	if (mode == 1)
		fd = creat(name, 0666);
	else if (mode == 0 || mode == 2 || mode == 3)
		fd = open(name, mode==3? 2: mode);
	else
		return(-1);
	if (fd> 0 && mode == 3) lseek(fd, 0L, 2);
	return(fd);
}


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


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

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


select_(new, port) {
	int	old;

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


reads_(n, s)
int		n;
unsigned int	*s;
{
	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_(IOBuf, s);
	return(write(Output, IOBuf, length_(s)));
}


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


readpacked_(len, buf, fd)
int	len, *buf, fd;
{
	return (read(fd, buf, len));
}


writepacked_(len, buf, fd)
int	len, *buf, fd;
{
	return (write(fd, buf, len));
}


reposition_(how, lo, hi, fd)
uint	how, lo, hi, fd;
{
	return (lseek(fd, (off_t)(((long)hi<<16)|lo), how));
}


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

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


memcopy_(len, s2, s1)
int	len, *s1, *s2;
{
	return((int) memmove(s1, s2, len));
}


memcomp_(len, s2, s1)
int	len, *s1, *s2;
{
	return(memcmp(s1, s2, len));
}

