/*
    Copyright (C) 1995-1997
	Rainer Schnitker, Heeper Str. 283, 33607 Bielefeld
	email: rainer@mathematik.uni-bielefeld.de

    All rights reserved
*/

#include <rsxnt.h>

/* not declared in <emx/syscalls.h> */
int __os_version (void);

static void set_errno_eax_eflags(SYSCALL_FRAME *f)
{
    f->e.eax = - f->e.eax;
    f->e.eflags |= 1;
}

int _rsxnt_dos_call(SYSCALL_FRAME *f)
{
    unsigned char rAH = f->h.ah;

    f->e.eflags &= ~1;	     /* clear carry bit */

    switch (f->h.ah) {

    case 0x01: /* read char from stdinput, with echo & C-c */
	f->h.al = __read_kbd(1,1,1);
	return 0;

    case 0x02:
	__write(1, &(f->h.dl), 1);
	return 0;

    case 0x06:
	if (f->h.dl == 0xFF) {	    /* direct console output */
	    int c = __read_kbd(1, 0, 0);
	    if (c != -1) {
		f->h.al = (unsigned char) c;
		f->e.eflags &= ~128;
	    } else
		f->e.eflags |= 128;
	} else			    /* direct console output */
	    __write(1, &(f->h.dl), 1);
	return 0;

    case 0x07:	/* direct character input, without echo & C-c */
	f->h.al = __read_kbd(0,1,0);
	return 0;

    case 0x08:	/* character input without echo , with C-c */
	f->h.al = __read_kbd(0,1,1);
	return 0;

    case 0x0a:	/* get input buffer */
	__cgets ((char *) f->e.edx);
	return 0;

    case 0x0b:
	if (__read_kbd(0,0,1) == -1)
	    f->h.al = 0xFF;
	else
	    f->h.al = 0;
	return 0;

    case 0x0d:
	/* Reset disk. */
	return 0;

    case 0x0e:
	/* Select disk. */
	__chdrive(f->h.dl + 'A');
	f->h.al = 32;
	return 0;

    case 0x19:
	/* Get current disk: a=0 b=1 */
	f->h.al = __getdrive() - 'A';
	return 0;

    case 0x2a:
	/* Get date. */
	break;

    case 0x2c:
	/* Get time. */
	break;

    case 0x30:
	/* Get version number (eax = major|minor) */
	f->e.eax = __os_version();
	return 0;

    case 0x37:
	/* Get or set the switch character. __swchar() */
	f->h.al = __swchar(f->h.ah,f->h.dl);
	return 0;

    case 0x39:
	f->e.eax = __mkdir((const char *)f->e.edx);
	if (f->e.eax < 0)
	    set_errno_eax_eflags(f);
	return 0;

    case 0x3a:
	f->e.eax = __rmdir((const char *)f->e.edx);
	if (f->e.eax < 0)
	    set_errno_eax_eflags(f);
	return 0;

    case 0x3b:
	f->e.eax = __chdir((const char *)f->e.edx);
	if (f->e.eax < 0)
	    set_errno_eax_eflags(f);
	return 0;

    case 0x3c:
	/* old emx 0.8 create handle. */
	break;

    case 0x3d:
	/* old emx 0.8 open handle. */
	break;

    case 0x3e:
	f->e.eax = __close(f->e.ebx);
	if (f->e.eax < 0)
	    set_errno_eax_eflags(f);
	return 0;

    case 0x3f: /* Read handle. */
	f->e.eax = __read(f->e.ebx, (void *) f->e.edx, f->e.ecx);
	if (f->e.eax < 0)
	    set_errno_eax_eflags(f);
	return 0;

    case 0x40: /* Write handle. */
	f->e.eax = __write(f->e.ebx, (const void *) f->e.edx, f->e.ecx);
	if (f->e.eax < 0)
	    set_errno_eax_eflags(f);
	return 0;

    case 0x41: /* Delete directory entry. */
	f->e.eax = __remove((const char *) f->e.edx);
	if (f->e.eax < 0)
	    set_errno_eax_eflags(f);
	return 0;

    case 0x42: /* Move file pointer. */
	f->e.eax = __lseek(f->e.ebx, f->e.edx, f->h.al);
	if (f->e.eax < 0)
	    set_errno_eax_eflags(f);
	return 0;

    case 0x43: /* Get/set file attributes. */
	f->e.eax = __chmod((const char *)f->e.edx, f->h.al, f->e.ecx);
	if (f->e.eax < 0)
	    set_errno_eax_eflags(f);
	else
	    f->e.ecx = f->e.eax;
	return 0;

    case 0x44:
	f->e.edx = __ioctl1(f->e.ebx, f->h.al);
	if (f->e.edx < 0) {
	    f->e.eax = - f->e.edx;
	    f->e.eflags |= 1;
	}
	return 0;

    case 0x45:
	f->e.eax = __dup(f->e.ebx);
	if (f->e.eax < 0)
	    set_errno_eax_eflags(f);
	return 0;

    case 0x46:
	f->e.eax = __dup2(f->e.ebx, f->e.ecx);
	if (f->e.eax < 0)
	    set_errno_eax_eflags(f);
	return 0;

    case 0x47:
	f->e.eax = __getcwd((char *)f->e.esi,
		    (f->h.dl == 0) ? f->h.dl : 'A' + f->h.dl - 1);
	if (f->e.eax < 0)
	    set_errno_eax_eflags(f);
	return 0;

    case 0x4c:
	__exit (f->h.al);
	return 0;

    case 0x4e:
	f->e.eax = __findfirst((const char *)f->e.edx, f->e.ecx, (struct _find *)f->e.esi);
	if (f->e.eax < 0)
	    set_errno_eax_eflags(f);
	return 0;

    case 0x4f:
	f->e.eax = __findnext((struct _find *)f->e.esi);
	if (f->e.eax < 0)
	    set_errno_eax_eflags(f);
	return 0;

    case 0x56:
	f->e.eax = __rename((const char *)f->e.edx, (const char *)f->e.edi);
	if (f->e.eax < 0)
	    set_errno_eax_eflags(f);
	return 0;

    case 0x57:
	/* Get/set time/data of file. */
	break;

    default:
	/* bad_func */
	break;
    }

    if (rAH) {
	static char msg[] = "DOS call AH = 0x__";  /* 16/17 */

	msg[16] = rAH >> 4;
	if (msg[16] > 9)
	    msg[16] += ('A' - 10);
	else
	    msg[16] += '0';

	msg[17] = rAH & 0xf;
	if (msg[17] > 9)
	    msg[17] += ('A' - 10);
	else
	    msg[17] += '0';

	MessageBox(NULL, msg, "RSXNT: Unsupported Syscall",
		   MB_OK|MB_ICONERROR|MB_APPLMODAL|MB_SETFOREGROUND);
    }

    f->e.eax = -1;
    f->e.ecx = -1;
    f->e.eflags |= 1;
    return 1;

}
