/* File: main-vme.c */

/* Purpose: Support for "Vax Angband" */

/*
This is MAIN-VME C for VM/ESA machines.
First enable definition of VM in file "h-config.h"
You need to unpack archive EXT-VM VMARC .
 
To do that first set fixed file record length:
'COPYFILE EXT-VM VMARC A = = = ( REC F'
Then unpack:
VMARC UNPACK EXT-VM VMARC A
 
( if you don't have archivator vmarc, there is many places where you
get it, i got it from cc1.kuleuven.ac.be )
 
Then read MAKEFILE EXEC. It contains all neccessary information to
compile Angband.
 
EXT-VM VMARC content:
MAKEFILE EXEC
VMSERV TXTLIB
CNSHND ASSEMBLE
 
You will need about 3-4 MB free disk space to compile it.
If you have any problems, mail to
 
SM20616@vm.lanet.lv or SD30066@vm.lanet.lv
 
A large amount of this file appears to be a complete hack, but
what can you expect from a system designed for the Vax... :-)
 */


#include "angband.h"

#if defined(USE_VME) || defined(VM)


/*
 * Convert EBCDIC to ASCII
 */
char e2a[] =
{
	0x00, 0x01, 0x02, 0x03, 0x1A, 0x09, 0x1A, 0x7F, 0x1A, 0x1A, 0x1A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
	0x10, 0x11, 0x12, 0x13, 0x1A, 0x0A, 0x08, 0x1A, 0x18, 0x19, 0x1A, 0x1A, 0x1C, 0x1D, 0x1E, 0x1F,
	0x1A, 0x1A, 0x1C, 0x1A, 0x1A, 0x0A, 0x17, 0x1B, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x05, 0x06, 0x07,
	0x1A, 0x1A, 0x16, 0x1A, 0x1A, 0x1E, 0x1A, 0x04, 0x1A, 0x1A, 0x1A, 0x1A, 0x14, 0x15, 0x1A, 0x1A,
	0x20, 0xA6, 0xE1, 0x80, 0xEB, 0x90, 0x9F, 0xE2, 0xAB, 0x8B, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
	0x26, 0xA9, 0xAA, 0x9C, 0xDB, 0xA5, 0x99, 0xE3, 0xA8, 0x9E, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
	0x2D, 0x2F, 0xDF, 0xDC, 0x9A, 0xDD, 0xDE, 0x98, 0x9D, 0xAC, 0xBA, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
	0xD7, 0x88, 0x94, 0xB0, 0xB1, 0xB2, 0xFC, 0xD6, 0xFB, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
	0xF8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x96, 0xA4, 0xF3, 0xAF, 0xAE, 0xC5,
	0x8C, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x97, 0x87, 0xCE, 0x93, 0xF1, 0xFE,
	0xC8, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0xEF, 0xC0, 0xDA, 0x5B, 0xF2, 0xF9,
	0xB5, 0xB6, 0xFD, 0xB7, 0xB8, 0xB9, 0xE6, 0xBB, 0xBC, 0xBD, 0x8D, 0xD9, 0xBF, 0x5D, 0xD8, 0xC4,
	0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0xCB, 0xCA, 0xBE, 0xE8, 0xEC, 0xED,
	0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0xA1, 0xAD, 0xF5, 0xF4, 0xA3, 0x8F,
	0x5C, 0xE7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0xA0, 0x85, 0x8E, 0xE9, 0xE4, 0xD1,
	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0xB3, 0xF7, 0xF0, 0xFA, 0xA7, 0xFF
};


/*
 * Convert ASCII to EBCDIC
 */
char a2e[] =
{
	0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, 0x16, 0x05, 0x25, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
	0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x35, 0x1F,
	0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
	0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
	0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
	0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
	0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
	0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
	0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, 0x16, 0x05, 0x25, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
	0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x35, 0x1F,
	0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
	0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
	0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
	0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
	0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
	0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07
};


/*
 * System headers (already included by "angband.h" XXX XXX XXX)
 */
#include <string.h>
#include <ctype.h>
#include <stdio.h>

/* Some prototypes and definitions */

#define FIELD_SY 1
#define FIELD_SX 80
#define FIELD_EY 2
#define FIELD_EX 10

void GetAddr(int, int, char *);
void InitConsole(void);
void TerminateConsole(void);
void ResetScrBuf(void);
void AddScrBuf(char *, int);
char InKey(void);
char InKeyBuf(void);
void ScreenClear(void);
void ResetDISP(void);
int kbhit(void);
void ShowLine(int y, int x, int len);
void LoadProfile(void);

/* Changed lines marker. */

char DISP[26];

/* Max rows & columns number in screen (note that in older version
 ** than 2.7.9 we needed 25 lines, though 24th was unused. So it is set
 ** to 25 although screen actually has only 24 lines. (we just used to
 ** transfer 25th line into 24th.
 ** But in new version we no longer use it.
 */

int rows, cols;

/* Game cursor position on screen */

int curx = 1;
int cury = 1;

/*
 * Virtual Screen
 */
byte VirtualScreen[2048];
byte ScreenAttr[2048];

/*
 * This array is used for "wiping" the screen, initialized in "init_wat()"
 */
byte wiper[256];

/*
 * The main screen
 */
static term term_screen_body;


/* Update line on screen.
 ** Actually just set flag that we should update it.
 */
void ScreenUpdateLine(int line)
{
	DISP[line + 1] = 1;
}

/*
 * Clear the whole screen
 */
void ScreenClear(void)
{
	int iy;

	for (iy = 0; iy < rows; iy++)
	{
		memcpy(VirtualScreen + (iy*cols), wiper, cols);
		memset(ScreenAttr + (iy*cols), 0xF1, cols);
		ScreenUpdateLine(iy);
	}
}


/*
 * Nuke a Term
 */
static void Term_nuke_vm(term *t)
{
	TerminateConsole();
	puts("Console has been terminated(nuke).");
}

/*
 * Move the cursor
 */
static errr Term_curs_vm(int x, int y)
{
	/* Hack: mark line cursor was at as changed to ensure that old
	 ** cursor would be removed.
	 */
	DISP[cury] = 1;
	curx = x + 1;
	cury = y + 1;
	return (0);
}


/*
 * The Angband color table
 *
 * Comment: White has been changed to blue to make screen look better.
 *          Green and Light Green are exchanged for the same reason.
 *          -0x80 means changing to bold font.
 *
 * Color Table:
 * Dark to Blue, White to Blue, Slate to Blue, Orange to Pink,
 * Red to Red, Green to GreenB, Blue to BlueB, Umber to Yellow,
 * Gray to Blue, Light White to WhiteB, Violet to PinkB, Yellow to Yellow
 * Light colors: Red to RedB,Green to Green,Blue to Cyan, Umber to YellB
 */
static const byte vm_color[] =
{
	0xF1, 0xF1, 0xF1, 0xF3,
	0xF2, 0xF4 - 0x80, 0xF1 - 0x80, 0xF6,
	0xF1, 0xF7 - 0x80, 0xF3 - 0x80, 0xF6,
	0xF2 - 0x80, 0xF4, 0xF5, 0xF6 - 0x80
};

/*
 * Place some text on the screen using an attribute
 */
static errr Term_text_vm(int x, int y, int n, byte a, cptr s)
{
	register int i;
	register byte attr;
	register byte *dest;
	register byte *dest2;

	/* Attribute... */
	attr = vm_color[a & 0x0F];

	/* Paranoia */
	if (n > cols - x) n = cols - x;

	/* Access the destination */
	dest = VirtualScreen + ((cols * y) + x);
	dest2 = ScreenAttr + ((cols * y) + x);

	/* Virtually write the string */
	for (i = 0; (i < n) && s[i]; i++)
	{
		*dest++ = s[i];
		*dest2++ = attr;
	}

	/* Dump the line */
	ScreenUpdateLine(y);

	/* Success */
	return (0);
}


/*
 * Erase part of line.
 */
static errr Term_wipe_vm(int x, int y, int w)
{

	/* Paranoia -- Verify the dimensions */
	if (cols < (w + x)) w = (cols - x);

	/* Wipe part of the virtual screen, and update */
	memcpy(VirtualScreen + (y*cols + x), wiper, w);
	memset(ScreenAttr + (y*cols + x), 0xF1, w);
	ScreenUpdateLine(y);

	/* Success */
	return (0);
}


/*
 * Handle special request.
 */
static errr Term_xtra_vm(int n, int v)
{
	int i, j;
	char tmp;

	/* Analyze the request */
	switch (n)
	{

		/* Make a noise */
	case TERM_XTRA_NOISE:

		/* No noises here! :) */
		return (0);

		/* Wait for a single event */
	case TERM_XTRA_EVENT:

		/* No wait key press check */
		if (!v && !kbhit()) return (1);

		/* Wait for a keypress */
		i = getkey();

		/* Save keypress */
		Term_keypress(i);

		/* Success */
		return (0);

	case TERM_XTRA_CLEAR:

		ScreenClear();
		return (0);

#if 0
	case TERM_XTRA_FROSH:
		ScreenUpdateLine(VirtualScreen + (cols*v), v);
		return (0);
#endif

	case TERM_XTRA_FLUSH:

		/* Flush keys */
		while (1)
		{
			tmp = getkeybuf();
			if (!tmp) break;
			Term_keypress(tmp);
		}

		/* Success */
		return (0);
	}

	/* Unknown request */
	return (1);
}


/*
 * Initialize the VM/CNSconsole.
 */
errr init_vme(void)
{
	register i;

	term *t = &term_screen_body;

	short blank = ' ';

	static int done = FALSE;

	/* Paranoia -- Already done */
	if (done) return ( -1);

	/* Build a "wiper line" of blank spaces */
	for (i = 0; i < 256; i++) wiper[i] = blank;

	/* Acquire the size of the screen */
	rows = 25;
	cols = 80;

	/* Initialize the console */
	InitConsole();

	/* Wipe the screen */
	for (i = 0; i < rows; i++)
	{
		/* Wipe that row */
		memcpy(VirtualScreen + (i*cols), wiper, cols);
		memset(ScreenAttr + (i*cols), 0xF1, cols);
	}

	/* Erase the screen */
	ScreenClear();

	/* Initialize the term -- very large key buffer */
	term_init(t, cols, rows - 1, 1024);

	/* Prepare the init/nuke hooks */
	t->nuke_hook = Term_nuke_vm;

	/* Connect the hooks */
	t->text_hook = Term_text_vm;
	t->wipe_hook = Term_wipe_vm;
	t->curs_hook = Term_curs_vm;
	t->xtra_hook = Term_xtra_vm;

	/* Save it */
	term_screen = t;

	/* Activate it */
	Term_activate(term_screen);

	/* Done */
	done = TRUE;

	/* Success */
	return 0;
}

/* Wait for keypress */
int
getkey(void)
{
	return ((int)InKey());
}

/* Read key buffer if not empty */

int
getkeybuf(void)
{
	return ((int)InKeyBuf());
}


/*********************************************************************/
/*********************************************************************/
/******************   Actual work with console   *********************/
/*********************************************************************/


/* Low-level functions */
int CNSINIT(char *path, int device);
int CNSTERM(char *path);
int CNSREAD(char *path, char *buffer, int buflen);
int CNSWRITE(char *path, char *buffer, int buflen);

#define _PF1    (0xF1)
#define _PF2    (0xF2)
#define _PF3    (0xF3)
#define _PF4    (0xF4)
#define _PF5    (0xF5)
#define _PF6    (0xF6)
#define _PF7    (0xF7)
#define _PF8    (0xF8)
#define _PF9    (0xF9)
#define _PF10   (0x7A)
#define _PF11   (0x7B)
#define _PF12   (0x7C)
#define _PF13   (0xC1)
#define _PF14   (0xC2)
#define _PF15   (0xC3)
#define _PF16   (0xC4)
#define _PF17   (0xC5)
#define _PF18   (0xC6)
#define _PF19   (0xC7)
#define _PF20   (0xC8)
#define _PF21   (0xC9)
#define _PF22   (0x4A)
#define _PF23   (0x4B)
#define _PF24   (0x4C)

#define _PA2    (0x6E)
#define _PA3    (0x6B)

#define _CLEAR  (0x60)

#define _ENTER  (0x7D)

extern char cnscrstb[];    /* Hardware 3270 cursor offsets */

/* Console identificator */
char *cons = "console";

/* Console interrupt flag; should be set by assembler patch */
int CNSINTR;
/* Assembler function prototype; this handles console interrupt */
extern int CNSHD();

/* Buffer for output stream (VM/ESA uses streams to control terminals */
static char * ScrBuf;
/* Incoming buffer from console after cnsread */
static char * InBuf;
/* User entered command buffer (paranoia: make it so long no one will
 ** ever run short of it :)
 */
static char ComBuf[256];
/* Pointer to current position in ComBuf */
static char * ComPtr;
/* This array is used to clean up input field.
 ** Comment: erase everything user entered after we accepted it.
 */
static char wiping[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
/* Flag: should we wipe input field ? */
static int wipe = 0;
/* Counter: how many times did game checked if we pressed any key.
 ** Comment: after every 100th we update the screen.
 ** Comment2: because of slow work with screen it would be _very_
 **           unwise to make it more often.
 */
static int kbhitcount;
/* Keep length of collected output stream */
static int BufLen;
/* Define array which will be used to bring actual cursor
 ** (not game cursor!!!) back to the beginning of input field.
 */
static char CursorHome[] = {0, 0, 0, 0x13};
/* Define array to make fields on the screen.
 ** Comment: 2 fields: input field(writable), and game field(protected).
 ** Comment2: We will change PSS settings into dumb repeating of color
 **           setting if PSS fonts are not abailable.
 */
static char ScrField[] =
        {0, 0, 0, 0x29, 0x03, 0xC0, 0xC1, 0x42, 0xF3, 0x43, 0xC1, \
         0, 0, 0, 0x29, 0x03, 0xC0, 0x60, 0x42, 0xF1, 0x43, 0xC1};
/* Last command user entered (for repeating purposes */
static char LastCmd[256];
/* Array which holds PFkeys definitions */
static char PFcmd[25][80];


/* Actually initialize console ... */
void InitConsole(void)
{
	/* Use this to activate full screen mode after console has been
	 ** initialized.
	 */
	unsigned char init[6] =
	        {0xC2, 0x11, 0x40, 0x40, 0, 0};
	int i;
	/* Array for checking is PSS fonts are loaded */
	char pss[256];

	/* Allocate memory */
	ScrBuf = malloc(4100);
	if (ScrBuf == NULL)
	{
		puts("Cannot mallocate memory for screen buffer!");
		exit(77);
	}
	/* Block system standarts... */
	system("cp set msg off");
	system("cp set emsg off");
	system("cp set imsg off");
	system("cp term brkkey none");
	/* Test PSS */
	system("desbuf");
	system("query display (stack");
	gets(pss);
	i = 1;
	if (pss[63] != 'P') i = 0;
	if (pss[64] != 'S') i = 0;
	if (pss[65] != 'S') i = 0;
	if (pss[72] != '0') i = 0;
	if (pss[73] != '1') i = 0;
	if (pss[74] != 'A') i = 0;
	if (pss[75] != 'B') i = 0;
	if (i == 0)
	{
		/* No PSS. Cannot run without them... */
		puts("ERROR: Cannot run without PSS fonts!");
		exit(77);
	}
	ScrBuf[0] = 0xC2;
	ScrBuf[1] = 0;
	BufLen = 1;
	/* Allocate memory */
	InBuf = malloc(200);
	if (InBuf == NULL)
	{
		puts("Cannot mallocate memory for screen buffer!");
		exit(77);
	}
	/* Okay, lets make some intial assigments */
	InBuf[0] = 0;
	ComBuf[0] = 0;
	ComPtr = ComBuf;
	LastCmd[0] = 0;
	GetAddr(FIELD_SY, FIELD_SX, ScrField);
	GetAddr(FIELD_EY, FIELD_EX, ScrField + 11);
	GetAddr(FIELD_SY, FIELD_SX + 1, wiping);
	GetAddr(FIELD_SY, FIELD_SX + 1, CursorHome);
	/* Initialize console */
	cnsxinit(cons, 0x9, 1, CNSHD);
	/* Activate full-screen mode */
	cnswrite(cons, init, 6);
	/* No lines on screen were changed */
	for (i = 1; i < 25; i++)
		DISP[i] = 0;
	/* Corsor home... */
	AddScrBuf(CursorHome, sizeof(CursorHome));
	/* No console interrupt yet */
	CNSINTR = 0;
	/* No check keypresses yet */
	kbhitcount = 0;
	/* Let's load 'profile angband' for PFs settings */
	LoadProfile();
}

void TerminateConsole(void)
{
	free(ScrBuf);
	free(InBuf);
	/* Terminate console */
	cnsterm(cons);
	/* Restore system defaults.
	 ** Comment: better we should have written them down at start but
	 ** it is reasonably difficult to make, so just set standart values.
	 */
	system("cp set msg on");
	system("cp set emsg on");
	system("cp set imsg on");
	system("cp term brkkey pa1");
}

/* Reset collected output stream */
void ResetScrBuf(void)
{
	int i;
	unsigned char attr;

	/* Where shall cursor be ? */
	GetAddr(cury, curx, ScrBuf + BufLen);
	BufLen += 3;
	/* Actually 'make' cursor : underline symbol */
	ScrBuf[BufLen++] = 0x28;
	ScrBuf[BufLen++] = 0x41;
	ScrBuf[BufLen++] = 0xF4;
	attr = *(ScreenAttr + (cury - 1) * cols + curx - 1);
	ScrBuf[BufLen++] = 0x28;
	ScrBuf[BufLen++] = 0x42;
	ScrBuf[BufLen++] = attr | 0x80;
	ScrBuf[BufLen++] = 0x28;
	ScrBuf[BufLen++] = 0x43;
	if (attr > 0x80) ScrBuf[BufLen++] = 0xC1;
	else ScrBuf[BufLen++] = 0xC2;
	ScrBuf[BufLen++] = *(VirtualScreen + (cury - 1) * cols + curx - 1);
	ScrBuf[BufLen++] = 0x28;
	ScrBuf[BufLen++] = 0x41;
	ScrBuf[BufLen++] = 0x00;
	ScrBuf[BufLen++] = 0x28;
	ScrBuf[BufLen++] = 0x43;
	ScrBuf[BufLen++] = 0xC1;
	/* Draw screen fields.
	 ** Comment: paranoia, should always be there, but won't be any worse
	 **          if we redraw them.
	 */
	memcpy(ScrBuf + BufLen, ScrField, 22);
	if (wipe)
	{
		/* If we should wipe input field, let's do it. */
		wipe = 0;
		memcpy(ScrBuf + BufLen + 22, wiping, sizeof(wiping));
		/* Actually write to terminal */
		cnswrite(cons, ScrBuf, BufLen + 22 + sizeof(wiping));
	}
	else
	{
		/* Actually write to terminal */
		cnswrite(cons, ScrBuf, BufLen + 22);
	}
	/* Discard old output stream */
	ScrBuf[0] = 0xC2;
	ScrBuf[1] = 0;
	BufLen = 1;
}

/* Just add some more to output stream */
void AddScrBuf(char * ptr, int len)
{
	/* Stream cannot be longer than 4k, so reset it */
	if (len + BufLen > 4000) ResetScrBuf();
	memcpy(ScrBuf + BufLen, ptr, len);
	BufLen += len;
}

/* Calculate codes for cursor setting and write them down into *stream.
 ** Comment: system has _really crazy tables for this calculation so
 **          we need function for this.
 */
void GetAddr(int y, int x, char *stream)
{
	int sx, sy, len;

	len = y * 80 + x - 81;

	sx = len & 0x3F;
	sy = len >> 6;

	*stream++ = 0x11;
	/* Use standart array for cursor offsets (VMSERV TXTLIB) */
	*stream++ = cnscrstb[sy];
	*stream = cnscrstb[sx];
}

/* Okay, program requested pressed key, let's return it */
char InKey(void)
{
	char ret;
	char * info;
	int i;
	char *ptr, *ptrs;
	int PF;
	int prev;

	/* If we didn't finish previous line user entered just return
	 ** next symbol.
	 ** Comment: unlikely IBM PC and others user may enter string
	 **          of any length (limited by input field length to 9
	 **          symbols) and only them by pressing ENTER key or
	 **          functional key make real console interrupt.
	 **          So we should handle everything user entered.
	 */
	if (*ComPtr)
	{
		ret = *ComPtr;
		ComPtr++;
		return (ret);
	}
	/* If we get here than user command buffer is empty and we have
	 ** actually wait for new command.
	 */
	/* Okay, update screen before :) */
	ResetDISP();
	/* Well, now wait till user enters something and read it. */
	cnsread(cons, InBuf, 200);
	/* Oh, we already handling interrupt so, reset interrupt flag */
	CNSINTR = 0;
	/* No previous cmd inserted yet */
	prev = 0;
	/* User pressed CLEAR key. Redraw all screen then. */
	if (*InBuf == 0x6D)
	{
		/* Hack: mark all lines as changed */
		for (i = 1; i < 26; i++)
			DISP[i] = 1;
		/* Cursor home */
		AddScrBuf(CursorHome, sizeof(CursorHome));
		/* Redraw the whole screen */
		ResetDISP();
		/* Hack: we should return something, shouldn't we?
		 ** Just return CR. It seems safest.
		 */ 
		return (13);
	}
	/* Okay parse stream from console to make string only of
	 ** user's input.
	 */
	info = memchr(InBuf, 0x1D, 200);
	info += 2;
	info[9] = 0;
	/* Mark that we should clear input field */
	wipe = 1;
	/* Cursor home */
	AddScrBuf(CursorHome, sizeof(CursorHome));
	/* Pointer to current letter in buffered command set to start */
	ComPtr = ComBuf;
	/* Clear length buffer */
	ComBuf[0] = 0;
	switch (*InBuf)
	{
		/* PA2 & PA1 */
	case 0x6E:
		;
	case 0x6C:
		/* These 2 keys are supposed to mean 'ESC' */
		return (27);
		break;
		/* Hack: determine which PF key was exactly pressed.
		 */
	case _PF1:
		PF = 1;
		break;
	case _PF2:
		PF = 2;
		break;
	case _PF3:
		PF = 3;
		break;
	case _PF4:
		PF = 4;
		break;
	case _PF5:
		PF = 5;
		break;
	case _PF6:
		PF = 6;
		break;
	case _PF7:
		PF = 7;
		break;
	case _PF8:
		PF = 8;
		break;
	case _PF9:
		PF = 9;
		break;
	case _PF10:
		PF = 10;
		break;
	case _PF11:
		PF = 11;
		break;
	case _PF12:
		PF = 12;
		break;
	case _PF13:
		PF = 13;
		break;
	case _PF14:
		PF = 14;
		break;
	case _PF15:
		PF = 15;
		break;
	case _PF16:
		PF = 16;
		break;
	case _PF17:
		PF = 17;
		break;
	case _PF18:
		PF = 18;
		break;
	case _PF19:
		PF = 19;
		break;
	case _PF20:
		PF = 20;
		break;
	case _PF21:
		PF = 21;
		break;
	case _PF22:
		PF = 22;
		break;
	case _PF23:
		PF = 23;
		break;
	case _PF24:
		PF = 24;
		break;
		/* Uh, user pressed ENTER.
		 ** Determine if we should add 'CR' at the end or not ?
		 */
	case _ENTER:
		PF = 0;
		/* Copy entered string into buffer */
		strcpy(ComBuf, info);
		/* Never end strings of length 1 or 0 with CR */
		if (strlen(ComBuf) < 2) break;
		/* If string ends with R* or R& add CR */
		ptr = info + strlen(info) - 1;
		if (*ptr == '*' || *ptr == '&')
		{
			ptr--;
			if (ptr < info) break;
			if (*ptr != 'R') break;
			ptr = ComBuf + strlen(ComBuf);
			ptr[0] = 13;
			ptr[1] = 0;
			break;
		}
		/* Well, only numbers should be padded with CR.
		 ** Comment: handle 18/... too.
		 */
		if (!isdigit(*ptr)) break;
		ptr--;
		i = 1;
		while (ptr >= info)
		{
			if (*ptr == 'R') break;
			if (*ptr == '@' && ptr == info)
				break;
			if (*ptr == '/')
			{
				i = 0;
				if (*(ptr - 1) != '8') break;
				if (*(ptr - 2) != '1') break;
				if ((ptr - 2) != info) break;
				i = 1;
				break;
			}
			if (!isdigit(*ptr))
			{
				i = 0;
				break;
			}
			ptr--;
		}
		if (i)
			ptr = ComBuf + strlen(ComBuf);
		ptr[0] = 13;
		ptr[1] = 0;
		break;
	default:
		PF = 0;
	}
	/* Okay let's proceed with parsing PFkeys commands */
	ptrs = PFcmd[PF];
	ptr = ComBuf;
	/* If key actually was PF and we didn't run into end of PF
	 ** command definition...
	 */
	while (*ptrs && PF)
	{
		/* If not '\' just copy symbol into buffer */
		if (*ptrs != '\\')
		{
			*ptr = *ptrs;
			ptr++;
			ptrs++;
			continue;
		}
		/* We have discovered '\'. Let's resolve it. */
		ptrs++;
		switch (*ptrs)
		{
			/* End of line ? Do nothing then. */
		case 0:
			break;
			/* User actually wants '\' */
		case '\\':
			*ptr = '\\';
			ptr++;
			break;
			/* User wants his previous command inserted. */
		case 'p':
			/* Set flag that we used previous command */
			prev = 1;
			strcpy(ptr, LastCmd);
			ptr = ComBuf + strlen(ComBuf);
			break;
			/* Insert string user actually entered */
		case 's':
			strcpy(ptr, info);
			ptr = ComBuf + strlen(ComBuf);
			break;
			/* User wants 'CR' */
		case 'n':
			*ptr = 13;
			ptr++;
			break;
			/* Simulate CTRL key pressing */
		case '^':
			ptrs++;
			if (!(*ptrs)) break;
			*ptr = KTRL(*ptrs);
			ptr++;
			break;
			/* ESC */
		case 'c':
			*ptr = 27;
			ptr++;
			break;
			/* Hmm, urecognized command. Just copy letter. */
		default:
			*ptr = *ptrs;
			ptr++;
		}
		if (ptrs) ptrs++;
	}
	/* Terminate string with 0 if neccessary */
	if (PF) *ptr = 0;
	/* Empty string? User probably wants to send CR. */
	if (!(*ComBuf))
	{
		return (13);
	}
	/* Okay, set pointer to next letter */
	ComPtr++;
	/* Backup last command if not empty */
	ptr = ComBuf;
	/* String still "empty" */
	i = 1;
	while ((*ptr) && i)
	{
		if ((*ptr != 13) && (*ptr != 27) && (*ptr != ' '))
			i = 0;
		ptr++;
	}
	/* Never update previous command if we inserted it.
	 ** Comment: this is to avoid recursively multiplying previous
	 **          commands.
	 */
	if ((!i) && (!prev))
		strcpy(LastCmd, ComBuf);
	/* Return something */
	return (*ComBuf);
}

/* Get symbol from buffer if exists */

char InKeyBuf(void)
{
	char ret;

	ret = *ComPtr;
	if (ret) ComPtr++;
	return (ret);
}

/* Here we draw all changed lines */
void ResetDISP(void)
{
	int i;

	/* No need to redraw screen in near future */
	kbhitcount = 0;
	for (i = 1; i < 25; i++)
		if (DISP[i] != 0)
		{
			/* If line was changed, it won't stay changed any more */
			DISP[i] = 0;
			/* We don't want to erase input field definitons from
			 ** screen, so check it carefully.
			 */
			switch (i)
			{
			case FIELD_SY:
				ShowLine(i, 1, FIELD_SX - 1);
				if (i == FIELD_EY)
				{
					ShowLine(i, FIELD_EX + 1, 80-FIELD_EX);
				}
				break;
			case FIELD_EY:
				ShowLine(i, FIELD_EX + 1, 80-FIELD_EX);
				break;
			default:
				ShowLine(i, 1, 80);
			}
		}
	/* Okay, actually show something */
	ResetScrBuf();
}

/* Did user press something? */
int kbhit(void)
{
	kbhitcount++;
	if (kbhitcount > 99)
	{
		/* We waited long enough, time to redraw screen.
		 ** Comment: during sleep every 100th turn is shown.
		 */
		kbhitcount = 0;
		ResetDISP();
	}
	return (CNSINTR);
}

/* Let's show requested line(or part of it). */
void ShowLine(int y, int x, int len)
{
	char slbuf[512];
	char *ptr, *scr, *attr;
	int i;
	unsigned char curattr;

	ptr = slbuf + 3;
	/* Hack: was used for older version to place 25th string on
	 ** 24th.
	 */
	if (y < 25)
		GetAddr(y, x, slbuf);
	else
		GetAddr(24, x, slbuf);
	/* Set some adresses */
	curattr = 0;
	scr = VirtualScreen + (y - 1) * cols + x - 1;
	attr = ScreenAttr + (y - 1) * cols + x - 1;
	/* Let's proceed with string. */
	for (i = 0; i < len; i++)
	{
		/* Attribute has changed ? Let's add codes for changing color */
		if (*attr != curattr)
		{
			/* Pss has changed ? Let's change pss. */
			if (((*attr)&0x80) != (curattr&0x80) || (!curattr))
			{
				*ptr++ = 0x28;
				*ptr++ = 0x43;
				if (*attr > 0x80) *ptr++ = 0xC1;
				else *ptr++ = 0xC2;
			}
			/* Color has changed ? Let's change it. */
			if (((*attr)&0x7F) != (curattr&0x7F))
			{
				*ptr++ = 0x28;
				*ptr++ = 0x42;
				if (*attr > 0x80) *ptr++ = *attr;
				else *ptr++ = *attr + 0x80;
			}
			curattr = *attr;
		}
		*ptr++ = *scr;
		scr++;
		attr++;
	}
	/* Add string to output stream */
	AddScrBuf(slbuf, ptr - slbuf);
}

void LoadProfile(void)
{

	FILE *fp;
	char line[128], *ptr, *pfptr, *p;
	int pf, i;

	for (i = 1; i <= 24; i++) strcpy(PFcmd[i], "\\s");

	fp = fopen("PROFILE ANGBAND", "r");
	if (!fp) return;
	{
		while (fgets(line, 128, fp))
		{
			if (*line == '#') continue;
			ptr = strstr(line, "PF");
			if (!ptr) continue;
			ptr += 2;
			p = ptr;
			while (isdigit(*p)) ++p;
			*p++ = 0;
			pf = atoi(ptr);
			if (pf < 1 || pf > 24) continue;
			ptr = strchr(p, '"');
			++ptr;
			p = strchr(ptr, '"');
			if (!p)
			{
				puts("'\"' missing in PROFILE ANGBAND.");
				continue;
			}
			*p = 0;
			strcpy(PFcmd[pf], ptr);
		}
	}
}

/*
 **
 ** File descriptor emulation for VM/ESA
 **
 **
 */

#include <string.h>
#include <stdio.h>
#include "fcntl.h"

static FILE *file_descriptors[40];

int
open(char *name, int flags, int mode)
{
	char fmode[16];
	FILE *fp;
	int i;

	strcpy(fmode, "rb");
	if ((flags & O_WRONLY) || (flags & O_RDWR)) strcpy(fmode, "wb+");

	fp = fopen(name, fmode);

	if (!fp) return ( -1);
	for (i = 1; i < 40; i++)
		if (!file_descriptors[i])
		{
			file_descriptors[i] = fp;
			return (i);
		}
	return ( -1);
}

void
close(int fd)
{
	fclose(file_descriptors[fd]);
}

int
read(int fd, char *buff, int bytes)
{
	return (fread(buff, 1, bytes, file_descriptors[fd]));
}

int
write(int fd, char *buff, int bytes)
{
	return (fwrite(buff, 1, bytes, file_descriptors[fd]));
}

long
lseek(int fd, long pos, int set)
{
	return (fseek(file_descriptors[fd], pos, set));
}

void
unlink(char *filename)
{
	remove(filename);
}


#endif /* USE_VME */

