/*
   CyberRax Programming (C) 2003
   TITLE:   DOS2.H--
   DESCRIPTION:   Additional DOS routines
   LAST MODIFIED:   12 Jun 2003
   PROCEDURES DEFINED IN THIS FILE:
       void RESETDISK()
       void INDOSFLAGADDR()
       byte INDOSFLAG()
       word INDOSFLAGWORD()
       byte GETSWITCHCHAR()
       byet SETSWITCHCHAR(byte new_char)
       byte SETALLOCSTRATEGY(strategy)
       byte ALLOCFIRSTFITHIGH()
       byte ALLOCBESTFITHIGH()
       byte ALLOCLASTFITHIGH()
       byte ALLOCFIRSTFITHIGHLOW()
       byte ALLOCBESTFITHIGHLOW()
       byte ALLOCLASTFITHIGHLOW()
       byte GETUMBLINKSTATE()
       byte SETUMBLINKSTATE(state)
       byte ENABLEUMBLINK()
       byte DISABLEUMBLINK()
       void FINDPATH()
   STRUCTURES DEFINIED IN THIS FILE:
       <none>
   DEFINITIONS AFFECTING THIS CODE:
      KeepInsert1 - don't undefine Insert1
      KeepInsert2 - don't undefine Insert2
      Insert1     - insert SETUMBLINKSTATE() in [EN/DIS]ABLEUMBLINK(),
		      SETALLOCSTRATEGY() in ALLOCxxx(), INDOSFLAGADDR()
		      in INDOSFLAG[WORD]() instead of calling
      Insert2     - insert GETDOSVERSION() in INDOSFLAGWORD() instead of
		      calling
		    These definitions are for hand-optimizing the code for
		      speed/size in case the mentioned procedures aren't
		      called by themselves. InsertX is undefinied by all
                      procedures which support it if the appropriate
		      KeepInsertX is not definied.

   NOTE:   this header file uses features of SPHINX/Sheker C-- and needs
	   quite some modifications to work under original SPHINX C-- 0.203
*/


? ifndef _DOS2_
? define _DOS2_		TRUE


? ifndef _NUMBERS_
  ? include "NUMBERS.H--"
? endif

? ifndef _JSTUFF_
  ? include "JSTUFF.H--"
? endif


? warning		TRUE


? define WAS_ERROR	-1

? define UMBS_UNLINKED	NULL
? define UMBS_LINKED	ONE


enum { LOWFIRST, LOWBEST, LOWLAST,
       HIGHFIRST = FOURTY_H, HIGHBEST, HIGHLAST,
       HIGHLOWFIRST = EIGHTY_H, HIGHLOWBEST, HIGHLOWLAST };



inline void FINDPATH ()
/* Determines program's path, this means the coplete commandline like
     C:\..\FILE.EXT, INCLUDING the filename and extension. Analog to
     STARTPATH() in SYSTEM.H-- and ?argc directive.
   Input: nothing
   Size: 21 bytes
*/
{
? DOSrequired 0x0300
        SI = NULL;
	CX = 0x8001;
	DS = DSWORD[0x2C];
	loop(CX){
		$LODSW
                IF(AX==ONE)GOTO MACRO_END;
		SI--;
	}
	SI = NULL;
MACRO_END:
}
/* Returns:  CX = destroyed
	     Pathname in DS:SI if success
	     DS = ***DESTROYED*** (!!!), SI = 0 if error occoured
*/



inline void RESETDISK ()
/* Writes all modified disk buffers to disk
   Input: nothing
   Uses: 0 - 2 bytes of stack
   Size: 4 bytes
*/
{
AH = 0xD;
$INT 0x21
}
/* Returns: nothing
	    AH destroyed
*/



inline byte GETUMBLINKSTATE ()
/* Returns the current UMB link state
   Input: nothing
   Uses: 0 - 2 bytes of stack
   Size: min. 9 bytes
*/
{
? DOSrequired 0x0500

AX = 0x5802;
$INT 0x21
IF (CARRYFLAG)
   AL = WAS_ERROR;
}
/* Returns: AL = UMBS_UNLINKED (0) if UMBs not linked into DOS memory chain
	    AL = UMBS_LINKED (1) if UMBs linked in
	    AL = WAS_ERROR (0xFF) if error accoured
*/



inline byte SETUMBLINKSTATE (BX)
/* (Un)Links UMBs from DOS memory chain
   Input: BX = new UMB link state =>  UMBS_UNLINKED (0) - UMBs unlinked
					UMBS_LINKED (1) - UMBs linked
   Uses: 0 - 2 bytes of stack
   Size: min. 11 bytes
*/
{
? DOSrequired 0x0500

AX = 0x5803;
BH = NULL;
$INT 0x21
IF (NOTCARRYFLAG)
   AL = OK;
}
/* Returns: AL = OK (0) if link state successfully changed
	    AL <> 0 if error accoured
	    BX destroyed
*/



inline byte ENABLEUMBLINK ()
/* Links UMBs into DOS memory chain so memory could be allocated in high
     memory area (above 640kB)
   Note: UMB link state should be saved before using this call and restored
	   before terminating the program
	 UMB's will be available only if CONFIG.SYS contain's DOS=UMB and
	   DOS memory allocation strategy is changed to include high memory.
   Input: nothing
          'Insert1' defined to insert SETUMBLINKSTATE() instead of calling
   Uses: SETUMBLINKSTATE() from DOS2.H--
         0 - 2 bytes of stack
   Size: ca. 11 bytes
*/
{
? ifdef Insert1
   @
? endif
SETUMBLINKSTATE(UMBS_LINKED);
@UNDEFINEINSERT1();
}
/* Returns: AL = OK (0) if UMBs linked
	    AL <> 0 if error accoured
	    BX destroyed
*/



inline byte DISABLEUMBLINK ()
/* Unlinks UMBs from DOS memory chain.
   Note: UMB link state should be saved before and restored after using
	   this call
	 UMB's will be available only if CONFIG.SYS cointain's DOS=UMB and
           DOS memory allocation strategy has been changed to include high
           memory.
   Input: nothing
          'Insert1' defined to insert SETUMBLINKSTATE() instead of calling
   Uses: SETUMBLINKSTATE() from DOS2.H--
         0 - 2 bytes of stack
   Size: ca. 11 bytes
*/
{
? ifdef Insert1
   @
? endif
SETUMBLINKSTATE(UMBS_UNLINKED);
@UNDEFINEINSERT1();
}
/* Returns: AL = OK (0) if UMBs linked
	    AL <> 0 if error accoured
	    BX destroyed
*/



inline byte SETALLOCSTRATEGY (BX)
/* Sets DOS's memory allocation strategy.
   Alternative to using ALLOC*()
   Note: allocation strategies including high memory (*HIGH*()) need DOS 5.0 +
	   UMB provider (a'la EMM386 or UMBPCI) + 'DOS=UMB' in CONFIG.SYS
   Input: BX = new strategy
   Size: 11 bytes
*/
{
? DOSrequired 0x020B			// According to RBIL

AX = 0x5801;
BH = NULL;
$INT 0x21
IF (NOTCARRYFLAG)
   AL = OK;
}
/* Returns: AL = OK (0) if strategy set to the new one
	    AL <> 0 if error accoured
	    BX destroyed
*/



inline byte ALLOCFIRSTFITHIGH ()
/* Sets DOS's memory allocation strategy to "high memory first fit"
   Input: nothing
          'Insert1' defined to insert SETALLOCATIONSTRATEGY() instead
            of calling
   Uses: SETALLOCATSTRATEGY() from DOS2.H--
         0 - 2 bytes of stack
   Size: ca. 11 bytes
*/
{
? DOSrequired 0x0500

? ifdef Insert1
   @
? endif
SETALLOCSTRATEGY(HIGHFIRST);
@UNDEFINEINSERT1();
}
/* Returns: AL = OK (0) if strategy set to the new one
	    AL <> 0 if error accoured
	    BX destroyed
*/



inline byte ALLOCBESTFITHIGH ()
/* Sets DOS's memory allocation strategy to "high memory best fit"
   Input: nothing
          'Insert1' defined to insert SETALLOCATIONSTRATEGY() instead
            of calling
   Uses: SETALLOCATSTRATEGY() from DOS2.H--
         0 - 2 bytes of stack
   Size: ca. 11 bytes
*/
{
? DOSrequired 0x0500

? ifdef Insert1
   @
? endif
SETALLOCSTRATEGY(HIGHBEST);
@UNDEFINEINSERT1();
}
/* Returns: AL = OK (0) if strategy set to the new one
	    AL <> 0 if error accoured
	    BX destroyed
*/



inline byte ALLOCLASTFITHIGH ()
/* Sets DOS's memory allocation strategy to "high memory last fit"
   Input: nothing
          'Insert1' defined to insert SETALLOCATIONSTRATEGY() instead
	    of calling
   Uses: SETALLOCATSTRATEGY() from DOS2.H--
         0 - 2 bytes of stack
   Size: ca. 11 bytes
*/
{
? DOSrequired 0x0500

? ifdef Insert1
   @
? endif
SETALLOCSTRATEGY(HIGHLAST);
@UNDEFINEINSERT1();
}
/* Returns: AL = OK (0) if strategy set to the new one
	    AL <> 0 if error accoured
	    BX destroyed
*/



inline byte ALLOCFIRSTFITHIGHLOW ()
/* Sets DOS's memory allocation strategy to "first fit, try high then low mem"
   Input: nothing
          'Insert1' defined to insert SETALLOCATIONSTRATEGY() instead
            of calling
   Uses: SETALLOCATSTRATEGY() from DOS2.H--
         0 - 2 bytes of stack
   Size: ca. 11 bytes
*/
{
? DOSrequired 0x0500

? ifdef Insert1
   @
? endif
SETALLOCSTRATEGY(HIGHLOWFIRST);
@UNDEFINEINSERT1();
}
/* Returns: AL = OK (0) if strategy set to the new one
	    AL <> 0 if error accoured
	    BX destroyed
*/



inline byte ALLOCBESTFITHIGHLOW ()
/* Sets DOS's memory allocation strategy to "best fit, try high then low mem"
   Input: nothing
          'Insert1' defined to insert SETALLOCATIONSTRATEGY() instead
            of calling
   Uses: SETALLOCATSTRATEGY() from DOS2.H--
         0 - 2 bytes of stack
   Size: ca. 11 bytes
*/
{
? DOSrequired 0x0500

? ifdef Insert1
   @
? endif
SETALLOCSTRATEGY(HIGHLOWBEST);
@UNDEFINEINSERT1();
}
/* Returns: AL = OK (0) if strategy set to the new one
	    AL <> 0 if error accoured
	    BX destroyed
*/



inline byte ALLOCLASTFITHIGHLOW ()
/* Sets DOS's memory allocation strategy to "last fit, try high then low mem"
   Input: nothing
          'Insert1' defined to insert SETALLOCATIONSTRATEGY() instead
            of calling
   Uses: SETALLOCATSTRATEGY() from DOS2.H--
         0 - 2 bytes of stack
   Size: ca. 11 bytes
*/
{
? DOSrequired 0x0500

? ifdef Insert1
   @
? endif
SETALLOCSTRATEGY(HIGHLOWLAST);
@UNDEFINEINSERT1();
}
/* Returns: AL = OK (0) if strategy set to the new one
	    AL <> 0 if error accoured
	    BX destroyed
*/



inline void INDOSFLAGADDR ()
/* Retrieves the address InDOS flag, which signals whether or not it's safe
     to use DOS functions (used by TSRs)
   Input: nothing
   Note: not only the InDOS flag should be checked but also the critical error
	 flag, which is the byte *following* the InDOS flag in DOS 2.x (ie at
	 ES:BX+1) while it's preceeding in DOS 3.0+ (ie at ES:BX-1)
   Uses: 0 - 2 bytes of stack
   Size: min. 4 bytes
*/
{
? DOSrequired 0x0200

AH = 0x34;
$INT 0x21
}
/* Returns: ES:BX = address of InDOS flag
*/



inline byte INDOSFLAG ()
/* Retrieves the InDOS flag
   Note: not only the InDOS flag should be checked but also the critical error
	 flag, which is the byte *following* the InDOS flag in DOS 2.x (ie at
	 ES:BX+1) while it's preceeding in DOS 3.0+ (ie at ES:BX-1)
   Input: nothing
	 'Insert1' definied to insert INDOSFLAGADDR() instead of calling
   Uses: INDOSFLAGADDR() from DOS2.H--
	 0 - 4 bytes of stack
   Size: min. 7 bytes
*/
{
? ifdef Insert1
  @
? endif
INDOSFLAGADDR();

AL = ESBYTE[BX];
@UNDEFINEINSERT1();
}
/* Returns: AL = InDOS flag
	    BX, ES destroyed
*/



inline word INDOSFLAGWORD ()
/* Retrieves the InDOS and CriticalError flags
   Input: nothing
	 'Insert1' definied to insert INDOSFLAGADDR() instead of calling
	 'Insert2' definied to insert GETDOSVERSION() instead of calling
   Uses: INDOSFLAGADDR() from DOS2.H--
	 GETDOSVERSION() from internal library
	 2 - 4 bytes of stack
   Size: min. 26 bytes
*/
{
? ifdef Insert1
  @
? endif
INDOSFLAGADDR();
$PUSH BX

? ifdef Insert2
  @
? endif
GETDOSVERSION();

$POP BX
IF (AL > TWO)
   BX--;

BX = ESWORD[BX];
IF (AL > TWO)
   BH >< BL;

? ifdef codesize
  AX >< BX;
? else
  AX = BX;
? endif

@UNDEFINEINSERT1();
@UNDEFINEINSERT2();
}
/* Returns: AH = InDOS flag
	    AL = CriticalError flag
	    BX, ES destroyed
*/



inline byte GETSWITCHCHAR ()
/* Retrieves the character used to start switches on commandline
   Input: nothing
   Size: min. 5 bytes
*/
{
? DOSrequired 0x0200

AX = 0x3700;
$INT 0x21
}
/* Returns: AL = 0 if function supported
	      DL = switch character
	    AL = 0xFF if function not supported
*/



inline byte SETSWITCHCHAR (DL)
/* Sets the character which is used to start switches on commandline
   Ignored by MS-DOS 5+ and DR-DOS 3.41 - 6.0
   Input: DL = new character
   Size: min. 5 bytes
*/
{
? DOSrequired 0x0200

AX = 0x3701;
$INT 0x21
}
/* Returns: AL = 0 if successful
	    AL = 0xFF if function not supported
	    DX destroyed

      NOTE: DR-DOS 6.0 and Novell DOS 7 leave AX unchanged
*/


? endif


/* end of DOS2.H-- */
