!
! Buffer format
!
! BASE        start of the space allocated to the buffer
! SIZE        size  of the space allocated to the buffer, in bytes
!
%record %format Buff Fm ( %integer Base, Size )

!
! for machine-code
!
%const %integer Buff Base        = 0,
                Buff Size        = 4

!
! Commonest stream-private block is the one containing all the RMS
! structures needed for a file.
!
%from IMP %include RMS

%record %format FD Fm ( -
        %record(Fab Fm) Fab,
        %record(Rab Fm) Rab,
        %record(Nam Fm) Nam,
        %string(255) Resultant )

!
! Stream control block "accessor"
!
! The buffer currently in use is described by S_THISB.
!
!    base
!      |
!      |<-----------size------------>|
!     +--+--+--+--+--+--+--+--+--+--+--+
!     |  |  |  |  |  |  |  |  |  |  |  |
!     +--+--+--+--+--+--+--+--+--+--+--+
!      ^                                ^
!      |                                |
!      |                                |
!   notional                         notional
!   pointer                           limit
!    NPTR                             NLIM
!
! For both input and output, the notional pointer points at the next
! unprocessed character slot in the buffer. The buffer has no unprocessed
! character slots if NPTR>=NLIM. The notional NPTR and NBUF are derived from
! the PTR and LIM in the accessor record by adding the constants PTROFF or
! LIMOFF. For example, to test if a buffer is completely processed, the
! comparison is:
!
!           S_PTR+PTROFF >= S_LIM+LIMOFF
!
! To go from nominal to actual, subtract OFF
! To go from actual to nominal, add OFF
!
%const %integer Ptr Off = 1,
                Lim Off = 1

!      
! (1) For use as an INPUT SCB
!
! LIM points to the last character in the buffer
! PTR points to the most recently used character
!     i.e. one before the next symbol.
!     The buffer is empty if LAST SYMBOL >= LIMIT
!     because all characters have been consumed.
!
! (2) For use as an OUTPUT SCB
!
! LIM points to the last valid space in the buffer
! PTR points to the most recently WRITTEN character
!     space. The buffer is therefore full if
!     LIMIT >= LAST SYMBOL because all available
!     character positions have been filled up.
!
! (0) Generic Fields
!
! RAB and FAB  are pointers to a record and file access block
!              respectively; note that these need NOT necessarily
!              be the appropriate RMS structures.
!
! Handler routines are all CALLed. The arguments are as follows:
! Functions:
!
! CLOSE    HANDLER (SCB,Mode)            0 => CLOSE, 1 => ABANDON
! COMPLETE HANDLER (SCB)
! POSITION HANDLER (SCB,Byteno)          >=0
! RESET    HANDLER (SCB)
!
! BREAK  HANDLER (used only on output);  R1 = character to process
! BUFFER HANDLER (on input)
! BUFFER HANDLER (on output)             R1 = preserved across JSB call
!

%const %integer Max Handlers = 10

%record %format SCB Fm (
{0 }    %integer LIM,                   {generic I/O system buffer limit}
{4 }             PTR,                   {generic I/O system char pointer}
{8 }    %short   Breaks,                {<=this value => break char}
                                        { >this value => normal char}  -
{10}    %byte    Last Put,              {last character in previous buffer}
{11}             Ref Count,             {no of uses of SCB at present}
{12}  ( %integer Break Handler,         {called on special output characters}
{16}             Buffer   Handler,      {called on buffer overflow}
{20}             Position Handler,      {called on complex conditioning ops}
{24}             Close    Handler,      {called to close the file}
{28}             Complete Handler,      {COMPLETE OUTPUT or something...}
{32}             Reset    Handler %or   {RESET function}
{12}    %integer %array Handlers ( 1: Max Handlers ) ),
{52}    %record(Buff Fm) ThisB,         {buffer currently in use for input}
{56}  ( %record(*) %name Rab, Fab %or
{56}    %integer User1, User2, User3 %or
{56}    %record(Fd Fm) %name Fd ),
{**}    %short   Flags,
{**}    %integer Position,              {position of current buffer or <0}
{**}    %record(Buff Fm) AllocB,        {buffer allocated if any}
{**}                     NameB )        {object name buffer if any}

!
! Flags for SCBs
!
%const %integer SCB Flag Abandoned      = 1<<0   {at least one ABANDON call}

!
! handler offsets within the SCB
! (used by in-line assembler)
!
%const %integer Break      H = 12,
                Buffer     H = 16,
                Position   H = 20,
                Close      H = 24,
                Complete   H = 28

%const %integer ThisB Ad     = 52,
                RAB   Ad     = 56, User1 Ad = 56,
                FAB   Ad     = 60, User2 Ad = 60,
                                   User3 Ad = 64

!
! Some useful procedure specs
!

%external %record(SCB Fm) %map %spec New SCB %alias "IMP___NEW_SCB" (
          %integer Buffer If Any                                    )

%external %record(SCB Fm) %name %spec In  Scb %alias "IMP___IN_SCB"
%external %record(SCB Fm) %name %spec Out Scb %alias "IMP___OUT_SCB"

%external %routine %spec Set Object Name %alias "IMP___SET_OBJECT_NAME" -
                                       ( %record(SCB Fm) %name S,
                                         %string(*)      %name T )

