DEFINITION MODULE Streams;

(*  Streams defines an abstract object called a `STREAM'
    and a set of valid operations on such objects.

    Streams have one of three modes; Input, Output or
    Input-Output, which is fixed when a stream object is created.
    Input streams are sequences of elements from which elements
    may be removed (read) in a serial manner.
    A one-element bckspace is defined for all Input streams.
    Output streams are sequences of elements to which elements
    may be added (written) in a serial manner.
    Input/Output streams have the characteristics of both 
    Input and Output streams.

    The source (for Input streams) or sink (for Output streams)
    is not defined by the Streams module, which only provides
    generic procedures which are that for all stream types.
    A specific type is defined by an implementation which maps
    the generic procedures into specific operations.
    This module makes no assumptions about the type of object
    being stored on the stream; this is defined by an implementation
    but will typically be characters or bytes.
    The 'size' of a stream element can always by found by
    the function 'ElementSize'.

    The `StreamIP' module provides details on the creation of
    specific stream implementations.
*)

FROM SYSTEM       IMPORT WORD, ADDRESS;
FROM SYSTEMTYPES  IMPORT LONGINTEGER, LONGCARDINAL;

EXPORT QUALIFIED

(* TYPEs *)       STREAM, STREAMIP, ERRORCODE, ERRORSTRING, SEEKMODE,

(* ReadOnly VAR *)ErrorStringList,

(* PROCs *)       Initialise, Finalise,
                  Put, Get, PutN, GetN, Backspace, 
                  Flush, Delete, ElementSize, Seek, Tell;


TYPE STREAMIP;    (* The abstract type denoting a stream implementation. *)

TYPE ERRORCODE  = (Success,          (* OK, cool, slinky, etc. *)
                   IllegalFunction,  (* impossible function *)
                   NotImplemented,   (* function not implemented *)
                   EndOfStream,      (* no more elements on stream *)
                   StreamError);     (* stream-specific error *)

TYPE     STREAM = POINTER TO RECORD
                    Status : ERRORCODE;  (* EndOfStream... etc. *)
	         ErrorCode : INTEGER;     (* Stream IP specific  *)
                 Extension : WORD;        (* user-level hook...  *)
            Implementation : STREAMIP;    (* opaquely hidden...  *)
                   END;

TYPE ERRORSTRING = ARRAY [0 .. 31] OF CHAR;
(*  Contains a string literal corresponding to an ERRORCODE *)

VAR ErrorStringList : ARRAY ERRORCODE OF ERRORSTRING;
(*  Indexing this array with an ERRORCODE will pick
    out the appropriate error message string.
*)

PROCEDURE Initialise();
(*  Package Initialisation.
    It is called during the module initialisation process and should
    not need to be called by the user unless it is desired to restart
    after a call to Finalise;
*)

PROCEDURE Finalise();
(*  Closes all open streams by a call to CloseStream (see below).
    The order of closure is undefined.
*)

PROCEDURE ElementSize(s : STREAM) : CARDINAL;
(*  returns the size in bytes of an element of stream 's'. *)

PROCEDURE Get(s: STREAM; VAR element: WORD);
(*  Returns the next element on stream `s'.
    The use of VAR WORD allows any object of simple type
    to be returned without coerciom.
*)

PROCEDURE GetN(s : STREAM; address : ADDRESS;  nreq : CARDINAL) : CARDINAL;
(*  Gets the next 'nreq' elements (at most) from stream `s',
    and places them at increasing addresses starting at 'address'. The size
    of the individual elements is determined by the stream implementation.
    The number of elements actually taken off is returned as result.
*)

PROCEDURE Put(s : STREAM;  element : WORD);
(*  Outputs `element' to stream `s'. *)

PROCEDURE PutN(s : STREAM;  address : ADDRESS;  nreq : CARDINAL) : CARDINAL;
(*  Outputs `nreq' elements to stream `s', from increasing addresses
    starting at 'address'. The result is the number actually put. The size
    of the individual elements is determined  by the stream implementation.
*)

PROCEDURE Backspace(s: STREAM);
(*  Performs a one element backspace on stream `s'. 
    Repeated calls have no additional effect.
*)

PROCEDURE Delete(VAR s : STREAM);
(*  Closes the stream denoted by `s', and makes in invalid. *)

PROCEDURE Flush(s : STREAM);
(*  Flushes the (output side of) stream `s'. *)

TYPE SEEKMODE = (beginning, current, end);

PROCEDURE Seek(s : STREAM;  seekmode : SEEKMODE;  offset : LONGINTEGER);
(*  Sets the 'next element' pointer on stream `s' to a position
    specified by offset taken relative to 'seekmode'.  
*)

PROCEDURE Tell(s : STREAM;  VAR p : LONGCARDINAL);
(*  Sets p to the 'current element' pointer on stream `s'.
    Can be passed back to Seek if 'seekmode = beginning'.
*)

END Streams.
