DEFINITION MODULE FileSystem;
(*
        file manipulation routines

Derived from the Modula-2 system developed by the
group of Prof. N. Wirth, ETH Zurich, Switzerland.
*)


FROM SYSTEM IMPORT ADDRESS, WORD;

EXPORT QUALIFIED
    (* file operations: *)
    File, Response, Command,
    Create, Close, Lookup, Rename, Delete,
    SetRead, SetWrite, SetModify, SetOpen,
    Doio, SetPos, GetPos, Length,

    (* Streamlike I/O: *)
    Flag, FlagSet,
    Reset, Again,
    ReadWord, ReadChar, ReadByte, ReadNBytes,
    WriteWord, WriteChar, WriteByte, WriteNBytes,

    (* Medium Handling: *)
    FileProc, DirectoryProc,
    MediumType, CreateMedium, RemoveMedium,

    FileNameChar;


TYPE MediumHint = CARDINAL;
(*- medium index used in DiskFiles *)

     MediumType = ARRAY [0..2] OF CHAR;
(*- medium name (A, B...) *)

     Flag     = (er, ef, rd, wr, ag, txt);
(*- status flag for file operations

er = error occured, ef = end-of-file reached, rd = in read mode, wr = in 
write mode, ag = "Again" has been called after last read, txt = text-file
(the last access to the file was a 'WriteChar' or 'ReadChar').
*)

     FlagSet  = SET OF Flag;
(*- status flag set *)

     Response = (done, notdone, notsupported, callerror, unknownmedium,
                unknownfile, paramerror, toomanyfiles, eom, userdeverror);
(*- result of a file operation *)

     Command  = (create, close, lookup, rename, delete, setread, setwrite, 
                setmodify, setopen, doio, setpos, getpos, length);
(*- commands passed to DiskFiles *)

     BuffAdd  = POINTER TO ARRAY [0..0FFFEH] OF CHAR;
(*- file buffer pointer type *)

     File     = RECORD
                bufa: BuffAdd;    (* Buffer Address *)
                buflength: CARDINAL;
                    (* size of buffer in bytes. In the current release
                       it is always a multiple of 128 *)
                validlength: CARDINAL;
                    (* Number of valid bytes in the buffer. *)
                bufind: CARDINAL;
                    (* Byte-Index of current position in the buffer *)
                flags: FlagSet;   (* status of the file *)
                eof: BOOLEAN;
                    (* TRUE, if last access was past end of file *)
                res: Response;    (* result of last operation *)
                lastRead:CARDINAL;(* the last read word or byte (char) *)
                mt: MediumType;
                    (* selects the driver that supports that file *)
                fHint: CARDINAL;   (* internally used by the device-driver *)
                mHint: MediumHint; (* internally used by medium-handler *)
                CASE com: Command OF
                    lookup:  new: BOOLEAN;
                  | setpos, getpos, length:  highpos, lowpos: CARDINAL;
                END;
               END;
(*- file structure used for bookkeeping by DiskFiles *)

PROCEDURE Create (VAR f: File; mediumName: ARRAY OF CHAR);
(*- create a temporary file
in:     mediumName   name of medium to create file on, in char format
out:    f            initialized file structure

A temporary file is characterised by an empty name. To make the file
permanent, it has to  be renamed with a non-empty name before closing it.
For subsequent operations on this file, it is referenced by "f".
*)

PROCEDURE Close (VAR f: File);
(*- Close a file
in:     f       structure referencing an open file
out:    f       the field f.res will be set appropriately.

Terminates the operations on file "f". If "f" is a temporary file, it will 
be destroyed, whereas a file with a non-empty name remains on its medium
and is accessible through "Lookup". When closing a text-file after writing,
the end-of-file code 32C is written on the file (MS-DOS and CP/M convention).
*)

PROCEDURE Lookup (VAR f: File; filename: ARRAY OF CHAR; newFile: BOOLEAN);
(*- look for a file
in:     filename        drive and name of file to search for 
        newFile         TRUE if file should be created if not found
out:    f               initialized file structure; f.res will be set 
                        appropriately.

Searches the medium specified in "filename" for a file that matches the
name and type given in "filename". If the file is not found and "newFile" 
is TRUE, a new (permanent) file with the given name and type is created.
If it is not  found and "newFile" is FALSE, no action takes place and 
"notdone" is returned  in the result field of "f".
*)

PROCEDURE Rename (VAR f: File; newname: ARRAY OF CHAR);
(*- rename a file
in:     f       structure referencing an open file
        newname filename to rename to, with device:name.type specified
out:    f       file name in f will be changed and the f.res field will
                be set appropriately.

The medium, on which the files reside can not be changed with this command. 
The medium name inside "newname" has to be the old one.
*)

PROCEDURE Delete (name: ARRAY OF CHAR; VAR f: File);
(*- delete a file
in:     name    name of file to delete, with dev:name.type specified
out:    f       the result field f.res will be set appropriately.
*)

PROCEDURE ReadWord (VAR f: File; VAR w: WORD);
(*- Returns the word at the current position in f
in:     f       structure referencing an open file
out:    w       word read from file
        f       the result field f.res will be set appropriately.       

the file will be positioned at the next word when the read is done.
*)

PROCEDURE WriteWord (VAR f: File; w: WORD);
(*- Write one word to a file
in:     f       structure referencing an open file
        w       word to write
out:    f       the field f.res will be set appropriately.
*)

PROCEDURE ReadChar (VAR f: File; VAR ch: CHAR);
(*- Read one character from a file
in:     f       structure referencing an open file
out:    ch      charatcter read from file
        f       the result field f.res will be set appropriately.

the file will be positioned at the next character when the read is done.
*)
  
PROCEDURE WriteChar (VAR f: File; ch: CHAR);
(*- Write one character to a file
in:     f       structure referencing an open file
        ch      character to write
out:    f       the result field f.res will be set apporopriately.
*)

PROCEDURE ReadByte (VAR f: File; VAR b: CHAR);
(*- Read one byte from a file
in:     f       structure referencing an open file
out:    b       byte read from file
        f       the result field f.res will be set appropriately.

the file will be positioned at the next byte when the read is completed.
*)

PROCEDURE WriteByte (VAR f: File; b: CHAR);
(*- Write one byte to a file
in:     f       structure referencing an open file 
        b       byte to write
out:    f       the result field f.res will be set appropriately.
*)

PROCEDURE ReadNBytes (VAR f: File; bufPtr: ADDRESS;
                 requestedBytes: CARDINAL; VAR read: CARDINAL);
(*- Read a specified number of bytes from a file
in:     f              structure referencing an open file
        bufPtr         pointer to buffer area to read bytes into
        requestedBytes number of bytes to read
out:    bufPtr^        bytes read from file
        f              the result field f.res will be set appropriately.
        read           the number of bytes actually read.

the file will be positioned at the next byte after the requested string.
*)

PROCEDURE WriteNBytes (VAR f: File; bufPtr: ADDRESS;
                 requestedBytes: CARDINAL; VAR written: CARDINAL);
(*- Write a specified number of bytes to a file
in:     f              structure referencing an open file
        bufPtr         pointer to string of bytes to write
        requestedBytes number of bytes to write
out:    f              the result field f.res will be set appropriately.
        written        the number of bytes actually written
*)

PROCEDURE Again (VAR f: File);
(*- returns a character to the buffer to be read again
in:     f       structure referencing an open file
out:    f       the f.res field will be set appropriately. 

This should be called after a read operation only (it has no effect
otherwise). It prevents the subsequent read from reading the next element;
the element just read before will be returned a second time. Multiple calls 
to Again without a read in between have the same effect as one call to 
Again. The position in the file is undefined after a call to Again (it is 
defined again after the next read operation).
*)

PROCEDURE SetRead (VAR f: File);
(*- Set the file in reading-state, without changing the current position.
in:     f       structure referencing an open file
out:    f       f.res will be set appropriately.

Upon calling SetRead, the current position must be before the eof.
In reading-state, no writing is allowed.
*)

PROCEDURE SetWrite (VAR f: File);
(*- Sets the file in writing-state, without changing the current position.
in:     f       structure referencing an open file
out:    f       f.res will be set appropriately.

Upon calling SetWrite, the current position must be a legal position in
the file (including eof). In writing-state, no reading is allowed, and 
a write always takes place at the eof. The current implementation does
not truncate the file.
*)

PROCEDURE SetModify (VAR f: File);
(*- Sets the file in modifying-state, without changing the current position.
in:     f       structure referencing an open file
out:    f       f.res will be set appropriately.
Upon calling SetModify, the current position must be before the eof.
In modifying-state, reading and writing are allowed. Writing is done
at the current position, overwriting whatever element is already there.
The file is not truncated.
*)

PROCEDURE SetOpen (VAR f: File);
(*- Set the file to opened-state, without changing the current position.
in:     f       structure referencing an open file
out:    f       f.res will be set appropriately.

The buffer content is written back on the file, if the file has been in
writing or modifying status. The new buffer content is undefined.
In opened-state, neither reading nor writing is allowed.
*)

PROCEDURE Reset (VAR f: File);
(*- Set the file to opened state and position it to the top of file.
in:     f       structure referencing an open file
out:    f       f.res will be set appropriately.
*)

PROCEDURE SetPos (VAR f: File; high, low: CARDINAL);
(*- Set the current position in file 
in:     f       structure referencing an open file
        high    high part of the byte offset
        low     low part of the byte offset
out:    f       f.res will be set appropriately.

The file will be positioned (high*2^16 +low) bytes from top of file.
*)

PROCEDURE GetPos (VAR f: File; VAR high, low: CARDINAL);
(*- Return the current byte position in file 
in:     f       structure referencing an open file
out:    high    high part of byte offset
        low     low part of byte offset

The actual position is (high*2^16 +low) bytes from  the top of file.
*)

PROCEDURE Length (VAR f: File; VAR high, low: CARDINAL);
(*- Return the length of the file in bytes.
in:     f       structure referencing an open file.
out:    high    high part of byte offset
        low     ;pw part of byte offset

The actual length is (high*2^16 +low) bytes.
*)

PROCEDURE Doio (VAR f: File);
(*-  Do various read/write operations on a file 
in:     f       structure referencing an open file
out:    f       f.res will be set appropriately.

The exact effect of this command depends on the state of the file (flags):
          opened    = NOOP.
          reading   = reads the record that contains the current byte from the
                      file. The old content of the buffer is not written back.
          writing   = the buffer is written back. It is then assigned to the
                      record, that contains the current position. Its content
                      is not changed.
          modifying = the buffer is written back and the record containing
                      the current position is read.
Note that 'Doio' does not need to be used when reading through the
'stream-like' I/O routines. Its use is limited to special applications.
*)


PROCEDURE FileNameChar (c: CHAR): CHAR;
(*- Check the character c for legality in an MS-DOS filename. 
in:     c       charater to check
out:            0C for illegal characters and c otherwise; lowercase
                letters are transformed into uppercase letters.
*)

TYPE FileProc = PROCEDURE (VAR File);
(*- Procedure type to be used for internal file operations 

A procedure of this type will be called for the functions:
           setread, setwrite, setmodify, setopen, doio,
           setpos, getpos, length, setprotect, getprotect,
           setpermanent, getpermanent.
*)

    DirectoryProc = PROCEDURE (VAR File, ARRAY OF CHAR);
(*- Procedure type to be used for operations on an entire file

A procedure of this type will be called for the functions:
         create, close, lookup, rename, delete.
*)

PROCEDURE CreateMedium (mt: MediumType;
                          fproc: FileProc; dproc: DirectoryProc;
                          VAR done: BOOLEAN);
(*- Install the medium "mt" in the file system
in:     mt      medium type to install
        fproc   procedure to handle internal file operations
        dproc   procedure to handle operations on an entire file
out     done    TRUE if medium was successfully installed.

Before accessing or creating a file on a medium, this medium has to be
announced to the file system by means of the routine CreateMedium.
FileSystem calls "fproc" and "dproc" to perform operations on a file of 
this medium. Up to 24 mediums can be announced.
*)

PROCEDURE RemoveMedium (mt: MediumType; VAR done: BOOLEAN);
(*- Remove the medium "mt" from the file system
in:     mt      medium type to remove
out:    done    true if medium was successfully removed

Attempts to access a file on this medium result in an error (unknownmedium).
*)


END FileSystem.
