/*	SCCS Id: @(#)tos.c	3.1	90/14/08
/* NetHack may be freely redistributed.  See license for details. */

/*
 *  TOS system functions.
 */

#define NEED_VARARGS
#include "hack.h"

#ifdef TTY_GRAPHICS
# include "tcap.h"
#else
/* To avoid error for tos.c; will be removed later */
static char *nh_HE="\033q";
#endif

#ifdef TOS

# include <osbind.h>
# ifndef WORD
#  define WORD short		/* 16 bits -- redefine if necessary */
# endif

#include <ctype.h>

static char NDECL(DOSgetch);
static char NDECL(BIOSgetch);
static void NDECL(init_aline);
char *_a_line;			/* for Line A variables */
# ifdef TEXTCOLOR
boolean colors_changed = FALSE;
# endif

int
tgetch()
{
	char ch;

	/* BIOSgetch can use the numeric key pad on IBM compatibles. */
	if (iflags.BIOS)
		ch = BIOSgetch();
	else
		ch = DOSgetch();
	return ((ch == '\r') ? '\n' : ch);
}

/*
 *  Keyboard translation tables.
 */
#define KEYPADLO	0x61
#define KEYPADHI	0x71

#define PADKEYS 	(KEYPADHI - KEYPADLO + 1)
#define iskeypad(x)	(KEYPADLO <= (x) && (x) <= KEYPADHI)

/*
 * Keypad keys are translated to the normal values below.
 * When iflags.BIOS is active, shifted keypad keys are translated to the
 *    shift values below.
 */
static const struct pad {
	char normal, shift, cntrl;
} keypad[PADKEYS] = {
			{C('['), 'Q', C('[')},		/* UNDO */
			{'?', '/', '?'},		/* HELP */
			{'(', 'a', '('},		/* ( */
			{')', 'w', ')'},		/* ) */
			{'/', '/', '/'},		/* / */
			{C('p'), '$', C('p')},		/* * */
			{'y', 'Y', C('y')},		/* 7 */
			{'k', 'K', C('k')},		/* 8 */
			{'u', 'U', C('u')},		/* 9 */
			{'h', 'H', C('h')},		/* 4 */
			{'.', '.', '.'},
			{'l', 'L', C('l')},		/* 6 */
			{'b', 'B', C('b')},		/* 1 */
			{'j', 'J', C('j')},		/* 2 */
			{'n', 'N', C('n')},		/* 3 */
			{'i', 'I', C('i')},		/* Ins */
			{'.', ':', ':'}			/* Del */
}, numpad[PADKEYS] = {
			{C('['), 'Q', C('[')}	,	/* UNDO */
			{'?', '/', '?'},		/* HELP */
			{'(', 'a', '('},		/* ( */
			{')', 'w', ')'},		/* ) */
			{'/', '/', '/'},		/* / */
			{C('p'), '$', C('p')},		/* * */
			{'7', M('7'), '7'},		/* 7 */
			{'8', M('8'), '8'},		/* 8 */
			{'9', M('9'), '9'},		/* 9 */
			{'4', M('4'), '4'},		/* 4 */
			{'.', '.', '.'},		/* 5 */
			{'6', M('6'), '6'},		/* 6 */
			{'1', M('1'), '1'},		/* 1 */
			{'2', M('2'), '2'},		/* 2 */
			{'3', M('3'), '3'},		/* 3 */
			{'i', 'I', C('i')},		/* Ins */
			{'.', ':', ':'}			/* Del */
};

/*
 * Unlike Ctrl-letter, the Alt-letter keystrokes have no specific ASCII
 * meaning unless assigned one by a keyboard conversion table, so the
 * keyboard BIOS normally does not return a character code when Alt-letter
 * is pressed.	So, to interpret unassigned Alt-letters, we must use a
 * scan code table to translate the scan code into a letter, then set the
 * "meta" bit for it.  -3.
 */
#define SCANLO		0x10

static const char scanmap[] = { 	/* ... */
	'q','w','e','r','t','y','u','i','o','p','[',']', '\n',
	0, 'a','s','d','f','g','h','j','k','l',';','\'', '`',
	0, '\\', 'z','x','c','v','b','N','m',',','.','?' 	/* ... */
};

#define inmap(x)	(SCANLO <= (x) && (x) < SCANLO + SIZE(scanmap))

/*
 * BIOSgetch gets keys directly with a BIOS call.
 */
#define SHIFT		(0x1 | 0x2)
#define CTRL		0x4
#define ALT		0x8

static char
BIOSgetch()
{
	unsigned char scan, shift, ch;
	const struct pad *kpad;

	long  x;

	/* Get scan code.
	 */
	x = Crawcin();
	ch = x & 0x0ff;
	scan = (x & 0x00ff0000L) >> 16;
	/* Get shift status.
	 */
	shift = Kbshift(-1);

	/* Translate keypad keys */
	if (iskeypad(scan)) {
		kpad = iflags.num_pad ? numpad : keypad;
		if (shift & SHIFT)
			ch = kpad[scan - KEYPADLO].shift;
		else if (shift & CTRL)
			ch = kpad[scan - KEYPADLO].cntrl;
		else
			ch = kpad[scan - KEYPADLO].normal;
	}
	/* Translate unassigned Alt-letters */
	if ((shift & ALT) && !ch) {
		if (inmap(scan))
			ch = scanmap[scan - SCANLO];
		return (isprint(ch) ? M(ch) : ch);
	}
	return ch;
}

static char
DOSgetch()
{
	return (Crawcin() & 0x007f);
}


long
freediskspace(path)
char *path;
{
	int drive = 0;
	struct {
		long freal; /*free allocation units*/
		long total; /*total number of allocation units*/
		long bps;   /*bytes per sector*/
		long pspal; /*physical sectors per allocation unit*/
	} freespace;
	if (path[0] && path[1] == ':')
		drive = (toupper(path[0]) - 'A') + 1;
	if (Dfree(&freespace,drive)<0) return -1;
	return freespace.freal*freespace.bps*freespace.pspal;
}

/*
 * Functions to get filenames using wildcards
 */
int
findfirst(path)
char *path;
{
	return (Fsfirst(path, 0) == 0);
}

int
findnext()
{
	return (Fsnext() == 0);
}

char *
foundfile_buffer()
{
	return (char *)Fgetdta() + 30;
}

long
filesize(file)
char *file;
{
	if (findfirst(file))
		return  (* (long *) ((char *)Fgetdta() + 26));
	else
		return -1L;
}

/*
 * Chdrive() changes the default drive.
 */
void
chdrive(str)
char *str;
{
	char *ptr;
	char drive;

	if ((ptr = index(str, ':')) != (char *)0) {
		drive = toupper(*(ptr - 1));
		(void)Dsetdrv(drive - 'A');
	}
	return;
}


void
get_scr_size()
{
# ifdef MINT
#  include <ioctl.h>
	struct winsize win;
	char *tmp;

	if((tmp=nh_getenv("LINES")))
		LI = atoi(tmp);
	else if((tmp=nh_getenv("ROWS")))
		LI = atoi(tmp);
	if(tmp && (tmp=nh_getenv("COLUMNS")))
		CO = atoi(tmp);
	else {
	    ioctl(0,TIOCGWINSZ, &win);
	    LI = win.ws_row;
	    CO = win.ws_col;
	}
# else
	init_aline();
	LI = (*((WORD  *)(_a_line + -42L))) + 1;
	CO = (*((WORD  *)(_a_line + -44L))) + 1;
# endif
}

# define BIGBUF  8192

int
_copyfile(from, to)
char *from, *to;
{
	int fromfd, tofd, r;
	char *buf;

	if ((fromfd = open(from, O_RDONLY|O_BINARY, 0)) < 0)
		return -1;
	if ((tofd = open(to, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, FCMASK)) < 0)
		return -1;
	buf = (char *)alloc((size_t)BIGBUF);
	while ( (r = read(fromfd, buf, BIGBUF)) > 0)
		write(tofd, buf, r);
	close(fromfd);
	close(tofd);
	free(buf);
	return 0;	/* successful */
}

int kbhit()
{
	return Cconis();
}

static void
init_aline()
{
# ifdef __GNUC__
/* line A calls nuke registers d0-d2,a0-a2; not all compilers regard these
   as scratch registers, though, so we save them
 */
	asm(" moveml d0-d2/a0-a2, sp@-");
	asm(" .word 0xa000; movel d0, __a_line");
	asm(" moveml sp@+, d0-d2/a0-a2");
# else
	asm(" movem.l d0-d2/a0-a2, -(sp)");
	asm(" .dc.w 0xa000");	/* tweak as necessary for your compiler */
	asm(" move.l d0, __a_line");
	asm(" movem.l (sp)+, d0-d2/a0-a2");
# endif
}

# ifdef TEXTCOLOR
/* used in termcap.c to decide how to set up the hilites */
unsigned long tos_numcolors = 2;

void
set_colors()
{
	static char colorHE[] = "\033q\033b0";

	if (!iflags.BIOS)
		return;
	init_aline();
	tos_numcolors = 1 << (((unsigned char *) _a_line)[1]);
	if (tos_numcolors <= 2) {			/* mono */
		iflags.use_color = FALSE;
		return;
	} else {
		colors_changed = TRUE;
		nh_HE = colorHE;
	}
}

void
restore_colors()
{
	static char plainHE[] = "\033q";

	if (colors_changed)
		nh_HE = plainHE;
	colors_changed = FALSE;
}
# endif /* TEXTCOLOR */

# ifdef SUSPEND

#include	<signal.h>

#   ifdef MINT
extern int __mint;
#   endif

int
dosuspend() {
#   ifdef MINT
	extern int kill();
	if (__mint == 0) {
#   endif
		pline("Sorry, it seems we have no SIGTSTP here.  Try ! or S.");
#   ifdef MINT
	}
	else if(signal(SIGTSTP, SIG_IGN) == SIG_DFL) {
		suspend_nhwindows((char *)0);
		(void) signal(SIGTSTP, SIG_DFL);
		(void) kill(0, SIGTSTP);
		get_scr_size();
		resume_nhwindows();
	} else {
		pline("I don't think your shell has job control.");
	}
#   endif /* MINT */
	return(0);
}
# endif /* SUSPEND */

#endif /* TOS */
