/*
OKAY.C -- basic test for validity of undocumented DOS

cl -DTESTING -qc okay.c
okay
*/

#include <stdlib.h>
#include <stdio.h>

#ifdef __TURBOC__
#define ASM asm
#pragma inline
#elif defined(_MSC_VER) && (_MSC_VER >= 600)
#define ASM _asm
#else
#error Requires inline assembler
#endif      

typedef enum { FALSE, TRUE } BOOL;

BOOL netware(void);
unsigned lastdrv_netware(void);

BOOL undoc_dos_okay(void)
{
    char far *doslist;
    unsigned lastdrv_doc;
    unsigned drive;

    /* get offset for LASTDRIVE within DOS List of Lists */
    unsigned lastdrv_ofs = 0x21;
    if (_osmajor==2) lastdrv_ofs = 0x10;
    else if ((_osmajor==3) && (_osmajor==0)) lastdrv_ofs = 0x1b;

    /* Get DOS Lists of Lists */
    ASM mov ah, 52h
    ASM xor bx, bx
    ASM mov es, bx
    ASM int 21h
    ASM mov doslist, bx
    ASM mov doslist+2, es

    if (! doslist) 
        return FALSE;

    /* use documented DOS to verify results */
#ifdef __TURBOC__
    lastdrv_doc = setdisk(getdisk());
#else
    _dos_getdrive(&drive);
    _dos_setdrive(drive, &lastdrv_doc);
#endif
    if (doslist[lastdrv_ofs] == lastdrv_doc)
        return TRUE;
    else if (netware())
    {
		puts("Novell NetWare");
        if (lastdrv_doc != 32)
            puts("NetWare Function 0Eh looks strange");
        return (doslist[lastdrv_ofs] == lastdrv_netware());
    }

    return FALSE;
}

/*
    Novell Return Shell Version function (INT 21h AH=EAh AL=01h)
    see "Interrupt List" on accompanying disk; also see Barry
    Nance, Networking Programming in C, pp. 117, 341-2. Could also
	test for presence of Novell IPX with INT 2Fh AX=7A00h.
*/
BOOL netware(void)
{
    char buf[40];
    char far *fp = buf;
    ASM push di
    ASM mov ax, 0EA01h
    ASM mov bx, 0
    ASM les di, fp
    ASM int 21h
    ASM xor al, al
    ASM mov ax, bx
    /* if BX still 0, then NetWare not present; return in AX */
    ASM pop di
}

/*
    Novell Get Number of Local Drives function (INT 21h AH=DBh)
    see "Interrupt List" on accompanying disk
*/
unsigned lastdrv_netware(void)
{
    ASM mov ah, 0DBh
    ASM int 21h
    /* AL now holds number of "local drives" (i.e., LASTDRIVE) */
    ASM xor ah, ah
    /* unsigned returned in AX */
}

#ifdef TESTING
main()
{
	fputs("Undocumented DOS ", stdout);
	puts( undoc_dos_okay() ? "ok" : "not ok");
}
#endif
