type pbytes = ^tbytes;
tbytes = array[0..0] of byte;
A linear buffer of bytes located somewhere in memory. Pointers returned on files are pbyte structures.
type pdrivebank = ^tdrivebank;
tdrivebank = record
drive: char; {current drive 'B','C',...,'Q'; '-' = none}
files: byte; {number of files on disk; 0 = invalid disk or file system}
drive_sectors: word; {number of disk sectors}
fat_sectors : word; {number of sectors required for FAT}
vzone_sectors: word; {number of sectors required for disk valudation zone}
drivesize: longint; {disk size in bytes = sum of all file sizes}
fat : pbytes; {pointer to file allocation table (FAT)}
end;
This structure is used for managing drives. Before accessing a file from a memory bank, the according drive must be selected.
- DRIVE holds the current drive letter, where A to K means a ROM drive, L to Q a flash drive and - that there's currently no drive selected in this bank
- FILES gives the number of files contained in the selected drive
- DRIVE_SECTORS is the number of 512B sectors the drive consists of. Total drive size in B = DRIVE_SECTORS shl 9
- FAT_SECTORS: how much drive sectors are used for the file allocation table
- VZONE_SECTORS: number of sectors used for the FAT validation zone
- DRIVESIZE = sum of all filesizes on that drive
- FAT points to the drive's file allocation table. Internal use, only
type pdrivebanks = ^tdrivebanks;
tdrivebanks = array[0..3] of tdrivebank;
var drivebanks: tdrivebanks; {drivebanks 0..3 are mapped into EMS slots 2,3,4 and 5}
There are 4 drivebanks you can use to map drives into, where flash drives always occupy 1 bank and for ROM drives this depends on the drive's size.
However, when using DFA in RXE programs, note that you mustn't remap drivebank 0, see 4. Using DFA in RXE programs therefore.
type string8 = string[8];
string3 = string[3];
type pdfa = ^tdfa;
tdfa = record
fsect: word; {first sector of file relative to end of FAT}
fsize: longint; {file size in bytes}
fbuff: pbytes; {pointer to file contents/first byte of file}
findx: byte;
fname: string8; {file name}
fext: string3; {file name extension}
year: word; {file date}
day,mon: byte;
s,m,h: byte; {file time}
end;
The tdfa structure is used to hold file information.
- FSECT: Number of the first sector on the drive occupied by the file
- FSIZE = filesize in bytes
- FBUFF is the pointer to the linear buffer within the CPUs address space that you can use to access the file's contents
- FINDX can be used rather like the filename to identify the file on the disk. FINDX is the file's number on the disk, e.g. the first file has index 0, the second index 1 and so on. You may use FINDX to enumerate disk's files, e.g. for file explorers (see also the TINYSHELL demo)
- FNAME = filename (8 chars)
- FEXT = file extension (3 chars)
- YEAR, DAY, MON, S, M, H: File date and time. Note that the file system seldom holds the correct values here, so these fields have less meaning.
const maperr: boolean = false; {error: cannot map drive to bank, disk too big}
dfaerr: boolean = false; {error: file not found }
These variables hold error codes when you executed a DFA operation. MAPERR is true, when it's impossible to map a drive into a bank. This is when for example the drive number is invalid (e.g. W:\) or you want to map a drive that uses three banks into bank 2 (where you only may map drives using one or two banks).
function getdrivebankmap(bank: byte): char; {get current drivebank drive }
procedure getdrivebank(bank: byte); {get disk info for drivebank }
procedure getdrivebanks; {get disk info for all drivebanks}
procedure mapdrivebank(drive: char; bank: byte); {map drive into drivebank + get info}
procedure mapdrivebanks; {map drives into drivebanks + get info}
Drive mapping functions.
Before doing anything with DFA, you always should call GETDRIVEBANKS determining which drives currently are mapped and storing infos about them in the DRIVEBANKS variable (on startup, bank 0 normally is the drive that the program was started from). Rather like GETDRIVEBANKS, GETDRIVEBANK determines which drive is mapped into a bank and stores the drive info to DRIVEBANKS, but with one certain bank only.
GETDRIVEBANKMAP returns the drive char of the drive mapped into a bank.
Finally, MAPDRIVEBANK is used to map a certain drive into a certain bank. Always check MAPERR variable afterwards, which is true on fail (details see above). Also, when using DFA in RXE programs you mustn't remap drivebank 0, see 4. Using DFA in RXE programs therefore.
{get size of a string stored in FAT string format}
function fatstringsize(buff: pbytes; size: byte): byte;
{get direct file access for file at FAT index}
procedure getdfa(var dfa: tdfa; bank,index: byte);
{get direct file access for first file (name) in FAT}
procedure getdfaname(var dfa: tdfa; bank,pos: byte; fname: string8);
{get direct file access for first file (extension) in FAT}
procedure getdfaext(var dfa: tdfa; bank,pos: byte; fext: string3);
{get direct file access for first file (name).(extension) in FAT}
procedure getdfanameext(var dfa: tdfa; bank,pos: byte; fname: string8; fext: string3);
{get pointer to byte pos in file; usefull for files > 64KB allocating more than one segment}
function dfaseek(dfa: tdfa; pos: longint): pbytes;
These finally are the file access functions assuming that the according drive is mapped proper.
- FATSTRINGSIZE: internal use only. Retrieves the size of a string stored in a format used by the file system to hold file names and extensions
- GETDFA, GETDFANAME, GETDFAEXT, GETDFANAMEEXT: replaces to DOS openfile functions when filling a TDFA structure with data sufficient for accessing it. Therefore, you may define the file by it's index on the drive, by it's file name, by it's file extension or it's name and extension combined. Also, you can specify the first index to look at. This makes it possible to enumerate all files with the same extension, for example (then call GETDFAEXT again with pos+1 where pos is the index of the previous file found). E.g., when you want DF access for a file "help.txt", you use "getdfanameext(dfa,bank,0,'help','txt')", where BANK is the bank number you mapped to drive to and DFA the variable recieving file info. Always check DFAERR variable afterwards which is TRUE on fail (file not found)!
- DFASEEK retrieves a pointer for a certain byte of the file. This is usefull for files > 64 KB which you can't fully access using one buffer only (as maximum buffer size is 64KB). In that case, when accessing file bytes located at position > 70000 for example, get a pointer by DFASEEK(dfa,70000) and use this pointer for the buffer holding this byte and the following.