The
File Management System (FMS)
forms the communication link between the DOS and the actual Disk Hardware.
The FMS performs all file allocation and removal on the disk. All file space
is allocated dynamically, and the space used by files is immediately reusable
upon that file's deletion. The user of the FMS need not be concerned with the
actual location of a file on the disk, or how many sectors it requires.
Communication with the FMS is done through
File Control Blocks (FCB).
These blocks contain the information about a file, such as its name and what
drive it exists on. All disk I/O performed through FMS is "one character at a
time" I/O. This means that programs need only send or request a single
character at a time while doing file data transfers. In effect, the disk looks
on different than a computer terminal. Files may be opened for either reading
or writing. Any number of files may be opened at any one time, as long as each
one is assigned its own File Control Block.
The FMS is a command language whose commands are represented by various numbers
called
Function Codes
. Each
Function Code
tells FMS to perform a specific function such as open a file for read, or
delete a file. In general, making use of the various functions which the FMS
offers, is quite simple. The index register is made to point to the
File Control Block
which is to be used, the
Function Code
is stored in the first byte of the
File Control Block
, and FMS is called as a subroutine by JSR. At no time does the user ever
have to be concerned with where the file is being located on the disk, how
long it is, or where its directory entry is located. The FMS does all of this
automatically.
Since the file structure of FLEX is a linked structure, and the disk space is
allocated dynamically, it is possible for a file to exist on the disk in a
set of non-contiguous sectors. Normally, if a disk has just been formatted, a
file will use consecutive sectors on the disk. As files are created and
deleted, however, the disk may become "fragmented". Fragmentation results in
the sectors on the disk becoming out of order physically, even though logically
they are still all sequential. This is a characteristic of "linked list"
structures and dynamic file allocation methods. The user need not be concerned
with this fragmentation, but should be aware of the fact that files may exist
whose sectors seem to be spattered all over the disk. The only result of
fragmentation is the slowing down of file read times, because of the increased
number of head seeks necessary while reading the file.
The FLEX File Management System is utilized by the user through function codes.
The proper function code number is placed, by the user, in the Function Code
byte of the File Control Block (FCB) before calling FMS (Byte 0). FMS should
be called by a JSR to the "FMS call" entry. On entry to FMS, the X-register
should contain the address of the FCB. On exit from FMS, the CPU Z-condition
code bit will be clear if an error was detected while processing the function.
This bit may be tested by the BNE and BEQ instructions. Note: In the following
examples, the line "JSR FMS" is referencing the FMS Call entry at $D406.
- Function 0: Read/Write Next Byte/Character
-
If the file is open for reading, the next byte is fetched from the file and
returned to the calling program in the A-register. If the file is open for
writing, the content of the A-register on entry is placed in the buffer as the
next byte to be written to the file. The Compression Mode Flag must contain
the proper value for automatic space compression to take place, if desired
(see
FLEX File Control Block
for details). On exit, this function code remains unchanged in the Function
Code byte of the FCB; thus, consecutive read/writes may be performed without
having to repeatedly store the function code. When reading, and End-of-File
error is returned when all data in the file has been read. When the current
sector being read is empty, the next sector in the file is prepared for
processing automatically, without any action being required of the user.
Similarly, when writing, full sectors are automatically written to the disk
without user intervention.
Example:
If reading: |
LDX | #FCB | ; Point to the FCB |
JSR | FMS | ; Call FMS |
BNE | ERROR | ; Check for errors |
; The character read is now in A |
If writing: |
LDA | CHAR | ; Get the character |
LDX | #FCB | ; Point to the FCB |
JSR | FMS | ; Call FMS |
BNE | ERROR | ; Check for errors |
; The character in A has been written |
- Function 1: Open for Read
-
The file specified in the FCB is opened for read-only access. If the file
cannot be found, an error is returned. The only parts of the FCB which must
be preset by the programmer before issuing this function are the file
specification parts (drive number, file name and file extension) and the
function code. The remaining parts of the FCB will be initialized by the Open
process. The Open process sets the File Compression Mode Flag to zero,
indicating a text file. If the file is binary, the programmer should set the
File Compression Mode Flag to $FF, after opening the file, to disable the
space compression feature. On exit from FMS, after opening a file, the function
code in the FCB is automatically set to zero (Read/Write Next Byte Function)
in anticipation of I/O on the file.
Example:
LDX | #FCB | ; Point to the FCB |
[ Set up file spec in FCB ] |
LDA | #1 | ; Set open function mode |
STA | 0,X | ; Store in FCB |
JSR | FMS | ; Call FMS |
BNE | ERROR | ; Check for errors |
; The file is now open for text reading |
; |
; To set for binary, continue with the following |
LDA | #$FF | ; Set $FF for suppression flag |
STA | 59,X | ; Store in suppression flag |
- Function 2: Open for Write
-
This is the same as Function 1, Open For Read, except that the file must not
already exist in the diskette directory, and it is opened for write-only
access. A file opened for write may not be read unless it is first closed and
then re-opened for read-only. The space compression flag should be treated the
same as described in "Open for Read". A file is normally opened as a sequential
file but may be created as a random file by setting the FCB location File
Sector Map byte non-zero immediately following an open for write operation.
Refer to the section on Random Files for more details. The file will be created
on the drive specified unless the drive spec is $FF in which case the file
will be created on the first drive found to be ready.
Example:
LDX | #FCB | ; Point to the FCB |
[ Set up file spec in FCB ] |
LDA | #2 | ; Setup open for write code |
STA | 0,X | ; Store in FCB |
JSR | FMS | ; Call FMS |
BNE | ERROR | ; Check for errors |
; The file is now open for text write |
; For binary write, follow example in Read open. |
- Function 3: Open for Update
-
This function opens the file for both read and write. The file must not be open
and must exist on the specified drive. If the drive spec is $FF, all drives
will be searched. Once the file has been opened for update, four operations
may be performed on it:
1. | sequential read |
2. | random read |
3. | random write |
4. | close file |
Note that it is not possible to do sequential writes to a file open for update.
This implies that it is not possible to increase the size of a file which is
open for update.
- Function 4: Close File
-
If the file was opened for reading, a close merely removes the FCB from the
chain of open files. If the file was opened for writing, any data remaining in
the buffer is first written to the disk, padding with zeros if necessary,
to fill out the sector. If a file was opened for writing but never written
upon, the name of the file is removed from the diskette directory since the
file contains no data.
Example:
LDX | #FCB | ; Point to the FCB |
LDA | #4 | ; Setup close code |
STA | 0,X | ; Store in FCB |
JSR | FMS | ; Call FMS |
BNE | ERROR | ; Check for errors |
; File has now been closed |
- Function 5: Rewind File
-
Only files which have been opened for read may be rewound. On exit from FMS,
the function code in the FCB is set to zero, anticipating a read operation on
the file. If the programmer wishes to rewind a file which is open for writing
so that it may now be read, the file must first be closed, then re-opened for
reading.
Example:
; Assuming the file is open for read: |
LDX | #FCB | ; Point to the FCB |
LDA | #5 | ; Setup rewind code |
STA | 0,X | ; Store in FCB |
JSR | FMS | ; Call FMS |
BNE | ERROR | ; Check for errors |
; File is now rewound & ready for read |
- Function 6: Open Directory
-
This function opens the directory on the diskette for access by a program. The
FCB used for this function must not already be open for use by a file. On
entry, the only information which must be preset in the FCB is the drive
number; no file name is required. The directory entries are read by using the
Get Information Record
function. The
Put Information Record
function is used to write a directory entry. The normal
Read/Write Next Byte
function will not function correctly on an FCB which is opened for directory
access. It is not necessary to close an FCB which has been opened for directory
access after the directory manipulation is finished. The user should normally
not need to access the directory.
- Function 7: Get Information Record
-
This function should only be issued on an FCB which has been opened with the
Open Directory
function. Each time the
Get Information Record
function is issued, the next directory entry will be loaded into the
Directory Information
area of the FCB. All directory entries, including deleted and unused entries are
read when using this function. After an entry has been read, the FCB is said
to "point" to the directory entry just read; the
Current Directory Address
bytes in the FCB refer to the entry just read. An End-of-File error is returned
when the end of the directory is reached.
Example:
| ; Get the 3rd directory entry: |
| LDX | #FCB | ; Point to the FCB |
| LDA | DRIVE | ; Get the drive number |
| STA | 3,X | ; Store in the FCB |
| LDA | #6 | ; Setup open dir code |
| STA | 0,X | ; Store in FCB |
| JSR | FMS | ; Call FMS |
| BNE | ERROR | ; Check for errors |
| LDB | #3 | ; Setup counter to 3 |
LOOP | LDA | #7 | ; Setup get rec code |
| STA | 0,X | ; Store in FCB |
| JSR | FMS | ; Call FMS |
| BNE | ERROR | ; Check for errors |
| DECB | | ; Decrement the counter |
| BNE | LOOP | ; Repeat till finished |
| ; The 3rd entry is now in the FCB |
- Function 8: Put Information Record
-
This function should only be issued on an FCB which has been opened whith the
Open Directory
function. The directory information is copied from the
Directory Information
portion of the FCB into the directory entry to which the FCB currently points.
The directory sector just updated is then re-written automatically on the
diskette to ensure that the directory is up-to-date. A user program should
normally never have to write into a directory. Careless use of this function
can lead to the destruction of data files, necessitating a re-initialization of
the diskette.
- Function 9: Read Single Sector
-
This function is a low-level interface directly to the disk driver which
permits the reading of a single sector, to which the
Current Position
byte of the FCB point, into the
Sector Buffer
area of the FCB. This function is normally used internally within FLEX and
a user program should never need to use it. The
Read/Write Next Byte
function should be used instead, whenever possible. Extreme care should be
taken when using this function since it does not conform to the usual
conventions to which most of other FLEX functions adhere.
Example:
LDX | #FCB | ; Point to the FCB |
LDA | TRACK | ; Get track number |
STA | 30,X | ; Set current track |
LDA | SECTOR | ; Get sector number |
STA | 31,X | ; Set current sector |
LDA | #9 | ; Setup function code |
STA | 0,X | ; Store in FCB |
JSR | FMS | ; Call FMS |
BNE | ERROR | ; Check for errors |
- Function 10: Write Single Sector
-
This function, like the
Read Single Sector
function, is a low-level interface directly to the disk driver which permits
the writing of a single sector. As such, it requires extreme care in its use.
This function is normally used internally by FLEX, and a user program should
never need to use it. The
Read/Write Next Byte
function should be used whenever possible. Careless use of the
Write Single Sector
function may result in the destruction of data, necessitating a
re-initialization of the diskette. The disk address being written is taken
from the
Current Position
byte of the FCB; the data is taken from the
Current Position
bytes of the FCB; the data is taken from the FCB
Sector Buffer.
This function honors the
Verify Flag
(see
FLEX Memory Map
), and will check the sector after writing it if directed to do so by the
Verify Flag.
- Function 11: Reserved for future system use
- Function 12: Delete File
-
This function deletes the file whose specification is in the FCB (drive number,
file name and extension). The sectors used by the file are released to the
system for re-use. The file should not be open when this function is issued.
The file specification in the FCB is altered during the delete process.
Example:
LDX | #FCB | ; Point to the FCB |
[ setup file spec in FCB ] |
LDA | #12 | ; Setup function code |
STA | 0,X | ; Store in FCB |
JSR | FMS | ; Call FMS |
BNE | ERROR | ; Check for errors |
; File has now been deleted |
- Function 13: Rename File
-
On entry, the file must not be open, the old name must be in the
File Specification
area of the FCB, and the new name and extension must be in the
Scratch Bytes
area of the FCB. The file whose specification is in the FCB is renamed to the
name and extension stored in the FCB
Scratch Bytes
area. Both the new name and the new extension must be specified; neither the
name nor the extension can be defaulted.
Example:
LDX | #FCB | ; Point to the FCB |
[ setup both file specs in FCB ] |
LDA | #13 | ; Setup function code |
STA | 0,X | ; Store in FCB |
JSR | FMS | ; Call FMS |
BNE | ERROR | ; Check for errors |
; File has been renamed |
- Function 14: Reserved for future system use
- Function 15: Next Sequential Sector
-
On entry the file should be open for either reading or writing (not update). If
the file is open for reading, this function code will cause all of the remaining
(yet unread) data bytes in the current sector to be skipped, and the data
pointer will be positioned at the first data byte of the next sequential sector
of the file. If the file is opened for write, this operation will cause the
remainder of the current sector to be zero filled and written out to the first
available data location in the next sequential sector. It should be noted that
all calls to this function code will be ignored unless at least one byte of
data has either been written or read from the current sector.
- Function 16: Open System Information Record
-
On entry, only the drive number need be specified in the FCB; there is no file
name associated with this function. The FCB must not be open for use by a file.
This function accesses the
System Information Record
for the diskette whose drive number is in the FCB. There are no separate
functions for reading or changing this sector. All references to the data
contained in the
System Information Record
must be made by manipulating the
Sector Buffer
directly. This function is used internally within FLEX; there should be no
need for a user-written program to change the
System Information Record.
Doing so may result in the destruction of data, necessitating the
re-initialization of the diskette. There is no need to close the FCB when
finished.
- Function 17: Get Random Byte From Sector
-
On entry, the file should be open for reading or update. Also, the desired
byte's number should be stored in the
Random Index
byte of the FCB. This byte number is relative to the beginning of the sector
buffer. On exit, the byte whose number is stored in the
Random Index
is returned to the calling program in the A-register. The
Random Index
should not be less than 4 since there is no user data in the first four bytes
of the sector.
Example:
; To read the 54th data byte of the current sector |
LDX | #FCB | ; Point to the FCB |
LDA | #54+4 | ; Setup to item + 4 |
STA | 35,X | ; Put it in random index |
LDA | #17 | ; Setup function code |
STA | 0,X | ; Store in FCB |
JSR | FMS | ; Call FMS |
BNE | ERROR | ; Check for errors |
; Character is now in accu A |
- Function 18: Put Random Byte in Sector
-
The file must be open for update. This function is similar to
Get Random Byte
except the character in the A accumulator is written into the sector at the
data location specified by
Random Index
of the FCB. The
Random Index
should not be less than 4 since only system data resides in the first 4
bytes of the sector.
Example:
; To write the 54th data byte of the current sector |
LDX | #FCB | ; Point to the FCB |
LDA | #54+4 | ; Setup to item + 4 |
STA | 35,X | ; Put it in random index |
LDA | #18 | ; Setup function code |
STA | 0,X | ; Store in FCB |
LDA | CHAR | ; Get character to be written |
JSR | FMS | ; Call FMS |
BNE | ERROR | ; Check for errors |
; Character has been written |
- Function 19: Reserved for future system use
- Function 20: Find Next Drive
-
This function is used to find the next online drive which is in the "ready"
state. Due to hardware limitations, the mini floppy version of FLEX performs
this command differently than the full size floppy version. The functioning
of the full size floppy version is as follows. If the drive number in the
FCB is hex FF, the search for drives will start with drive 0. If the drive
number is 0, 1 or 2, the search will start with drive 1, 2 or 3 respectively.
If a ready drive is found, its drive number will be returned in the drive
number byte of the FCB and the carry bit will be cleared. If no ready drive
is found, the carry bit will be set and error #16 (Drives Not Ready) is set.
The minifloppy version functions as follows. If called with a
Drive Number
in the FCB of hex FF, the function will return with 0 as the drive number in
the FCB. If called with a 0, it will return with the drive number set to 1. In
both cases the carry is cleared on return. If called with a drive number of 1
or higher, the drive number is left unchanged, the carry bit is set on return
and error #16 (Drives Not Ready) is set.
- Function 21: Position to Record N
-
This is one of the 2 function codes provided for random file accessing by
sector. The desired record number to be accessed should be stored in the FCB
location
Current Record Number
(a 16-bit binary value). The file must be open for read or update before
record number one. Positioning to record 0 will read in the first sector
of the
File Sector Map.
After a successful Position operation, the first character read with a
sequential read will be the first data byte of the specified record. An attempt
to position to a nonexistent record will cause an error. For more information
on random files see
RANDOM FILES
for details.
Example:
; To position to record #6 |
LDX | #FCB | ; Point to the FCB |
LDA | #6 | ; Set position |
STA | 33,X | ; Put in FCB |
CLR | 32,X | ; Set M.S.B. to 0 |
LDA | #21 | ; Setup function code |
STA | 0,X | ; Store in FCB |
JSR | FMS | ; Call FMS |
BNE | ERROR | ; Check for errors |
; Record ready to be read |
- Function 22: Backup One Record
-
This is also used for random file accessing. This function takes the
Current Record Number
in the FCB and decrements it by one. A Position to the new record is performed.
This has the effect of back spacing one full record. For example, if the
Current Record Number
is 16 and the
Backup One Record
function is performed, the file would be positioned to read the first byte of
record #15. The file must be open for read or update before this function may
be used. See section
RANDOM FILES
for details.
FLEX version 9.0 supports random files. The random access technique allows
access by record number of a file and can reach any specified sector in a
file, no matter how large it is, in a maximum of two disk reads. With a small
calculation using the number of data bytes in a sector (252), the user may also
easily reach the Nth character of a file using the same mechanism.
Not all files may be accessed in a random manner. It is necessary to create
the file as a random file. The default creation mode is sequential and is what
all of the standard FLEX Utilities work with. The only random file in a
standard FLEX system is the ERRORS.SYS file. FLEX uses a random access
technique when reporting error messages. A file which has been created as a
random access file may read either randomly or sequentially. A sequential file
may only be read sequentially.
To create a random file, the normal procedure for opening a file for write
should be used. Immediately following a successful open, set the
File Sector Map
location of the FCB to any non-zero value and proceed with the file's creation.
It only makes sense to create text type files in the random mode. As the file
is built, the system creates a
File Sector Map.
This
File Sector Map
(FSM) is a map or directory which tells the system where each record (sector)
of the file is located on the disk. The FSM is always two sectors in length
and is assigned record number 0 in the file. This implies that a data file
requiring 5 sectors for the data will actually be 7 sectors in length. The
user has no need for the FSM sectors and they are automatically skipped when
opening a file for read. The FMS uses them for the Position and Backup
function code operations.
The directory information of a file states whether or not a file is a random
file. If the
File Sector Map
byte is non-zero, the file is random, otherwise it is sequential only. It
should be noted that random files can be copied from a disk to another without
losing its random properties, but it can not be appended to another file.
Within
flexemu
if using a directory as a FLEX drive the user execution bit will be used to
distinguish between random and sequential files. Random files have this bit
set.