/*	SCCS Id: @(#)os2.c	3.1	93/01/18 */
/*	Copyright (c) Timo Hakulinen, 1990, 1991, 1992, 1993. */
/*	NetHack may be freely redistributed.  See license for details. */

/*
 *  OS/2 system functions.
 */

#define NEED_VARARGS
#include "hack.h"

#ifdef OS2

#include "termcap.h"

/* OS/2 system definitions */

#include "def_os2.h"

#include <ctype.h>

static char NDECL(DOSgetch);
static char NDECL(BIOSgetch);

int
tgetch()
{
	char ch;

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

/*
 *  Keyboard translation tables.
 */
#define KEYPADLO	0x47
#define KEYPADHI	0x53

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

/*
 * Keypad keys are translated to the normal values below.
 * When flags.BIOS is active, shifted keypad keys are translated to the
 *    shift values below.
 */
static const struct pad {
	char normal, shift, cntrl;
} keypad[PADKEYS] = {
			{'y', 'Y', C('y')},		/* 7 */
			{'k', 'K', C('k')},		/* 8 */
			{'u', 'U', C('u')},		/* 9 */
			{'m', C('p'), C('p')},		/* - */
			{'h', 'H', C('h')},		/* 4 */
			{'g', 'g', 'g'},		/* 5 */
			{'l', 'L', C('l')},		/* 6 */
			{'p', 'P', C('p')},		/* + */
			{'b', 'B', C('b')},		/* 1 */
			{'j', 'J', C('j')},		/* 2 */
			{'n', 'N', C('n')},		/* 3 */
			{'i', 'I', C('i')},		/* Ins */
			{'.', ':', ':'}			/* Del */
}, numpad[PADKEYS] = {
			{'7', M('7'), '7'},		/* 7 */
			{'8', M('8'), '8'},		/* 8 */
			{'9', M('9'), '9'},		/* 9 */
			{'m', C('p'), C('p')},		/* - */
			{'4', M('4'), '4'},		/* 4 */
			{'g', 'G', 'g'},		/* 5 */
			{'6', M('6'), '6'},		/* 6 */
			{'p', 'P', C('p')},		/* + */
			{'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
#define SCANHI		0x32
#define SCANKEYS	(SCANHI - SCANLO + 1)
#define inmap(x)	(SCANLO <= (x) && (x) <= SCANHI)

static const char scanmap[SCANKEYS] = { 	/* ... */
	'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' 	/* ... */
};

/*
 * BIOSgetch emulates the MSDOS way of getting keys directly with a BIOS call.
 */
#define SHIFT_KEY	(0x1 | 0x2)
#define CTRL_KEY	0x4
#define ALT_KEY		0x8

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

	KBDKEYINFO CharData;
	USHORT IOWait = 0;
	HKBD KbdHandle = 0;

	KbdCharIn(&CharData,IOWait,KbdHandle);
	ch = CharData.chChar;
	scan = CharData.chScan;
	shift = CharData.fsState;

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

static char
DOSgetch()
{
	KBDKEYINFO CharData;
	USHORT IOWait = 0;
	HKBD KbdHandle = 0;

	KbdCharIn(&CharData,IOWait,KbdHandle);
	if (CharData.chChar == 0) {	/* an extended code -- not yet supported */
		KbdCharIn(&CharData,IOWait,KbdHandle);	   /* eat the next character */
		CharData.chChar = 0;		/* and return a 0 */
	}
	return (CharData.chChar);
}

char
switchar()
{
	return '/';
}

int
kbhit()
{
	KBDKEYINFO CharData;
	HKBD KbdHandle = 0;

	KbdPeek(&CharData,KbdHandle);
	return (CharData.fbStatus & (1 << 6));
}

long
freediskspace(path)
char *path;
{
	FSALLOCATE FSInfoBuf;
#ifdef OS2_32BITAPI
	ULONG
#else
	USHORT
#endif
		DriveNumber, FSInfoLevel = 1, res;

	if (path[0] && path[1] == ':')
		DriveNumber = (toupper(path[0]) - 'A') + 1;
	else
		DriveNumber = 0;
	res =
#ifdef OS2_32BITAPI
		DosQueryFSInfo(DriveNumber,FSInfoLevel,(PVOID)&FSInfoBuf,(ULONG)sizeof(FSInfoBuf));
#else
		DosQFSInfo(DriveNumber,FSInfoLevel,(PBYTE)&FSInfoBuf,(USHORT)sizeof(FSInfoBuf));
#endif
	if (res)
		return -1L;		/* error */
	else
		return ((long) FSInfoBuf.cSectorUnit * FSInfoBuf.cUnitAvail *
			       FSInfoBuf.cbSector);
}

/*
 * Functions to get filenames using wildcards
 */

#ifdef OS2_32BITAPI
static FILEFINDBUF3 ResultBuf;
#else
static FILEFINDBUF ResultBuf;
#endif
static HDIR DirHandle;

int
findfirst(path)
char *path;
{
#ifdef OS2_32BITAPI
	ULONG
#else
	USHORT
#endif
		res, SearchCount = 1;

	DirHandle = 1;
	res =
#ifdef OS2_32BITAPI
		DosFindFirst((PSZ)path,&DirHandle,0L,(PVOID)&ResultBuf,(ULONG)sizeof(ResultBuf),&SearchCount,1L);
#else
		DosFindFirst((PSZ)path,&DirHandle,0,&ResultBuf,(USHORT)sizeof(ResultBuf),&SearchCount,0L);
#endif
	return(!res);
}

int
findnext()
{
#ifdef OS2_32BITAPI
	ULONG
#else
	USHORT
#endif
		res, SearchCount = 1;

	res =
#ifdef OS2_32BITAPI
		DosFindNext(DirHandle,(PVOID)&ResultBuf,(ULONG)sizeof(ResultBuf),&SearchCount);
#else
		DosFindNext(DirHandle,&ResultBuf,(USHORT)sizeof(ResultBuf),&SearchCount);
#endif
	return(!res);
}

char *
foundfile_buffer()
{
	return(ResultBuf.achName);
}

long
filesize(file)
char *file;
{
	if (findfirst(file)) {
		return  (* (long *) (ResultBuf.cbFileAlloc));
	} else
		return -1L;
}

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

	if ((ptr = index(str, ':')) != NULL) {
		drive = toupper(*(ptr - 1));
#ifdef OS2_32BITAPI
		DosSetDefaultDisk((ULONG)(drive - 'A' + 1));
#else
		DosSelectDisk((USHORT)(drive - 'A' + 1));
#endif
	}
}

void
disable_ctrlP()
{
	KBDINFO KbdInfo;
	HKBD KbdHandle = 0;

	if (!flags.rawio) return;
	KbdInfo.cb = sizeof(KbdInfo);
	KbdGetStatus(&KbdInfo,KbdHandle);
	KbdInfo.fsMask &= 0xFFF7; /* ASCII off */
	KbdInfo.fsMask |= 0x0004; /* BINARY on */
	KbdSetStatus(&KbdInfo,KbdHandle);
}

void
enable_ctrlP()
{
	KBDINFO KbdInfo;
	HKBD KbdHandle = 0;

	if (!flags.rawio) return;
	KbdInfo.cb = sizeof(KbdInfo);
	KbdGetStatus(&KbdInfo,KbdHandle);
	KbdInfo.fsMask &= 0xFFFB; /* BINARY off */
	KbdInfo.fsMask |= 0x0008; /* ASCII on */
	KbdSetStatus(&KbdInfo,KbdHandle);
}

void
get_scr_size()
{
	VIOMODEINFO ModeInfo;
	HVIO VideoHandle = 0;

	ModeInfo.cb = sizeof(ModeInfo);

	(void) VioGetMode(&ModeInfo,VideoHandle);

	CO = ModeInfo.col;
	LI = ModeInfo.row;
}

void
gotoxy(x,y)
int x,y;
{
	HVIO VideoHandle = 0;

	x--; y--;			/* (0,0) is upper right corner */

	(void) VioSetCurPos(x, y, VideoHandle);
}

#endif /* OS2 */
