#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <process.h>
#include "..\DPMI.H"
#include "..\DPMI10.H"

char file_desc[] =
"**************************************************************************\n"
"* FILE: dpmifun                                                          *\n"
"*                                                                        *\n"
"* DESC: shell for calling Dpmi functions                                 *\n"
"*                                                                        *\n"
"* Copyright (C) 1994                                                     *\n"
"*      Rainer Schnitker, Heeper Str. 283, 33607 Bielefeld                *\n"
"*      email: rainer@mathematik.uni-bielefeld.de                         *\n"
"*                                                                        *\n"
"* This program is distributed in the hope that it will be useful,        *\n"
"* but WITHOUT ANY WARRANTY; without even the implied warranty of         *\n"
"* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *\n"
"* GNU General Public License for more details.                           *\n"
"*                                                                        *\n"
"**************************************************************************\n";

/* input function from input.c */
int get_input(char *str, int size, int opt_newline);

typedef struct dpmifnct {
    char *name;
    int fnct;
    int args;
    char *help_text;
} DPMIFNCT;

DPMIFNCT dpmif[] = {
    #include "dpmifun.h"
};

#define N_REGS 10   /* we could use regs 0 - regs 9 */
int regs[128];	    /* so we have 512 bytes for functions */

/*
**  Test DPMI server
*/
#ifdef __EMX__
static int test_dpmi_server(void)
{
    return ((_emx_env & 0x80) | (_emx_env & 0x100));
}
#endif

#ifdef __GO32__
#include <go32.h>
extern Go32_Info_Block _go32_info_block;

static int test_dpmi_server(void)
{
    return _go32_info_block.run_mode & _GO32_RUN_MODE_DPMI;
}
#endif


void PrintDescriptor(LPDESCRIPTOR d)
{
    BYTE flag;

    if (!(d->access & PRESENT_BIT)) {
	printf("Not Present\n");
	return;
    }
    if (d->access & SEGMENT_BIT)/* code or data selector */
	printf("Base=%02X%02X%04X Limit=%01X%04X %s DPL=%u %s %s %s %s\n",
	       d->base_hi, d->base_mi, d->base_lo,
	       d->lim_hi & LIMIT_HI_MASK, d->lim_lo,
	       (d->lim_hi & GRANULAR_BIT) ? "Pages" : "Bytes",
	       (d->access & DPL_MASK) >> 5,
	       (d->lim_hi & DEFAULT_BIT) ? "32bit" : "16bit",
	       (d->access & CODE_BIT) ?
	       (d->access & CONFIRMING_BIT) ? "CONF" : "CODE" :
	       (d->access & EXPAND_BIT) ? "EXPD" : "DATA",
	       (d->access & WRITE_BIT) ?
	       (d->access & CODE_BIT) ? "R" : "W" : "-",
	       (d->access & ACCESS_BIT) ? "ACC" : " ");

    else {			/* system selector */
	flag = d->access & (BYTE) 7;
	switch (flag) {
	case 0:
	    break;
	case 1:
	    printf("TSS%s ", (d->access & 8) ? "386" : "286");
	    break;
	case 2:
	    printf("LDT ");
	    break;
	case 3:
	    printf("BUSYTSS%s ", (d->access & 8) ? "386" : "286");
	    break;
	case 4:
	    printf("CALLGATE%s ", (d->access & 8) ? "386" : "286");
	    break;
	case 5:
	    printf("TASKGATE ");
	    break;
	case 6:
	    printf("INT_GATE%s ", (d->access & 8) ? "386" : "286");
	    break;
	case 7:
	    printf("TRAPGATE%s ", (d->access & 8) ? "386" : "286");
	    break;
	}


	if (flag <= 3) {
	    printf("Base=%02X%02X%04X Limit=%01X%04X DPL=%u\n",
		   d->base_hi, d->base_mi, d->base_lo,
		   d->lim_hi & LIMIT_HI_MASK, d->lim_lo,
		   (d->access & DPL_MASK) >> 5);
	} else {
	    printf("Sel=%04X Offset=%02X%02X%04X DPL=%u\n",
		   d->base_lo,
		   d->base_hi, d->lim_hi, d->lim_lo,
		   (d->access & DPL_MASK) >> 5);
	}
    }				/* else system descriptor */
}

void do_help(char *s)
{
    int i;
    for (i = 0; dpmif[i].name ; i++)
	if (stricmp(dpmif[i].name, s) == 0) {
	    puts(dpmif[i].help_text);
	    return;
	}
    for (i = 0; dpmif[i].name ; i++)
	if (strstr(dpmif[i].name, s))
	    puts(dpmif[i].help_text);
}

static int make_tokens(char *argmem, char **argp)
{
    int i;
    int args=0;

    argp[args++] = argmem;
    for (i = 0; *(argmem + i) != 0; i++)
	if (*(argmem + i) == ' ') {
	    *(argmem + i) = 0;
	    if (*(argmem + i + 1) == ' ')
		continue;
	    if (*(argmem + i + 1) == 0)
		break;
	    argp[args++] = (argmem + i + 1);
	}
    argp[args] = 0;

    return args;
}

static int get_function(char *s, int *argc)
{
    int i;

    for (i = 0; dpmif[i].name ; i++)
	if (strcmp(dpmif[i].name, s) == 0) {
	    *argc = dpmif[i].args;
	    return (int) dpmif[i].fnct;
	}
    return 0;
}

static int my_atoi(char *s)
{
    int c;
    if ( (*s) < '0' || (*s) > '9')
	return -1;
    return ((c=atoi(s)) >= N_REGS) ? -1 : c;
}

static int hex_atoi(char *s)
{
    int c;
    if ( (*s) < '0' || (*s) > '9')
	return 0;
    if (*(s+1)=='x')
	sscanf(s+2,"%x\n", &c);
    else
	sscanf(s,"%d\n", &c);
    return c;
}

static int push_args(int begin, int end, char **argv, int pushv[])
{
    int i;

    for (i = begin; i <= end; i++) {
	if (argv[i][0] == 'r') {
	    int n = my_atoi(& argv[i][1]);
	    if (n<0)
		return n;
	    pushv[i] = regs[n];
	}
	else if (argv[i][0] == '&' && argv[i][1] == 'r') {
	    int n = my_atoi(& argv[i][2]);
	    if (n<0)
		return n;
	    pushv[i] = (int) & regs[n];
	}
	else
	    pushv[i] = hex_atoi(argv[i]);
    }
    return 0;
}

int execute_dpmi(int fnct, int p1, int p2, int p3, int p4, int p5);

int main(int argc, char **argv, char **env)
{
    char cmd[80];	    /* cmd line */
    char * argvec[20];	    /* cmd tokens */
    int push[20];	    /* pushed args for dpmi */
    unsigned fnct;	    /* dpmi function */
    int n,p,ret;

    puts(file_desc);
    puts("help command: help or h\n");

    if (!test_dpmi_server()) {
	puts("I need dpmi, run this program with a dpmiextender\n");
	puts("EMX: run rsx ; DJGPP run go32 not with 'nodpmi'\n");
	return 1;
    }

    for (;;) {
	printf("(DPMI):");
	fflush(stdout);
	get_input(cmd, sizeof(cmd), 1);
	n = make_tokens(cmd, argvec);

	switch (*cmd) {
	    case '0':
	    case 'q':
		printf("bye\n");
		return 0;

	    case '\n':
	    case '\r':
		continue;

	    case 'h':
		if (argvec[1])
		    do_help(argvec[1]);
		else {
		    printf("\n"
			"(h)elp <function> - get help\n"
			"c[0-9]            - clear regs 0-9\n"
			"r[0-9]            - print regs 0-9\n"
			"s[0-9] <value>    - set regs 0-9 to v\n"
			"DPMIFUNCTION args - execute dpmifuncion\n"
			"! <args>          - execute shell\n"
			"(q)uit            - quit\n"
			"Arrow keys <up>,<down>,<left>,<right>\n"
			);

		    printf("\nExample:\n"
			"dpmi:help DpmiGet                 // list all functions with DpmiGet\n"
			"int  DpmiGetCoproStatus (UNIT *)  // answer\n"
			"dpmi:DpmiGetCoproStatus &r1       // call DPMI function with address r1\n"
			"return 0 = 0x0                    // no error\n"
			"dpmi:r1                           // display register 1\n"
			"dpmi:GetDescriptor 0xf7 &r1       // use r1-r4 as a buffer\n"
			"return 0 = 0x0                    // buffer can use 512 bytes */\n"
			"dpmi:PrintDescriptor &r1\n"
			"Base=80003000 Limit=22FFF Bytes DPL=3 32bit CODE R ACC\n"
			);
		}
		continue;

	    case 'c':
		n = my_atoi(& argvec[0][1]);
		if (n < 0)
		    puts("What?");
		else
		    regs[n] = 0;
		continue;

	    case 'r':
		n = my_atoi(& argvec[0][1]);
		if (n < 0)
		    puts("What?");
		else
		    printf("Reg%d: %d = 0x%X\n", n, regs[n], regs[n]);
		continue;

	    case 's':
		n = my_atoi(& argvec[0][1]);
		if (n < 0)
		    puts("What?");
		else {
		    p = hex_atoi(argvec[1]);
		    regs[n] = p;
		    printf("Reg%d: %d = 0x%X\n", n, regs[n], regs[n]);
		}
		continue;

	    case '!':
		if (argvec[1] == NULL)
		    system("");
		else if (spawnvpe(P_WAIT, argvec[1], & argvec[1], env)==-1)
		    perror("shell program:");
		continue;

	    default:
		fnct = get_function(argvec[0], &p);
		if (!fnct) {
		    printf("not a dpmi function\n");
		    continue;
		}
		if (n-1 != p) {
		    printf("Illegal argument count\n");
		    continue;
		}
		push[0] = fnct;
		if (push_args(1, n-1, argvec, push)<0) {
		    printf("bad parameter\n");
		    continue;
		}
		ret=execute_dpmi(push[0],push[1],push[2],push[3],push[4],push[5]);
		printf("return %d = 0x%X\n", ret, ret);
		regs[0] = ret;	/* r0 = return register */
	}   /* switch */
    }
}
