'===========================================================================
' Subject: FILE ROUTINES USING INTERRUPTS     Date: 10-29-97 (01:20)       
'  Author: Petter Holmberg                    Code: QB, PDS                
'  Origin: petter.holmberg@usa.net          Packet: INTERRPT.ABC
'===========================================================================
' -------------------------------------------------------------------------- '
' QuickBASIC file routines, ver. 0.9beta                                     '
' By Petter Holmberg, 1997 (petter.holmberg@usa.net)                         '
'                                                                            '
' This program demonstrates file I/O using interrupts. With these routines   '
' you can instantly access up to 65536 bytes from anywhere in files up to 2  '
' gigabytes long, or directly write up to 65536 bytes to such a file with    '
' the speed of BLOAD/BSAVE. These routines will be included in a disk I/O    '
' library that I'll hopefully release for January 1, 1998.                   '
'                                                                            '
' These routines are just a preview of what they will look in the upcoming   '
' disk library. The routines in this program don't check if the drive of     '
' the file to be read from or written to is ready, they don't feature any    '
' checking to see if the file pointer exceeds the file length, they don't    '
' tell you if you have read past the end of the file, and in that case how   '
' much data you recieved and they don't tell you if you have written past    '
' the amount of free disk space aviable.                                     '
' These are just a few of the things not supported yet. However,             '
' these routines are very useful for QuickBASIC programmers since the BLOAD  '
' and BSAVE routines have a 64k file size limit and the file GET and PUT     '
' keywords are based on the length of the variable used.                     '
'                                                                            '
' If you want to experiment with these routines I strongly advise you to do  '
' so on a floppy disk, since I can't guarantee the results of using these    '
' routines in uncommon ways. Please note that I don't take any               '
' responsibility for any damage whatsoever due to the use of this code.      '
' These routines are just beta versions and they haven't been tested for     '
' bugs and errors, the whole code was written in just one evening.           '
'                                                                            '
' Any comments and suggestions can be sent to: petter.holmberg@usa.net       '
' If you use this code in your programs, all I ask for is some credits.      '
' Petter Holmberg                                                            '
'                                                                            '
' -------------------------------------------------------------------------- '

TYPE RegTypeX
  ax    AS INTEGER
  bx    AS INTEGER
  cx    AS INTEGER
  dx    AS INTEGER
  bp    AS INTEGER
  si    AS INTEGER
  di    AS INTEGER
  flags AS INTEGER
  ds    AS INTEGER
  es    AS INTEGER
END TYPE

DIM SHARED inregs AS RegTypeX, outregs AS RegTypeX

DECLARE SUB InterruptX (intnum%, inregs AS RegTypeX, outregs AS RegTypeX)
DECLARE SUB ReadFile (filename$, filepos&, destseg%, destofs%, readlen%, fileerror%)
DECLARE SUB WriteFile (filename$, filepos&, sourceseg%, sourceofs%, writelen%, fileerror%)

' --- Demonstration code:

CLS
INPUT "Input a file name (Make sure it's not already used!!!): ", filename$

' Create and reset file:
OPEN filename$ FOR OUTPUT AS #1: CLOSE #1

teststr$ = "This is a test"

PRINT "Test string: "; teststr$
PRINT "Writing text to file...";

WriteFile filename$, -1, VARSEG(teststr$), SADD(teststr$), LEN(teststr$), fileerror%

IF fileerror% > 0 THEN
 PRINT "Error!"
 PRINT "Error code:"; fileerror%
 END
ELSE
 PRINT "Done!"
END IF

PRINT "Reading from file...";

' Blank out the string:
teststr$ = SPACE$(LEN(teststr$))

ReadFile filename$, 0, VARSEG(teststr$), SADD(teststr$), LEN(teststr$), fileerror%

IF fileerror% > 0 THEN
 PRINT "Error!"
 PRINT "Error code:"; fileerror%
 END
ELSE
 PRINT "Done!"
END IF

PRINT "Text returned: "; teststr$

SUB ReadFile (filename$, filepos&, destseg%, destofs%, readlen%, fileerror%)

' This SUB reads a certain amount of data from a file into system memory.
' - filename$ is the name of the file to be read from.
' - filepos& is the starting position in the file for the reading. Due to
'   overflow errors, you can only define a number up to a little more than 1
'   megabyte. This will hopefully be fixed in the finished version.
' - destseg% is the destination segment in system memory for the data to be
'   transferred.
' - destofs% is the destination offset in system memory for the data to be
'   transferred.
' - readlen% is the number of bytes to be read from the file. If you want
'   to read more than 35536 bytes, write the number in hexadecimal.
' - fileerror% is a variable containing possible errors. The error codes are
'   listed below:
'    0: Call successful, no error
'    1: File not found
'    2: Path not found
'    3: Too many open files
'    4: Access denied
'    5: Access code invalid

filename$ = filename$ + CHR$(0)
fileerror% = 0

' Open the file for reading:
inregs.ax = &H3D00
inregs.ds = VARSEG(filename$)
inregs.dx = SADD(filename$)
InterruptX &H21, inregs, outregs

IF outregs.flags AND 1 THEN
 SELECT CASE outregs.ax
  CASE 2: fileerror% = 1
  CASE 3: fileerror% = 2
  CASE 4: fileerror% = 3
  CASE 5: fileerror% = 4
  CASE 12: fileerror% = 5
 END SELECT
 EXIT SUB
ELSE
 filehandle% = outregs.ax
END IF

' Set the file pointer:
inregs.ax = &H4200
inregs.bx = filehandle%
inregs.cx = (filepos& AND &HFFFF0000) \ &H10000 AND &HFFFF&
inregs.dx = filepos& AND &HFFFF
InterruptX &H21, inregs, outregs

' Read the data:
inregs.ax = &H3F00
inregs.bx = filehandle%
inregs.cx = readlen%
inregs.ds = destseg%
inregs.dx = destofs%
InterruptX &H21, inregs, outregs

' Close the file:
inregs.ax = &H3E00
inregs.bx = filehandle%
InterruptX &H21, inregs, outregs

END SUB

SUB WriteFile (filename$, filepos&, sourceseg%, sourceofs%, writelen%, fileerror%)

' This SUB writes a certain amount of data from system memory into a file.
' - filename$ is the name of the file to be written to. Note that the file
'   specified must already exist.
' - filepos& is the starting position in the file for the writing. Due to
'   overflow errors, you can only define a number up to a little more than 1
'   megabyte. This will hopefully be fixed in the finished version.
'   If you set this varable to -1, the data will be written to the end of
'   the file.
' - sourceseg% is the destination segment in system memory for the data to be
' - transferred.
' - sourceofs% is the destination offset in system memory for the data to be
'   transferred.
' - writelen% is the number of bytes to be written to the file. If you want
'   to write more than 35536 bytes, write the number in hexadecimal.
' - fileerror% is a variable containing possible errors. The error codes are
'   listed below:
'    0: Call successful, no error
'    1: File not found
'    2: Path not found
'    3: Too many open files
'    4: Access denied
'    5: Access code invalid

filename$ = filename$ + CHR$(0)
fileerror% = 0

' Open the file for writing:
inregs.ax = &H3D01
inregs.ds = VARSEG(filename$)
inregs.dx = SADD(filename$)
InterruptX &H21, inregs, outregs

IF outregs.flags AND 1 THEN
 SELECT CASE outregs.ax
  CASE 2: fileerror% = 1
  CASE 3: fileerror% = 2
  CASE 4: fileerror% = 3
  CASE 5: fileerror% = 4
  CASE 12: fileerror% = 5
 END SELECT
 EXIT SUB
ELSE
 filehandle% = outregs.ax
END IF

' Set the file pointer:
IF filepos& = -1 THEN
 inregs.ax = &H4202
 inregs.bx = filehandle%
 inregs.cx = 0
 inregs.dx = 0
 InterruptX &H21, inregs, outregs
ELSE
 inregs.ax = &H4200
 inregs.bx = filehandle%
 inregs.cx = (filepos& AND &HFFFF0000) \ &H10000 AND &HFFFF&
 inregs.dx = filepos& AND &HFFFF
 InterruptX &H21, inregs, outregs
END IF

' Write the data:
inregs.ax = &H4000
inregs.bx = filehandle%
inregs.cx = writelen%
inregs.ds = sourceseg%
inregs.dx = sourceofs%
InterruptX &H21, inregs, outregs

' Close the file:
inregs.ax = &H3E00
inregs.bx = filehandle%
InterruptX &H21, inregs, outregs

END SUB
