Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

In a compression MFS, for example, the developer's logic would be concentrated under the labels for READ.RECORD and WRITE.RECORD.  When the MFS has branched to the write logic, the developer's routines can compress the record passed to the MFS. During a read, the MFS branches to a different location, and the developer's code can then decompress the record.

Call to Next MFS

Under most circumstances, when an MFS has finished, it calls the next filing system, passing it all arguments, including those that have been modified.  The next filing system operates on those arguments as if they had come directly from BASIC+.

The next filing system may be the BFS, or it might be an additional MFS. If there is another MFS installed on the file, the current MFS calls the next MFS. If there are no more MFSs for the file, the MFS calls the BFS directly.

BFS Argument

The BFS argument (the second argument passed to the MFS) contains a list of all the MFSs and of the BFS for the file being accessed. If a Linear Hash dictionary file were indexed, for instance, the BFS argument would initially contain the full list of MFSs and the BFS name associated with the file: DICT.MFS, SI.MFS and RTP57. This list is a dynamic array (subvalue-mark-delimited) of all MFSs, with the proper BFS as the last value in the array.

To call the next file system routine, the MFS derives the name of the next MFS from this list, and then calls it using the "@variable" syntax for the BASIC+ CALL statement.  Deriving the name of the next MFS is a two-step process. The MFS must first remove its own name from the list. After this is accomplished, the first element of the BFS array then contains the name of the next filing system routine, and can be extracted simply.

The full BASIC+ logic to strip the current MFS name from the list, derive the next routine name, and call the next routine looks like this:

 

Code Block
FS = DELETE(BFS,1,1,1) ; * strip current name
NEXT.FS = FS<1,1,1> ; * derive name of next
routine
* now call next routine. Note that all seven
* arguments are passed
CALL @NEXT.FS(CODE,FS,HANDLE,NAME,FMC,RECORD, STATUS)

 

 

For example, if an MFS called SAMPLE.MFS has been installed onto a Linear Hash file, the BFS argument will be passed to SAMPLE.MFS with this structure:

Code Block
SAMPLE.MFS :@SVM : RTP57

When SAMPLE.MFS has finished processing, it executes the Delete() function to strip its own name from the list. The result is a one-element array containing simply the name RTP57 (the native Linear Hash filing system).  The subsequent extract derives the name and passes it to the CALL statement. As a result, SAMPLE.MFS calls RTP57, passing it the seven required arguments.

Return from the BFS

Since an MFS calls the next filing system using a CALL statement, the MFS remains resident while filing systems that follow are executing.  As with any subroutine calls, however, when routines (other MFSs and the BFS) are finished with the call, control returns to the statement following the CALL @NEXT.FS( ... ) statement.

An MFS thus has two opportunities with each operation to manipulate the data: when the call and arguments first come down from BASIC+, and again when the arguments are being returned from the BFS. In effect, this gives an MFS a "pre-file-operation" and a "post-file-operation" capability.

For example, an MFS that encrypts and decrypts data would modify the data differently depending on whether a read or write operation were being performed. If the data were being written to the file, the MFS would encrypt the data before calling the next filing system routine in line. All subsequent MFSs, and the BFS, would be passed a record that was already encrypted.

However, when reading the data, the MFS would decrypt the record after it had returned from the BFS and from any MFSs that came after the encryption MFS. In this way, the encryption MFS could pass clear data back to the BASIC+ READ statement.

The fact that MFSs can be stacked in this way affects the design of an MFS.  In some instances, the order of MFSs is critical, since the output from one MFS is the input for the next, or since one MFS might terminate a file operation before subsequent MFSs get an opportunity to examine the data.