/*	SCCS Id: @(#)msdos.c	1.3	87/07/14
/* An assortment of MSDOS functions.
 */

#include <stdio.h>
#include "hack.h"

#ifdef MSDOS
#include <sys/dos.h>

//char crap[1024*200];

void
flushout()
{
//memset(crap,0x0,sizeof(crap));
	(void) fflush(stdout);
}

getuid() {
	return 1;
}

char *
getlogin() {
	return ((char *) NULL);
}

tgetch(){
char ch;
ch = _dos_getc();
//scanf("%c",&ch);
fflush(stdout);
fflush(stdin);
return ((ch == '\r') ? '\n' : ch);
}

Otgetch() {

	char ch, popch();
	char DOSgetch(), BIOSgetch();

	if (!(ch = popch())) {
# ifdef DGK
		/* BIOSgetch can use the numeric key pad on IBM compatibles. */
		if (flags.IBMBIOS)
			ch = BIOSgetch();
		else
# endif
			ch = DOSgetch();
	}
	return ((ch == '\r') ? '\n' : ch);
}

# define DIRECT_INPUT	0x7
char
DOSgetch() {

}


# ifdef DGK
#  include <ctype.h>
#  include <fcntl.h>

#  define Sprintf (void) sprintf
#  define WARN 1
#  define NOWARN 0

static char *
getcomspec(warn) {
	return getenv("COMSPEC");
}

#  ifdef SHELL
#   include <process.h>
dosh() {
	extern char orgdir[];
	char *comspec;

	if (comspec = getcomspec()) {
		settty("To return to HACK, type \"exit\" at the DOS prompt.\n");
		chdirx(orgdir, 0);
//		if (spawnl(P_WAIT, comspec, comspec, NULL) < 0) 
			{
			printf("\nCan't spawn %s !\n", comspec);
			flags.toplin = 0;
			more();
		}
		chdirx(hackdir, 0);
		start_screen();
		docrt();
	} else
		pline("No COMSPEC !?  Can't exec COMMAND.COM");
	return(0);
}
#  endif /* SHELL */

/* Normal characters are output when the shift key is not pushed.
 * Shift characters are output when either shift key is pushed.
 */
#  define KEYPADHI	83
#  define KEYPADLOW	71
#  define iskeypad(x)	(KEYPADLOW <= (x) && (x) <= KEYPADHI)
static struct {
	char normal, shift;
	} keypad[KEYPADHI - KEYPADLOW + 1] = {
			{'y', 'Y'},		/* 7 */
			{'k', 'K'},		/* 8 */
			{'u', 'U'},		/* 9 */
			{'m', CTRL('P')},	/* - */
			{'h', 'H'},		/* 4 */
			{'g', 'g'},		/* 5 */
			{'l', 'L'},		/* 6 */
			{'p', 'P'},		/* + */
			{'b', 'B'},		/* 1 */
			{'j', 'J'},		/* 2 */
			{'n', 'N'},		/* 3 */
			{'i', 'I'},		/* Ins */
			{'.', ':'}		/* Del */
};

/* BIOSgetch gets keys directly with a BIOS call.
 */
#  define SHIFT		(0x1 | 0x2)
#  define KEYBRD_BIOS	0x16

char
BIOSgetch() {
	unsigned char scan, shift, ch;
	return ch;
}

/* construct the string  file.level */
void
name_file(file, level)
char *file;
int level;
{
	char *tf;
	
	if (tf = rindex(file, '.'))
		Sprintf(tf+1, "%d", level);
}


#  define FINDFIRST	0x4E00
#  define FINDNEXT	0x4F00
#  define GETDTA	0x2F00
#  define SETFILETIME	0x5701
#  define GETSWITCHAR	0x3700
#  define FREESPACE	0x36

static char
switchar()
{
}

long
freediskspace(path)
char *path;
{
return 32768*1024;
}

/* Functions to get filenames using wildcards
 */
static
findfirst(path)
char *path;
{
}

static
findnext() {
}

/* Get disk transfer area */
static char *
getdta() {
}

long
filesize(file)
char *file;
{
	char *dta;

	if (findfirst(file)) {
		dta = getdta();
		return  (* (long *) (dta + 26));
	} else
		return -1L;
}

void
eraseall(path, files)
char *path, *files;
{
	char *getdta(), *dta, buf[PATHLEN];

	dta = getdta();
	Sprintf(buf, "%s%s", path, files);
	if (findfirst(buf))
		do {
			Sprintf(buf, "%s%s", path, dta + 30);
			(void) unlink(buf);
		} while (findnext());
}

/* Rewritten for version 3.3 to be faster
 */
void
copybones(mode) {
	char from[PATHLEN], to[PATHLEN], last[13], copy[8];
	char *frompath, *topath, *dta, *comspec;
	int status;
	long fs;
	extern saveprompt;

	if (!ramdisk)
		return;

	/* Find the name of the last file to be transferred
	 */
	frompath = (mode != TOPERM) ? permbones : levels;
	dta = getdta();
	last[0] = '\0';
	Sprintf(from, "%s%s", frompath, allbones);
	if (findfirst(from))
		do {
			strcpy(last, dta + 30);
		} while (findnext());

	topath = (mode == TOPERM) ? permbones : levels;
	if (last[0]) {
		Sprintf(copy, "%cC copy", switchar());

		/* Remove any bones files in `to' directory.
		 */
		eraseall(topath, allbones);

		/* Copy `from' to `to' */
		Sprintf(to, "%s%s", topath, allbones);
		comspec = getcomspec();
		//status =spawnl(P_WAIT, comspec, comspec, copy, from,to, "> nul", NULL);
		status = -1;
	} else
		return;

	/* See if the last file got there.  If so, remove the ramdisk bones
	 * files.
	 */
	Sprintf(to, "%s%s", topath, last);
	if (findfirst(to)) {
		if (mode == TOPERM)
			eraseall(frompath, allbones);
		return;
	}

	/* Last file didn't get there.
	 */
	Sprintf(to, "%s%s", topath, allbones);
	msmsg("Cannot copy `%s' to `%s' -- %s\n", from, to,
		(status < 0) ? "can't spawn COMSPEC !" :
		(freediskspace(topath) < filesize(from)) ?
			"insufficient disk space." : "bad path(s)?");
	if (mode == TOPERM) {
		msmsg("Bones will be left in `%s'\n",
			*levels ? levels : hackdir);
		return;
	} else {
		/* Remove all bones files on the RAMdisk */
		eraseall(levels, allbones);
		playwoRAMdisk();
	}
}

playwoRAMdisk() {
	msmsg("Do you wish to play without a RAMdisk (y/n) ? ");

	/* Set ramdisk false *before* exit'ing (because msexit calls
	 * copybones)
	 */
	ramdisk = FALSE;
	if (getchar() != 'y') {
		settty("Be seeing you ...\n");
		exit(0);
	}
	set_lock_and_bones();
	return;
}

saveDiskPrompt(start) {
	extern saveprompt;
	char buf[BUFSIZ], *bp;
	int fd;

	if (saveprompt) {
		/* Don't prompt if you can find the save file */
		if ((fd = open(SAVEF, 0)) >= 0) {
			(void) close(fd);
			return 1;
		}
		remember_topl();
		home();
		cl_end();
		msmsg("If save file is on a SAVE disk, put that disk in now.\n");
		cl_end();
		msmsg("File name (default `%s'%s) ? ", SAVEF,
			start ? "" : ", <Esc> cancels save");
		getlin(buf);
		home();
		cl_end();
		curs(1, 2);
		cl_end();
		if (!start && *buf == '\033')
			return 0;

		/* Strip any whitespace. Also, if nothing was entered except
		 * whitespace, do not change the value of SAVEF.
		 */
		for (bp = buf; *bp; bp++)
			if (!isspace(*bp)) {
				strncpy(SAVEF, bp, PATHLEN);
				break;
			}
	}
	return 1;
}

/* Return 1 if the record file was found */
static
record_exists() {
	int fd;

	if ((fd = open(RECORD, 0)) >= 0) {
		close(fd);
		return TRUE;
	}
	return FALSE;
}

/* Return 1 if the comspec was found */
static
comspec_exists() {
	int fd;
	char *comspec;

	if (comspec = getcomspec())
		if ((fd = open(comspec, 0)) >= 0) {
			close(fd);
			return TRUE;
		}
	return FALSE;
}

/* Prompt for game disk, then check for record file.
 */
void
gameDiskPrompt() {
	extern saveprompt;

	if (saveprompt) {
		if (record_exists() && comspec_exists())
			return;
		(void) putchar('\n');
		getreturn("when the GAME disk has been put in");
	}
	if (comspec_exists() && record_exists())
		return;

	if (!comspec_exists())
		msmsg("\n\nWARNING: can't find comspec `%s'!\n", getcomspec());
	if (!record_exists())
		msmsg("\n\nWARNING: can't find record file `%s'!\n", RECORD);
	msmsg("If the GAME disk is not in, put it in now.\n");
	getreturn("to continue");
}

/* Read configuration */
void
read_config_file() {
	char	tmp_ramdisk[PATHLEN], tmp_levels[PATHLEN];
	char	buf[BUFSZ], *bufp;
	FILE	*fp, *fopenp();
	extern	char plname[];
	extern	int saveprompt;

//_dos_c_curoff();

	tmp_ramdisk[0] = 0;
	tmp_levels[0] = 0;
	if ((fp = fopenp(configfile, "r")) == NULL) {
		msmsg("Warning: no configuration file!\n");
		getreturn("to continue");
		return;
	}
	while (fgets(buf, BUFSZ, fp)) {
		if (*buf == '#')
			continue;

		/* remove trailing whitespace
		 */
		bufp = index(buf, '\n');
		while (bufp > buf && isspace(*bufp))
			bufp--;
		if (bufp == buf)
			continue;		/* skip all-blank lines */
		else
			*(bufp + 1) = 0;	/* 0 terminate line */

		/* find the '=' */
		if (!(bufp = strchr(buf, '='))) {
			msmsg("Bad option line: '%s'\n", buf);
			getreturn("to continue");
			continue;
		}
		
		/* skip  whitespace between '=' and value */
		while (isspace(*++bufp))
			;

		/* Go through possible variables */
		if (!strncmp(buf, "HACKDIR", 4)) {
			strncpy(hackdir, bufp, PATHLEN);
		
		} else if (!strncmp(buf, "RAMDISK", 3)) {
			strncpy(tmp_ramdisk, bufp, PATHLEN);

		} else if (!strncmp(buf, "LEVELS", 4)) {
			strncpy(tmp_levels, bufp, PATHLEN);

		} else if (!strncmp(buf, "OPTIONS", 4)) {
			parseoptions(bufp, TRUE);
			if (plname[0])		/* If a name was given */
				plnamesuffix();	/* set the character class */

		} else if (!strncmp(buf, "SAVE", 4)) {
			char *ptr;
			if (ptr = index(bufp, ';')) {
				*ptr = '\0';
				if (*(ptr+1) == 'n' || *(ptr+1) == 'N')
					saveprompt = FALSE;
			}
			(void) strncpy(SAVEF, bufp, PATHLEN);
			append_slash(SAVEF);

		} else if (!strncmp(buf, "GRAPHICS", 4)) {
			struct symbols s;

			if (sscanf(bufp, "%u%u%u%u%u%u%u%u%u", &s.vwall,
				    &s.hwall, &s.tlcorn, &s.trcorn, &s.blcorn,
				    &s.brcorn, &s.door, &s.room, &s.corr) == 9)
				symbol = s;
			else {
				msmsg("GRAPHICS did not contain 9 values\n");
				getreturn("to continue");
			}
		} else {
			msmsg("Bad option line: '%s'\n", buf);
			getreturn("to continue");
		}
	}
	fclose(fp);

	strcpy(permbones, tmp_levels);
	if (tmp_ramdisk[0]) {
		strcpy(levels, tmp_ramdisk);
		if (strcmpi(permbones, levels))		/* if not identical */
			ramdisk = TRUE;
	} else
		strcpy(levels, tmp_levels);
	strcpy(bones, levels);
}

/* Set names for bones[] and lock[]
 */
void
set_lock_and_bones() {
	if (!ramdisk) {
		strcpy(levels, permbones);
		strcpy(bones, permbones);
	}
	append_slash(permbones);
	append_slash(levels);
	append_slash(bones);
	strcat(bones, allbones);
	strcpy(lock, levels);
	strcat(lock, alllevels);
}

/* Add a backslash to any name not ending in /, \ or :   There must
 * be room for the \
 */
void
append_slash(name)
char *name;
{
	char *ptr;

	if (!*name)
		return;
	ptr = name + (strlen(name) - 1);
	if (*ptr != '\\' && *ptr != '/' && *ptr != ':') {
		*++ptr = '\\';
		*++ptr = '\0';
	}
}


void
getreturn(str)
char *str;
{
	int ch;

	msmsg("Hit <RETURN> %s.", str);
//	while ((ch = getchar()) != '\n')
//		;
}

void
msmsg(fmt, a1, a2, a3)
char *fmt;
long a1, a2, a3;
{
	printf(fmt, a1, a2, a3);
	flushout();
}

/* Chdrive() changes the default drive.
 */
#define SELECTDISK	0x0E
void
x68_chdrive(str)
char *str;
{

}

/* Use the IOCTL DOS function call to change stdin and stdout to raw
 * mode.  For stdin, this prevents MSDOS from trapping ^P, thus
 * freeing us of ^P toggling 'echo to printer'.
 * Thanks to Mark Zbikowski (ma...@microsoft.UUCP).
 */

#  define DEVICE	0x80
#  define RAW		0x20
#  define IOCTL		0x44
#  define STDIN		fileno(stdin)
#  define STDOUT	fileno(stdout)
#  define GETBITS	0
#  define SETBITS	1

static unsigned	old_stdin, old_stdout, ioctl();

disable_ctrlP() {
	if (!flags.rawio)
		return;
	old_stdin = ioctl(STDIN, GETBITS, 0);
	old_stdout = ioctl(STDOUT, GETBITS, 0);
	if (old_stdin & DEVICE)
		ioctl(STDIN, SETBITS, old_stdin | RAW);
	if (old_stdout & DEVICE)
		ioctl(STDOUT, SETBITS, old_stdout | RAW);
}

enable_ctrlP() {
	if (!flags.rawio)
		return;
	if (old_stdin)
		(void) ioctl(STDIN, SETBITS, old_stdin);
	if (old_stdout)
		(void) ioctl(STDOUT, SETBITS, old_stdout);
}

static unsigned
ioctl(handle, mode, setvalue)
unsigned setvalue;
{
}

/* Follow the PATH, trying to fopen the file.
 */
#define PATHSEP	';'

FILE *
fopenp(name, mode)
char *name, *mode;
{
	char buf[BUFSIZ], *bp, *pp,lastch;
	//char buf[BUFSIZ], *bp, *pp, *getenv(), lastch;
	FILE *fp;

	/* Try the default directory first.  Then look along PATH.
	 */
	strcpy(buf, name);
	if (fp = fopen(buf, mode))
		return fp;
	else {
		pp = getenv("PATH");
		while (pp && *pp) {
			bp = buf;
			while (*pp && *pp != PATHSEP)
				lastch = *bp++ = *pp++;
			if (lastch != '\\' && lastch != '/')
				*bp++ = '\\';
			strcpy(bp, name);
			if (fp = fopen(buf, mode))
				return fp;
			if (*pp)
				pp++;
		}
	}
	return NULL;
}
# endif /* DGK */

/* Chdir back to original directory
 */
# undef exit
void
msexit(code)
{
# ifdef CHDIR
	extern char orgdir[];
# endif

# ifdef DGK
	flushout();
	enable_ctrlP();		/* in case this wasn't done */
	if (ramdisk)
		copybones(TOPERM);
# endif
# ifdef CHDIR
	chdir(orgdir);		/* chdir, not chdirx */
#  ifdef DGK
	chdrive(orgdir);
#  endif
# endif
	exit(code);
}
#endif /* MSDOS */
