#include    <stdio.h>
#include    <dos.h>

#define	ERR	(-1)
#define	FALSE	0
#define	TRUE	1

#define	LIN_SIZ	80
#define	SCR_SIZ	24

static	struct CONS_TBL {
	    char	cur_type;
	    short	cur_line;
	    char	cur_disp;
	    short	cur_pont;
	    char	def_attr[4];
	    char	vram_code[SCR_SIZ][LIN_SIZ];
	    long	vram_attr[SCR_SIZ][LIN_SIZ];
	} console;

	char	*stralloc(char *str);

void	Console_Save()
{
    union REGS regs;
    struct SREGS seg;
    union {
	char far *p;
	short	 s[2];
    } pp;
    struct {
	char far *code;
	long far *attr;
    } tbl;

    regs.h.ah = 0x0A;
    int86(0x91,&regs,&regs);
    console.cur_type = regs.h.al;
    console.cur_line = regs.x.dx;

    regs.h.ah = 0x0C;
    int86(0x91,&regs,&regs);
    console.cur_disp = regs.h.al;

    regs.h.ah = 0x0E;
    int86(0x91,&regs,&regs);
    console.cur_pont = regs.x.dx;

    pp.p = (char far *)(console.def_attr);
    regs.h.ah = 0x12;
    regs.x.di = pp.s[0];
    seg.ds    = pp.s[1];
    int86x(0x91,&regs,&regs,&seg);

    tbl.code = (char far *)(console.vram_code);
    tbl.attr = (long far *)(console.vram_attr);
    pp.p = (char far *)(&tbl);
    regs.h.ah = 0x16;
    regs.h.al = 1;
    regs.h.dh = 1;
    regs.h.dl = 1;
    regs.h.bh = SCR_SIZ;
    regs.h.bl = LIN_SIZ;
    regs.x.di = pp.s[0];
    seg.ds    = pp.s[1];
    int86x(0x91,&regs,&regs,&seg);
}
void	Console_Load()
{
    union REGS regs;
    struct SREGS seg;
    union {
	char far *p;
	short	 s[2];
    } pp;
    struct {
	char far *code;
	long far *attr;
    } tbl;

    regs.h.ah = 0x09;
    regs.h.al = console.cur_type;
    regs.x.dx = console.cur_line;
    int86(0x91,&regs,&regs);

    regs.h.ah = 0x0B;
    regs.h.al = console.cur_disp;
    int86(0x91,&regs,&regs);

    regs.h.ah = 0x0D;
    regs.x.dx = console.cur_pont;
    int86(0x91,&regs,&regs);

    pp.p = (char far *)(console.def_attr);
    regs.h.ah = 0x11;
    regs.x.di = pp.s[0];
    seg.ds    = pp.s[1];
    int86x(0x91,&regs,&regs,&seg);

    tbl.code = (char far *)(console.vram_code);
    tbl.attr = (long far *)(console.vram_attr);
    pp.p = (char far *)(&tbl);
    regs.h.ah = 0x15;
    regs.h.al = 1;
    regs.h.dh = 1;
    regs.h.dl = 1;
    regs.h.bh = SCR_SIZ;
    regs.h.bl = LIN_SIZ;
    regs.x.di = pp.s[0];
    seg.ds    = pp.s[1];
    int86x(0x91,&regs,&regs,&seg);
}

#define	DEV_LOCAL	0x00
#define	DEV_NET		0x10
#define	DEV_FDD		0x20
#define	DEV_EXTFDD	0x30
#define	DEV_HDD		0x40
#define	DEV_MO		0x50
#define	DEV_RAM		0x60
#define	DEV_CD		0x70

static	unsigned char	drv_unit[26] = {
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF };
static	char	*drv_name[] = {
	"Local Disk",
	"NetWork Device",
	"Flopy Disk      %d",
	"Ext Flopy Disk  %d",
	"Hard Disk Drive %d",
	"MO Disk Drive   %d",
	"RAM Disk",
	"Compact Disc ROM",
	NULL
    };
static	char	*drv_vct[27];

void	DSKINIT()
{
    int n, i;
    union REGS regs;
    struct SREGS seg;
    union {
	char far *p;
	short	 s[2];
    } pp;
    unsigned char tmp[200];

    pp.p = (char far *)(&tmp);
    regs.h.ah = 0x00;
    regs.x.di = pp.s[0];
    seg.ds    = pp.s[1];
    int86x(0x8E, &regs, &regs, &seg);

    if ( regs.h.ah == 0 ) {
	for ( n = 0 ; n < 16 ; n++ ) {
	    switch(tmp[0x30 + n * 2]) {
	    case 0x00:	/* FDD */
		drv_unit[n] = DEV_FDD | tmp[0x31 + n * 2];
		break;
	    case 0x01:	/* ExtFDD */
		drv_unit[n] = DEV_EXTFDD | tmp[0x31 + n * 2];
		break;
	    case 0x02:	/* SCSI */
		regs.x.ax = 0x4408;
		regs.h.bl = n + 1;
		intdos(&regs, &regs);
		if ( regs.x.cflag == 0 && regs.x.ax == 0 )
		    drv_unit[n] = DEV_MO | tmp[0x31 + n * 2] >> 4;
		else
		    drv_unit[n] = DEV_HDD | tmp[0x31 + n * 2] >> 4;
		break;
	    case 0x03:	/* RAM */
		drv_unit[n] = DEV_RAM;
		break;
	    case 0x04:	/* MDC */
		drv_unit[n] = DEV_HDD;
		break;
	    case 0xFF:	/* no dev */
		drv_unit[n] = 0xFF;
		break;
	    default:	/* local dev */
		drv_unit[n] = 0x00;
		break;
	    }
	}
    }

    for ( n = 0 ; n < 26 ; n++ ) {
	if ( drv_unit[n] != 0xFF )
	    continue;
	regs.x.ax = 0x4409;
	regs.h.bl = n + 1;
	intdos(&regs, &regs);
	if ( regs.x.cflag == 0 ) {
	    if ( (regs.x.dx & 0x1000) != 0 )
		drv_unit[n] = DEV_NET;
	    else
		drv_unit[n] = DEV_LOCAL;
	}
    }

    for ( n = i = 0 ; n < 26 ; n++ ) {
	if ( drv_unit[n] != 0xFF ) {
	    sprintf(tmp, "%c: ", n + 'A');
	    sprintf(tmp + 3, drv_name[drv_unit[n] >> 4], drv_unit[n] & 0x0F);
	    drv_vct[i++] = stralloc(tmp);
	}
    }
    drv_vct[i] = NULL;
}
int	drv_menu(int x, int y, int drv)	/* A=1, B=2 ... */
{
    int n, no = 0;

    for ( n = 0 ; drv_vct[n] != NULL ; n++ ) {
	if ( (drv + 'A' - 1) == drv_vct[n][0] ) {
	    no = n;
	    break;
	}
    }

    if ( (n = menu(x, y, no, drv_vct)) < 0 )
	return drv;

    return (drv_vct[n][0] - 'A' + 1);
}
