(*
    Title: 	StreamIP - Definitions
    LastEdit:	Fri May 25 16:42:15 1984
    Author: 	Mick Jordan
		Acorn Research Centre
*)

DEFINITION MODULE StreamIP;

FROM SYSTEM       IMPORT WORD;
FROM SYSTEMTYPES  IMPORT LONGWORD;
FROM Streams      IMPORT STREAM;

EXPORT QUALIFIED

(* TYPEs *)       STREAMBLOCKPTR, STREAMBLOCK, FUNCTION, STREAMPROC, MODE,

(* PROCs *)       CreateStream, Control, Control1, Control2, Control2L,
                  KillStream, KillAllStreams, Implements;


TYPE MODE = (In, Out, InOut);  	(* every stream has a constant MODE *)

TYPE FUNCTION = 

(*  FUNCTION defines the list of standard operations which, with the
    exception of CREATE and USERFUNCTION, may result from calls to the 
    procedures defined above.
*)

    (CREATE, 				(* mandatory *)
     IMPLEMENTS,                        (* mandatory *)
     ELEMENTSIZE,                       (* mandatory *)
     PUT, GET,                          (* mandatory *)
     DELETE,      	                (* mandatory *)
     FLUSH,				(* mandatory *)

     PUTN, GETN,                        (* optional *)
     SEEK,				(* optional *)
     TELL,				(* optional *)
     USERFUNCTION			(* optional *)
    );

(*  CREATE is called by CreateStream (see below) and allows initialisation
    procedures to be carried out, e.g. buffer allocation.
    USERFUNCTION provides a way of programming extensible stream operations.
    The `optional' functions can be checked for on any given stream
    with the `Implements' function.
*)


TYPE STREAMBLOCKPTR = POINTER TO STREAMBLOCK;

(*  Stream implementations must provide a procedure of the following type,
    which will be called whenever an operation is requested by one of
    the generic procedures defined above.
*)

TYPE STREAMPROC = PROCEDURE(

    STREAMBLOCKPTR, 			(* of associated stream	      *)
    FUNCTION, 				(* requested		      *)
    WORD				(* a function/stream specific
                                           argument		      *)
                             ): WORD;

(*  the WORD parameter varies according to the function specified,
    as follows:-
    
    CREATE        the 'arg' parameter which was passed to `CreateStream'.
    IMPLEMENTS    the function being inquired about
    ELEMENTSIZE   unset
    PUT           the element to be put to the stream.
    GET           unset
    DELETE        unset
    PUTN          the address of the elements to be put to the stream.
    GETN          the address where the elements are to be placed.
    SEEK          the `seekmode' from Streams.Seek
    TELL          ditto
    USERFUNCTION  the `userfunction' code, from `StreamIP.Control1/2'.

    PUTN, GETN, SEEK and USERFUNCTION require a second argument which
    is stored in the `arg2' field of the STREAMBLOCK. This is:-
    
    PUTN          the number of elements to add
    GETN          the number of elements to take
    SEEK          the amount to seek by
    USERFUNCTION  the code which defines the particular userfunction

    The result parameter is set as follows:-
    
    CREATE        unset
    DELETE        unset
    IMPLEMENTS    a BOOLEAN, TRUE if function is implemented
    ELEMENTSIZE   the size in bytes
    PUT           unset
    GET           the value of the element taken off the stream
    PUTN          the number of elements successfully put
    GETN          the number of elements successfully taken off
    SEEK          unset
    TELL          unset
    USERFUNCTION  set depending on actual `userfunction'

    TELL sets the `arg2L' field of the STREAMBLOCK to the
    stream position.  USERFUNCTIONs may also place values
    in this field.
    
    GETN must set the 'lastValue' field of the STREAMBLOCK
    if BackSpace is to work as expected.
*)


TYPE STREAMBLOCK = RECORD

(*  The only parts of this record which really really of interest to
    the implementor are the `arg2' field, which is used to pass/return
    additional data and the `userField' which is the place to store
    stream specific data (usually a pointer to some other structure).
*)

    link : STREAMBLOCKPTR;		(* link to next STREAMBLOCK   *)
    proc : STREAMPROC;			(* implementor-defined        *)
    mode : MODE;		       	(* In, Out or Inout           *)
    backSpacePending : BOOLEAN; 	(* set TRUE if Backspace called *)
    lastValue : WORD;			(* stored for Backspace       *)
    eos : BOOLEAN;                      (* TRUE if EndOfStream set    *)

    CASE BOOLEAN OF
        TRUE: arg2L: LONGWORD;		(* set by Control2L	      *)
    |   FALSE: arg2: WORD		(* set by Control2	      *)
    END;

    stream : STREAM;                    (* point back to STREAM object *)
    userField : WORD;			(* free for implementors      *)
  END (* record *);

PROCEDURE CreateStream(m : MODE;  f : STREAMPROC; arg : WORD) : STREAM;
(*  Creates a new stream object of MODE m, with f as the procedure
    to be called by the generic operations. The streamblock is allocated
    and initialised, Status is set to Success and then f is called with
    arg as the third parameter.  If Status is set to anything other
    than Success on return from f, the streamblock is deallocated
    and the call fails.
*)

PROCEDURE Implements(s : STREAMBLOCKPTR;  f : FUNCTION) : BOOLEAN;
(*  returns TRUE iff `s' implements optional function `f' *)

PROCEDURE Control2(s : STREAMBLOCKPTR; f : FUNCTION; arg1, arg2 : WORD): WORD;
(*  This is provided as a convenient way of applying an arbitrary
    function to stream s.  Status is set to Success, `arg2' is
    stored in the corresponding slot of the stream block and then
    the associated streamproc is called with `arg1' as the third
    parameter.  

    Extensible operations can be programmed by defining a 
    extended operation type, then passing USERFUNCTION as
    `f', the extended operation as `arg1', with any additional
    argument as `arg2'.
*)

PROCEDURE Control2L(s : STREAMBLOCKPTR;  f : FUNCTION;  arg1 : WORD;
                                      arg2 : LONGWORD) : WORD;
(*  Control2L is provided primarily to provide a portability
    interface for the SEEK, TELL functions which use LONGINTS and
    LONGCARDS respectively.
*)

(* *** Cut-down versions of Control2, for efficiency. *** *)
PROCEDURE Control(s :  STREAMBLOCKPTR;  f : FUNCTION) : WORD;
PROCEDURE Control1(s : STREAMBLOCKPTR;  f : FUNCTION;  arg1 : WORD) : WORD;

PROCEDURE KillStream(s : STREAMBLOCKPTR);
(*  'DELETE' and forget stream `s'. *)

PROCEDURE KillAllStreams();
(*  'DELETE' all streams *)

END StreamIP .
