' Uses 1 fixed length string and 1 fixed length structure to calculate FAT32
' free/total disk space beyond 2 GB.

' Interesting idea to pass a fixed length string structure to Int86 function.

' btw: AH/AL register pairs are reversed,
'  so mid$(values,1,1)=al and mid$(values,2,1)=ah

' the original structure.
'Type RegTypeX
' AX AS Integer ' 1-2
' BX AS Integer ' 3-4
' CX AS Integer ' 5-6
' DX AS Integer ' 7-8
' BP AS Integer ' 9-10
' SI AS Integer ' 11-12
' DI AS Integer ' 13-14
' Flags AS Integer ' 15-16
' DS AS Integer ' 17-18
' ES AS Integer ' 19-20
'End Type

' the replacement structure.
TYPE RegsX
 Values AS STRING * 20
END TYPE

DIM FAT32Struc AS STRING * 44, ASCIIZ AS STRING * 4

DECLARE SUB InterruptX (N AS INTEGER, I AS RegsX, O AS RegsX)

DIM InregsX AS RegsX, OutregsX AS RegsX

'--------D-2136-------------------------------
'INT 21 - DOS 2+ - GET FREE DISK SPACE
'        AH = 36h
'        DL = drive number (00h = default, 01h = A:, etc)
'Return: AX = FFFFh if invalid drive

IF Command$ <> "" THEN
   D$ = LEFT$(Command$, 1)
ELSE
   LINE INPUT "Disk drive letter? ", D$
   D$ = UCASE$(D$)
END IF

' check control break
DEF SEG = &H40
IF PEEK(&H71) THEN
   Flag = -1
END IF
POKE &H71, &H0
DEF SEG
IF Flag THEN
   END
END IF

' check drive
MID$(InregsX.Values, 1, 1) = CHR$(0)' AL
MID$(InregsX.Values, 2, 1) = CHR$(&H36)' AH
MID$(InregsX.Values, 7, 1) = CHR$(ASC(D$) - 64)' DL

CALL InterruptX(&H21, InregsX, OutregsX)

AX = ASC(MID$(OutregsX.Values, 1, 1)) + ASC(MID$(OutregsX.Values, 2, 1)) * 256
IF AX = &HFFFF THEN
   PRINT "Invalid drive.": END
END IF

'INT 21 - Windows95 - FAT32 - GET EXTENDED FREE SPACE ON DRIVE
'        AX = 7303h
'        DS:DX -> ASCIIZ string for drive ("C:\" or "\\SERVER\Share")
'        ES:DI -> buffer for extended free space structure (see #01789)
'        CX = length of buffer for extended free space

ASCIIZ = D$ + ":\" + CHR$(0)
MID$(InregsX.Values, 2, 1) = CHR$(&H73)' AH
MID$(InregsX.Values, 1, 1) = CHR$(&H3)' AL

' assign the fixed length string structure
Address! = VARSEG(ASCIIZ)
Address.High% = (Address! AND &HFF00) / &HFF
Address.Low% = Address! AND &HFF
MID$(InregsX.Values, 18, 1) = CHR$(Address.High%)' DS high
MID$(InregsX.Values, 17, 1) = CHR$(Address.Low%)' DS low

Address! = VARPTR(ASCIIZ)
Address.High% = (Address! AND &HFF00) / &HFF
Address.Low% = Address! AND &HFF
MID$(InregsX.Values, 8, 1) = CHR$(Address.High%)' DX high
MID$(InregsX.Values, 7, 1) = CHR$(Address.Low%)' DX low

Address! = VARSEG(FAT32Struc)
Address.High% = (Address! AND &HFF00) / &HFF
Address.Low% = Address! AND &HFF
MID$(InregsX.Values, 20, 1) = CHR$(Address.High%)' ES high
MID$(InregsX.Values, 19, 1) = CHR$(Address.Low%)' ES low

Address! = VARPTR(FAT32Struc)
Address.High% = (Address! AND &HFF00) / &HFF
Address.Low% = Address! AND &HFF
MID$(InregsX.Values, 14, 1) = CHR$(Address.High%)' DI high
MID$(InregsX.Values, 13, 1) = CHR$(Address.Low%)' DI low

MID$(InregsX.Values, 6, 1) = CHR$(0)' CX high
MID$(InregsX.Values, 5, 1) = CHR$(LEN(FAT32Struc))' CX low

CALL InterruptX(&H21, InregsX, OutregsX)

'Return: CF clear if successful
'            ES:DI buffer filled
'        CF set on error
'            AX = error code
'        on DOS versions which do not support the FAT32 calls, this function
'          returns CF clear/AL=00h (which is the DOS v1+ method for reporting
'          unimplemented functions)

AX = ASC(MID$(OutregsX.Values, 1, 1)) + ASC(MID$(OutregsX.Values, 2, 1)) * 256
IF (AX AND &HFF) = 0 THEN
   PRINT "Unsupported call."
   END
END IF

Flags = ASC(MID$(OutregsX.Values, 15, 1)) + ASC(MID$(OutregsX.Values, 16, 1)) * 256
IF (Flags AND &H1) = &H1 THEN ' Flags
   AX = ASC(MID$(OutregsX.Values, 1, 1)) + ASC(MID$(OutregsX.Values, 2, 1)) * 256
   IF AX = 15 THEN
      PRINT "Invalid drive."
   ELSE
      PRINT "Error"; AX
   END IF
   END
END IF

'Format of extended free space structure:
'Offset  Size    Description     (Table 01789)
' 00h    WORD    (ret) size of returned structure
' 02h    WORD    (call) structure version (0000h)
'                (ret) actual structure version (0000h)
' 04h    DWORD   number of sectors per cluster (with adjustment for compression)
' 08h    DWORD   number of bytes per sector
' 0Ch    DWORD   number of available clusters
' 10h    DWORD   total number of clusters on the drive
' 14h    DWORD   number of physical sectors available on the drive, without
'                  adjustment for compression
' 18h    DWORD   total number of physical sectors on the drive, without
'                  adjustment for compression
' 1Ch    DWORD   number of available allocation units, without adjustment
'                  for compression
' 20h    DWORD   total allocation units, without adjustment for compression
' 24h  8 BYTEs   reserved

Bytes# = CLNG(ASC(MID$(FAT32Struc, 9, 1)))
Bytes# = Bytes# + CLNG(ASC(MID$(FAT32Struc, 10, 1))) * 256#
Bytes# = Bytes# + CLNG(ASC(MID$(FAT32Struc, 11, 1))) * 65536#
Bytes# = Bytes# + CLNG(ASC(MID$(FAT32Struc, 12, 1))) * 16777216#
Sectors# = CLNG(ASC(MID$(FAT32Struc, 21, 1)))
Sectors# = Sectors# + CLNG(ASC(MID$(FAT32Struc, 22, 1))) * 256#
Sectors# = Sectors# + CLNG(ASC(MID$(FAT32Struc, 23, 1))) * 65536#
Sectors# = Sectors# + CLNG(ASC(MID$(FAT32Struc, 24, 1))) * 16777216#
FreeSpace# = Bytes# * Sectors#
PRINT "Free Disk Space:"; FreeSpace#
Total# = CLNG(ASC(MID$(FAT32Struc, 25, 1)))
Total# = Total# + CLNG(ASC(MID$(FAT32Struc, 26, 1))) * 256#
Total# = Total# + CLNG(ASC(MID$(FAT32Struc, 27, 1))) * 65536#
Total# = Total# + CLNG(ASC(MID$(FAT32Struc, 28, 1))) * 16777216#
TotalSpace# = Bytes# * Total#
PRINT "Total Disk Space:"; TotalSpace#
END
