conststring  (1) snl = "
"

constinteger  amdahl = 369, xa = 371
INCLUDE  "TARGET"


if  TARGET = 2900 start   { machine specific constants }
      constinteger  MAX LINE = 132
      conststringname  DATE = X'80C0003F'
      conststringname  TIME = X'80C0004B'
      constinteger  SEG SHIFT = 18
finish   { 2900 }
!
if  TARGET = 370 start 
      constinteger  SEG SHIFT = 16
finish 
!
if  TARGET = XA or  TARGET = AMDAHL start 
      constinteger  SEG SHIFT = 20
finish 
!
unless  TARGET = 2900 start 
      constinteger  com seg = 31
      conststringname  DATE = COM SEG << SEG SHIFT + X'3B'
      conststringname  TIME = COM SEG << SEG SHIFT + X'47'
      constinteger  MAX LINE = 80  { for convenience on terminals }
finish 
!* COMMUNICATIONS RECORD FORMAT - EXTANT FROM CHOPSUPE 20A ONWARDS *
!
! This is the Supervisor Communications Record Format, defined in EMAS
! 2900 Supervisor Note 15.
if  TARGET = 2900 start 
      recordformat  c 
COMF(integer  OCPTYPE, IPLDEV, SBLKS, SEPGS,
      NDISCS, DLVNADDR, GPCTABSIZE, GPCA,
      SFCTABSIZE, SFCA, SFCK, DIRSITE,
      DCODEDA, SUPLVN, TOJDAY, DATE0,
      DATE1, DATE2, TIME0, TIME1,
      TIME2, EPAGESIZE, USERS, CATTAD,
      SERVAAD, byteinteger  NSACS, RESV1, SACPORT1, SACPORT0, 
      NOCPS, RESV2, OCPPORT1, OCPPORT0, 
      integer  ITINT,
      CONTYPEA, GPCCONFA, FPCCONFA, SFCCONFA, 
      BLKADDR, RATION, SMACS, TRANS,
      longinteger  KMON, integer  DITADDR, SMACPOS,
      SUPVSN, PSTVA, SECSFRMN, SECSTOCD, 
      SYNC1DEST, SYNC2DEST, ASYNCDEST, MAXPROCS,
      KINSTRS, ELAPHEAD, COMMSRECA, STOREAAD,
      PROCAAD, SFCCTAD, DRUMTAD, TSLICE,
      FEPS, MAXCBT, PERFORMAD,
      INTEGER  SP0,SP1,SP2,SP3,SP4,SP5,
      integer  LSTL, LSTB, PSTL,
      PSTB, HKEYS, HOOT, SIM,
      CLKX, CLKY, CLKZ, HBIT,
      SLAVEOFF, INHSSR, SDR1, SDR2,
      SDR3, SDR4, SESR, HOFFBIT,
      BLOCKZBIT, BLKSHIFT, BLKSIZE, END)
finish  else  start 
      recordformat  C 
COMF(integer  OCPTYPE, SLIPL, TOPS, SEPGS,
      NDISCS, NSLDEVS, DLVNADDR, DITADDR,
      SLDEVTABAD, STEER INT, DIRSITE, DCODEDA,
      exSUPLVN, TOJDAY, DATE0, DATE1,
      DATE2, TIME0, TIME1, TIME2,
      PAGESIZE, USERS, CATTAD, SERVAAD,
      NOCPS, ITINT, RATION, TRANS,
      longinteger  KMON, integer  SUPVSN, SECSFRMN,
      SECSTOCD, SYNC1DEST, SYNC2DEST, ASYNCDEST,
      MAXPROCS, KINSTRS, ELAPHEAD, COMMSRECA,
      STOREAAD, PROCAAD, TSLICE, FEPS,
      MAXCBT, PERFORMAD, END)
finish 
!*
!
if  TARGET = 2900 start 
recordformat  file inff(string (11)NAME,
      integer  SD,halfinteger  PGS, H0,
      byteinteger  CODES, CODES2, DAYNO, USE,
      OWNP, EEP, PHEAD, ARCH,
      byteinteger  CCT, SSBYTE, halfinteger  PREFIX)
finish  else  start 
recordformat  file inff(string (11)NAME, integer  SD,
      shortinteger  PGS, H0,
      byteinteger  CODES, CODES2, DAYNO, USE,
         OWNP, EEP, PHEAD, ARCH,
         CCT, SSBYTE, shortinteger  PREFIX)
finish 
recordformat  pe(integer  dest,srce,p1,p2,p3,p4,p5,p6)


if  TARGET # 2900 start 
RECORDFORMAT  FINFF((INTEGER  NKB, RUP, EEP, APF, USE, ARCH, FSYS, CONSEG,
      CCT, CODES,  DAYNO, CODES2,
       SSBYTE or  INTEGERARRAY  i(0:12)),STRING (6)OFFER)
finish  else  start 
RECORDFORMAT  FINFF(INTEGER  NKB, RUP, EEP, APF, USE, ARCH, FSYS, CONSEG,
      CCT, CODES, BYTEINTEGER  SP1, DAYNO, SP2, CODES2,
       INTEGER  SSBYTE,STRING (6)OFFER)
finish 
!*
recordformat  daf((integer  blksi, nblks, last blk, spare,
   integerarray  da(1 : 512) or  integer  sparex, integerarray  i(0:514)))
!
if  TARGET = 2900 start 

externalstringfnspec  derrs(integer  flag)
externalintegerfnspec  ddap(integerfn  a(integer  a,b,c), integer  act, addr)
externalintegerfnspec  dsfi(string  (6) user,
   integer  fsys, integer  type, set, address)
externalroutinespec  dstop(integer  reason)
!%externalintegerfnspec change context
externalintegerfnspec  d check bpass(string (6) user,
 string (63) bpass, integer  fsys)
externalintegerfnspec  dpon3(string (6) user,
   record (pe)name  p, integer  invoc, msgtype, outno)
externalroutinespec  dpoff(record (pe)name  p)
externalroutinespec  dtoff(record (pe)name  p)
externalintegerfnspec  dgetda(string  (6) user,
   string  (11) file, integer  fsys, address)
externalintegerfnspec  dchsize(string  (6) user,
   string  (11) file, integer  fsys, newsize)
externalroutinespec  get av fsys(integername  n,
   integerarrayname  a)
externalintegerfnspec  dfsys(string  (6) user, integername  fsys)
externalintegerfnspec  dpermission( c 
   string  (6) owner, user, string  (8) date,
   string  (11) file, integer  fsys, type, adrprm)
externalintegerfnspec  ddestroy(string  (6) user,
   string  (11) file, string  (8) date, integer  fsys, type)
externalintegerfnspec  ddisconnect(string (6) user, string (11) file  c 
      integer  fsys, destroy)
externalintegerfnspec  drename(string  (6) user,
   string  (11) oldname, newname, integer  fsys)
externalintegerfnspec  dfstatus(string  (6) user,
   string  (11) file, integer  fsys, act, value)
externalintegerfnspec  dfilenames(string  (6) user,
   record (file inff)arrayname  inf,
   integername  filenum, maxrec, nfiles, integer  fsys, type)
externalintegerfnspec  dfinfo(string  (6) user,
   string  (11) file, integer  fsys, address)
externalintegerfnspec  dcreate(string  (6) user,
   string  (11) file, integer  fsys, nkb, type)
externalintegerfnspec  dconnect(string  (6) user,
   string  (11) file, integer  fsys, mode, apf,
   integername  seg, gap)
externalintegerfnspec  dmessage(string  (6) user,
   integername  l, integer  act, fsys, adr)
externalintegerfnspec  dtransfer( c 
   string  (6) user1, user2,
   string  (11) file, newname, integer  fsys1, fsys2, type)
externalintegerfnspec  dnewgen(string (6) user, string (11) file, c 
   newgen of file, integer  fsys)

finish  else  start 

EXTERNALINTEGERFNSPEC  DCHECKBPASS(STRINGNAME  USER, BPASS, INTEGERNAME  FSYS)

EXTERNALINTEGERFNSPEC  DCHSIZE(STRINGNAME  FILE INDEX, FILE, INTEGERNAME  FSYS, NKB)
! The physical size of file FILE belonging to file index FILE INDEX on
! disc-pack FSYS (or -1) is altered (if necessary) so that its new size
! is NEWKB Kbytes.  The size may not be reduced to zero.  The file may
! be connected in the caller's virtual memory (only).  If the caller is
! not the file owner, he must either have W access to the file index or
! be privileged.

!%EXTERNALINTEGERFNSPEC CHANGE CONTEXT

EXTERNALINTEGERFNSPEC  DCONNECT(STRINGNAME  FILE INDEX, FILE, INTEGERNAME  FSYS, MODE, SEG, GAP)

EXTERNALINTEGERFNSPEC  DCREATE(STRINGNAME  FILE INDEX, FILE, INTEGERNAME  FSYS, NKB, TYPE, DA)
! A file of name FILE is created, in file index FILE INDEX on disc-pack
! FSYS, of E Epages, where E is the smallest number of Epages containing
! NKB Kbytes.  The maximum size of file allowed is 16 Mbytes.  Subsystems
! requiring larger files should arrange that they be made up of subfiles
! comprising files created by this procedure.
!
! Bits in TYPE may be set:
!
!     2**0     For a temporary file (destroyed when the creating process
!              stops if the file was connected, or at System start-up).
!
!     2**1     For a very temporary file (destroyed when the file is
!              disconnected).
!
!     2**2     For a file which is to be zeroed when created.
!
!     2**3     To set "CHERISHed" status for the file.
!
!
! Temporary files are made into ordinary files (that is, the "temporary"
! attribute is removed) on being RENAMEd, OFFERed, TRANSFERred or
! PERMITted, and also explicitly by an appropriate call on procedure
! DFSTATUS.
!
! The disc address of the first section of the file is returned in DA.

EXTERNALINTEGERFNSPEC  DDESTROY(STRINGNAME  FILE INDEX, FILE, DATE, INTEGERNAME  FSYS, TYPE)
! File FILE belonging to file index FILE INDEX on disc-pack FSYS, is
! destroyed.  TYPE should be set to 1 to destroy a file from archive
! storage, otherwise it should be set to zero.  When TYPE=1, DATE should
! be set to the archive date.  DATE is ignored if TYPE=0.
!
! The procedure fails if 'OWNP' for the file is either zero (no access)
! or 8 (do not destroy).

EXTERNALINTEGERFNSPEC  DDISCONNECT(STRINGNAME  FILE INDEX, FILE, INTEGERNAME  FSYS, DSTRY)
! The file of name FILE belonging to file index FILE INDEX on disc-pack
! FSYS is disconnected from the caller's virtual memory.  Parameter
! DESTROY should be set either to 0 or 1.  If set to 1 the file will be
! destroyed, provided that it belongs to the process owner (not necessary
! if the process is privileged) and the "use-count" for the file is zero
! after disconnection.  Otherwise the  parameter is ignored.

EXTERNALINTEGERFNSPEC  DFILENAMES(STRINGNAME  GROUP, INTEGERNAME  FILENO, MAXREC, C 
  NFILES, FSYS, TYPE, RECORD (file inff)ARRAYNAME  INF)
! This procedure delivers, in the record array INFS (which should be
! declared (0:n)), a sequence of records describing the on-line files
! (for TYPE=0), archived files (for TYPE=1) or backed-up files (for
! TYPE=2) belonging to group GROUP on fsys FSYS (or -1 if not known).
!
! The procedure works differently for on-line files (TYPE=0) and
! off-line files (TYPE>0).
!
! For on-line files, the records returned give the names of files and
! groups belonging to GROUP but not the contents of any of these groups.
! DFILENAMES must be called again with GROUP set to the name of the
! subgroup to determine these.  Thus
!
!        FLAG = DFILENAMES(ERCC99,...
!
! returns the names of files and groups in ERCC99's main file index.  If
! there is a group called PROJ:, the contents of it can be found with
!
!        FLAG = DFILENAMES(ERCC99.PROJ:,...
!
! The group separator, :, may be omitted if desired.
!
! Note that the usage of . and : (USEP and GSEP) is reversed in EMAS3.
! The UINF fields USEP, USEPCH etc allow utilities to be written which
! will work for both EMAS2 and EMAS3.
!
! MAXREC is set by the caller to specify the maximum number of records he
! is prepared to accept in the array INFS, and is set by Director to be
! the number of records returned.
!
! NFILES is set by Director to be the number of files actually held on
! on-line storage or on archive storage, depending on the value of TYPE.
!
! FILENO is not normally used.  [ If the top bit of MAXREC is set, FILENO
! is used in the same way as for off-line files, described below ]
!
! The format of the records returned in INFS is
!
!        %string(11)NAME,  %integer SPARE1, KBYTES,
!        %byteinteger ARCH, CODES, CCT, OWNP,
!           EEP, USE, CODES2, SSBYTE, SPARE2, PHEAD, DAYNO, GROUP
!
!        ( 32 bytes )
! PHEAD is non-zero if the file or group has been permitted itself to a
! user or user group.
! GROUP is non-zero if NAME is the name of a group.
!
! For off-line files, TYPE = 1 or 2, GROUP will normally be be the name
! of a file index eg ERCC99 or ERCC99{UTILS} when all the names in the
! index will be returned.  If an actual group name is given eg
!
!        ERCC99.PROJ:
!
! then only names of the form
!
!        ERCC99.PROJ:name
!
! are returned.  MAXREC and NFILES are used in the same way as above.
!
! Filenames are stored in chronological order of archive (or backup) date,
! youngest first.  FILENO is set by the caller to specify the "file-number"
! from which names are to be  returned, zero representing the most recently
! archived file.  Thus the caller can conveniently receive subsets of names
! of a very large number of files.
!
! The format of the records returned in INFS is
!
!        %string(11)NAME,  %integer KBYTES,
!        %string(8)DATE,  %string(6)TAPE,
!        %halfinteger PREFIX, CHAPTER,
!        %byteinteger EEP, PHEAD, SPARE, COUNT
!
!        ( 40 bytes )
! To allow the full filenames to be reconstructed, the array INFS, in
! general, contains some records which hold group names.  Records refering
! to filenames can be distinguished by the fact that KBYTES > 0.  If PREFIX
! is > 0, the name is a member of a group whose name is given in the
! record INFS(PREFIX).  The chain can be followed back until a record
! with a zero PREFIX field is found.
!
! Note.  MAXREC does not give the number of filenames returned but the
! number of records in INFS.
!
! TAPE and CHAPTER are returned null to unprivileged callers.

EXTERNALINTEGERFNSPEC  DFINFO(STRINGNAME  FILE INDEX, FILE, INTEGERNAME  FSYS, C 
  STRINGNAME  S, INTEGERARRAYNAME  I)
! This procedure returns detailed information about the attributes of
! file or group FILE belonging to file index FILE INDEX on disc-pack
! FSYS, in a record written to address ADR.
!
! A caller of the procedure having no permitted access to the file
! receives an error result of 32, as though the file did not exist.
!
! The format of the record returned is:
!
recordformat  DFINFOF((integer  NKB, RUP, EEP, APF,
      USE, ARCH, FSYS, CONSEG, CCT, CODES,
      byteinteger  SP1, DAYNO, SP2, CODES2,
      integer  SSBYTE or  INTEGERARRAY  i(1:12)), string (6)OFFER)
!
! where
! NKB       the number of Kbytes (physical file size)
!           zero indicates a group name
! RUP       the caller's permitted access modes
! EEP       the general access permission
! APF       1-4-4 bits, right-justified, giving respectively the Execute,
!           Write and Read fields of APF, if the file is connected in
!           this VM
! USE       the current number of users of the file
! ARCH      the value of the archive byte for the file (see procedure
!           DFSTATUS)
! FSYS      disc-pack number on which the file resides
! CONSEG    the segment number at which the file is connected in the
!           caller's VM, zero if not connected  
! CCT       the number of times the file has been connected since this
!           field was last zeroed (see procedure DFSTATUS)
! CODES     information for privileged processes 
! SP1       spare
! DAYNO     Day number when file last connected
! SP2       spare
! CODES2    information for internal use 
! SSBYTE    information for the subsystem's exclusive use
! OFFER     the username to which the file has been offered, otherwise
!           null

EXTERNALINTEGERFNSPEC  DFLAG(INTEGERNAME  FLAG, STRINGNAME  TXT)

EXTERNALINTEGERFNSPEC  DFSTATUS(STRINGNAME  FILE INDEX, FILE, INTEGERNAME  FSYS, ACT, VALUE)
! This procedure is supplied to enable the attributes of file FILE
! belonging to file index FILE INDEX on disc-pack FSYS to be modified,
! as follows.
!
! Parameter VALUE is for use by the archive/backup program (ACT=13),
! and by the subsystem (ACT=18), otherwise it should be set to zero.
!
! ACT                 ACTION
!
!  0      HAZARD      Remove CHERISHed attribute
!
!  1      CHERISH     Make subject to automatic System back-up procedures
!                     Note: If the file is one of
!                        SS#DIR, SS#OPT or SS#PROFILE
!                     then the 'archive-inhibit' bit is also set.
!                     Similarly, the 'archive-inhibit' bit is
!                     cleared by HAZARD for these files.
!
!  2      UNARCHIVE   Remove the "to-be-archived" attribute
!
!  3      ARCHIVE     Mark the file for removal from on-line to archive
!                     storage.
!
!  4      NOT TEMP    Remove the "temporary" attribute.
!
!  5      TEMPFI      Mark the file as "temporary", that is, to be
!                     destroyed when the process belonging to the file
!                     owner stops (if the file is connected at that
!                     time), or at system start-up.
!
!  6      VTEMPFI     Mark the file as "very temporary", that is, to be
!                     destroyed when it is disconnected from the owner's
!                     VM.
!
!  7      NOT PRIVATE May now be written to magnetic tape either for
!                     back-up or archive.  May be called only by
!                     privileged programs.
!
!  8      PRIVATE     Not to be written to magnetic tape either for
!                     back-up or archive.  May be called only by
!                     privileged programs.
!
!  9      SET CCT     Set the connect count for the file to VALUE.
!
! 11      ARCH        Operation 1 (PRIVILEGED).
!                     Set currently-being-backed-up bit (bit 2**1 in
!                     ARCH byte), unless the file is currently connected
!                     in write mode, when error result 52 is given.
!
! 12      ARCH        Operation 2 (PRIVILEGED).
!                     Clear currently-being-backed-up bit (2**1) and
!                     has-been-connected-in-write-mode bit (2**0).
!
! 14      ARCH        Operation 4 (PRIVILEGED).
!                     Clear the UNAVAilable and privacy VIOLATed bits in
!                     CODES.  Used by the back-up and archive programs
!                     when the file has been read in from magnetic tape.
!
! 15      CLR USE     Clear file use-count and WRITE-CONNECTED status
!                     (PRIVILEGED).
!
! 16      CLR NOARCH  Clear archive-inhibit bit in CODES.   PRIVILEGED -
!                                                           for System
!
! 17      SET NOARCH  Set archive-inhibit bit in CODES.     Library use
!
! 18      SSBYTE      Set SSBYTE to be the bottom 8 bits of VALUE (byte
!                     for a subsystem's exclusive use).
!
! 19      ARCH        Operation 5 (PRIVILEGED).
!                     Set the WRCONN bit in CODES2.  Used to prevent any
!                     user connecting the file in write mode during
!                     back-up or archive.
!
! 20      ARCH        Operation 6 (PRIVILEGED).
!                     Clear the WRCONN bit in CODES2.  Used when back-up
!                     is complete.
!
! 21      DAYNO       Set DAYNO to bottom 8 bits of VALUE
EXTERNALINTEGERFNSPEC  DFSYS(STRINGNAME  FILE INDEX, INTEGERNAME  FSYS)

EXTERNALINTEGERFNSPEC  DFSYSDATA(INTEGERNAME  FSYS, INTEGERARRAYNAME  DATA)

EXTERNALINTEGERFNSPEC  DGETDA(STRINGNAME  FILE INDEX, FILE, INTEGERNAME  FSYS, INTEGERARRAYNAME  I)
! This procedure provides the disc addresses of the sections of file FILE
! belonging to file index FILE INDEX on disc-pack FSYS.  Data is written
! from address ADR in the format
!
!     (%integer SECTSI, NSECTS, LASTSECT, %integerarray DA(0:255))
!
! where SECTSI      is the size (in epages) of the sections (except
!                   possibly the final section)
!
!       NSECTS      is the number of sections, and hence the number
!                   of entries returned in array DA
!
!       LASTSECT    is the size (in epages) of the final section
!
! In each entry in the DA array, the top byte contains the FSYS number.

EXTERNALINTEGERFNSPEC  DMESSAGE(STRINGNAME  USER, INTEGERNAME  LEN, ACT, INVOC, FSYS, ADR)

EXTERNALINTEGERFNSPEC  DNEWGEN(STRINGNAME  FILE INDEX, FILE, NEWGEN, INTEGERNAME  FSYS)
! This procedure provides a means of introducing an updated version
! (i.e. a new generation) of file FILE belonging to file index FILE INDEX
! even though it may be connected in other users' virtual memories.
!
! If FILE is not connected in any virtual memory, a call on DNEWGEN is
! equivalent to destroying FILE and then renaming NEWGEN to FILE,
! except that the new version of FILE retains the former FILE's access
! permissions.
!
! If FILE is connected in some virtual memory, then the filename
! NEWGEN "disappears", and any subsequent connection of FILE into
! a virtual memory yields the contents of the new generation formerly
! held in NEWGEN.
!
! When the number of users of a former copy of FILE becomes zero
! (i.e. when it is not connected in any virtual memory), that copy is
! destroyed.

EXTERNALINTEGERFNSPEC  DPERMISSION(STRINGNAME  FILE INDEX, C 
  USER, DATE, FILE, INTEGERNAME  FSYS, TYPE, ADR)
! This procedure allows the caller to set access permissions, or specific
! preventions, for file connection to individual users, groups of users
! or to all users to file FILE belonging to file index FILE INDEX.  It
! also allows a caller to determine the modes (if any) in which he may
! access the file.
!
! TYPE determines the service required of the procedure:
!
!         TYPE         Action
!
!           0          set OWNP (not for files on archive storage)
!           1          set EEP
!           2          put USER into the file list (see "Use of file
!                      access permissions", below)
!           3          remove USER from file list
!           4          return the file list
!           5          destroy the file list
!           6          put USER into the index list (see "Use of file
!                      access permissions", below)
!           7          remove USER from the index list
!           8          return the index list
!           9          destroy the index list
!          10          give modes of access available to USER for FILE
!          11          set EEP for the file index as a whole
!
! TYPEs 0 to 9 and 11 are available only to the file owner and to
! privileged processes.  For TYPE 10, ADRPRM (see below) should be the
! address of an integer into which the access permission of USER to the
! file is returned. If USER has no access to the file, error result 32
! will be returned from the function, as though the file did not exist.
! If the file is on archive storage, TYPE should be set to 16 plus the
! above values to obtain the equivalent effects.
!
! ADRPRM is either the permission being attached to the file, bit
! values interpreted as follows:
!
!         all bits zero    prevent access
!         2**0             allow READ access
!         2**1             allow WRITE access      not allowed for files
!         2**2             allow EXECUTE access    on archive storage
!         2**3             If TYPE = 0, prevent the file from being
!                          destroyed by e.g. DDESTROY, DDISCONNECT (and
!                          destroy).
! or, except for type 10, it is the address of an area into which access
! permission information is to be written
!
!     %recordformat(%integer BYTES RETURNED, OWNP, EEP, SPARE,
!         %record(EF)%array INDIV PRMS(0:15))
!
!       and EF is
!        %recordformat EF(%string(6)USER, %byteinteger PERMISSION)
!
!   where:
!
!   BYTES      indicates the amount of data returned.
!   RETURNED
!
!   OWNP       is the file owner's own permission to the file, or the
!              requesting user's "net" permission if the caller of the
!              procedure is not the file owner (see "Use of file access
!              permissions", below).
!
!   EEP        is the general (all users) access permission to the file
!              ("everyone else's permission").
!
!   UPRM       The PERMISSION values in the sub-records are those
!              for the corresponding users or groups of users denoted by
!              USER.  Up to 16 such permissions may be attached to a
!              file.
!
! Use of file access permissions
!
! The general scheme for permissions is as follows.  With each file
! there are associated:
!
!   OWNP       the permission of the owner of the file to access it
!
!   EEP        everyone else's permission to access it (other than users
!              whose names are explicitly or implicitly attached to the
!              file)
!
!   INDIV PRMS a list of up to 16 items describing permissions for
!              individual users, e.g. ERCC00, or groups of users, e.g.
!              ERCC?? (specifying all usernames of which the first four
!              characters are "ERCC")
!
! In addition, a user may attach a similar list of up to 16 items to
! his file index as a whole and an EEP for the file index.  These
! permissions apply to any file described in the index along with those
! attached to that particular file.
! In determining the mode or modes in which a particular user may access
! a file, the following rules apply:
!
!   1. If the user is the file owner then OWNP applies.
!
!   2. Otherwise, if the user's name appears explicitly in the list for
!      the file, the corresponding permission applies.
!
!   3. Otherwise, if the user's name is a member of a group of users
!      represented by a list item for the file, the corresponding
!      permission applies.
!
!   4. Otherwise EEP applies if greater than zero.
!
!   5. Otherwise, if the user's name appears explicitly in the list for
!      the index, the corresponding permission applies.
!
!   6. Otherwise, if the user's name is a member of a group of users
!      represented by a list item for the index, the corresponding
!      permission applies.
!
!   7. Otherwise, everybody else's permission to the file index applies.
!
! In the event of a user's name appearing more than once (implicitly)
! within groups specified in a single list, the actual list item to be
! selected to give the permission should be regarded as indeterminate.

EXTERNALINTEGERFNSPEC  DPOFF(RECORD (pe)NAME  P)

EXTERNALINTEGERFNSPEC  DPON3(STRINGNAME  USER, RECORD (pe)NAME  P, C 
  INTEGERNAME  INVOC, MSGTYPE, OUTNO)

EXTERNALINTEGERFNSPEC  DRENAME(STRINGNAME  FILE INDEX, OLDNAME, NEWNAME, INTEGERNAME  FSYS)
! File OLDNAME belonging to file index FILE INDEX on disc-pack FSYS is
! renamed NEWNAME.
!
! A file may not be renamed while it is connected in any virtual memory.

EXTERNALINTEGERFNSPEC  DSTOP(INTEGERNAME  REASON)

EXTERNALINTEGERFNSPEC  DSFI(STRINGNAME  FILE INDEX, INTEGERNAME  FSYS, TYPE, C 
  SET, STRINGNAME  S, INTEGERARRAYNAME  I)
! This procedure is used to set or read information in file index FILE
! INDEX (or user record in some cases) on disc-pack FSYS.  TYPE specifies
! which data item is to be referenced (see list below).  SET must be 1
! to write the data item into the index, or 0 to read the item from the
! index.  ADR is the address of an area, which must be available in write
! or read mode, to or from which the data item is to be transferred.
!
! TYPE              Data item                         Data type & size
!
!  0     BASEFILE name (the file to be connected
!        and entered at process start-up)                 string(18)
!
!  1     DELIVERY information (to identify                string(31)
!        slow-device output requested by the
!        index owner)
!
!  2     CONTROLFILE name (a file for use by the
!        subsystem for retaining control information)     string(18)
!
!  3     ADDRTELE address and telephone number of user    string(63)
!
!  4     INDEX USE (may not be reset)
!        Gives (in successive integers from ADR):
!        a) number of files
!        b) number of file descriptors currently in use
!        c) number of free file descriptors
!        d) index size (Kbytes)
!        e) Number of section descriptors (SDs)
!        f) Number of free section descriptors
!        g) Number of permission descriptors (PDs)
!        h) Number of free permission descriptors         integer(x8)
!
!  5     Foreground and background passwords
!        (reading is a privileged operation), a zero
!        value means "do not change"                      integer(x2)
!
!  6     Date last logged-in: (Y-70)<<9 ! (M<<5) !  D  and
!        date last started (non-interactive)  (same)
!        (may not be reset)                               integer(x2)
!
!  7     ACR level at which the process owning this
!        index is to run (may be set only by privileged
!        processes)                                       integer
!
!  8     Director Version (may be set only by privileged
!        processes)                                       integer(x2)
!
!  9     ARCHIVE INDEX USE (may not be reset)
!        Gives (in successive integers from ADR):
!        a) number of archived files
!        b) number of archived Kbytes
!        c) number of backed-up files
!        d) number of backed-up Kbytes
!        e) index size (Kbytes)
!        f) number of file descriptors
!        g) number of free file descriptors
!        h) number of permission descriptors
!        i) number of free permission descriptors         integer(x9)
!
! 10     Stack size (Kbytes)                              integer
!
! 11     Limit for total size of all files in disc
!        storage (Kbytes) (may be set only by privileged
!        processes                                        integer
!
! 12     Maximum file size (Kbytes) (may be set only by
!        privileged processes)                            integer
!
! 13     Current numbers of interactive and batch
!        processes, respectively, for the user (may
!        not be reset)                                    integer(x2)
!
! 14     Process concurrency limits (may be set only
!        by privileged processes).  The three words
!        denote respectively the maximum number of
!        interactive, batch and total processes which
!        may be concurrently running for the user.
!        (Setting the fields to -1 implies using
!        the default values, currently 1, 1 and 1.)       integer(x3)
!
! 15     When bit 2**0 is set, TELL messages to the
!        index owner are rejected with flag 48.           integer
!
! 16     Set Director monitor level (may be set only
!        by privileged processes)                         integer(x2)
!
! 17     Set SIGNAL monitor level (may be set only
!        by privileged processes)                         integer
!
! 18     Initials and surnames of user (may
!        be set only by privileged processes)             string(31)
!
! 19     Director monitor file                            string(11)
!
! 20     Thousands of instructions executed, interactive
!        and batch modes (may be reset only by
!        privileged processes)                            integer(x2)
!
! 21     Thousands of instructions executed (current
!        session only)                                    integer
!
! 22     Thousands of instructions executed in Director
!        procedures (current process session only)
!        (may not be reset)                               integer
!
! 23     Page-turns, interactive and batch modes
!        (may be reset only by privileged processes)      integer(x2)
!
! 24     Page-turns (current process session only)        integer
!
! 25     Thousands of bytes output to slow-devices
!        (local or remote) (may be reset only by
!        privileged processes)                            integer
!
! 26     Thousands of bytes input from slow-devices
!        (local or remote) (may be reset only by
!        privileged processes)                            integer
!
! 27     Milliseconds of OCP time used, interactive
!        and batch modes (may be reset only by
!        privileged processes)                            integer(x2)
!
! 28     Milliseconds of OCP time used (current
!        session only)                                    integer
!
! 29     Seconds of interactive terminal connect time
!        (may be reset only by privileged processes)      integer
!
! 30     No. of disc files, total disc Kbytes, no. of
!        cherished files, total cherished Kbytes, no.
!        of temporary files, total temporary Kbytes
!        (cannot be reset)                                integer(x6)
!
! 31     No. of archive files, total archive Kbytes       integer(x2)
!
! 32     Interactive session length in minutes            integer
!        0 or 5 <= x <= 240
!
! 33     Funds                                            integer
!
! 34     The FSYS of the Group Holder of the index        integer
!        owners funds, if he has a GH
!
! 35     Test BASEFILE name                               string(18)
!
! 36     Batch BASEFILE name                              string(18)
!
! 37     Group Holder of funds for scarce resources       string(6)
!
! 38     Privileges                                       integer
!
! 39     Default LP                                       string(15)
!
! 40     Dates passwords last changed                     integer(x2)
!        (may not be reset)
!
! 41     Password data                                    integer(x8) 
!
! 42     Get accounting data                              integer(x17)
!
! 43     Mail count                                       integer
!        (may be reset only by privileged processes)
!
! 44     Supervisor                                       string(6)
!
! 45     Secure record                          about 512 bytes
!
! 46     Gateway access id                                string(15)
!
! 47     File index attributes                            byte
!
! 48     User type                                        byte

EXTERNALINTEGERFNSPEC  DTOFF(RECORD (pe)NAME  P)

EXTERNALINTEGERFNSPEC  DTRANSFER(STRINGNAME  FILE INDEX1, FILE INDEX2, FILE1, C 
  FILE2, INTEGERNAME  FSYS1, FSYS2, TYPE)
! This procedure transfers FILE1 belonging to file index FILE INDEX1 on
! FSYS1 to the ownership of file index FILE INDEX2 on FSYS2 under name
! FILE2.
!
! TYPE = 0 'accepts' a file which has been 'offered'. This call
!          is non-privileged.
!        1 a privileged call to transfer a file.
!        2 like 1, but, in addition, forces a re-allocation of the
!          disc space.
!        3 a privileged call to copy the file.
!        4 as 3 but works even when file connected W (for test purposes)


EXTERNALINTEGERFNSPEC  DVALIDATE(INTEGERNAME  ADR, LEN, RW)
finish 

constinteger  not assigned = x'80808080'
constinteger  yes = 1
constinteger  file header size = 32
constinteger  already exists = 16;      !DIRECTOR FLAG
constinteger  r = b'00000001';          !READ PERMISSION
constinteger  w = b'00000010';          !WRITE PERMISSION
constinteger  shared = b'00001000';     !ALLOW OTHERS ACCESS
constinteger  link list entries = 1000
constinteger  link list entry size = 28
constinteger  max fep = 7;            !MAXIMUM FEPS CURRENTLY ALLOWED.
constinteger  max queues = 255;         !MAX QUEUES ALLOWED IN CONFIGURATION
constinteger  max remotes = 128;        !MAX REMOTES ALLOWED IN CONFIGURATION
constinteger  max streams = 255;        !MAX STREAMS ALLOWED IN CONFIGURATION
constinteger  queue entry size = 148;   !NUMBER OF BYTES IN A QUEUE DESCRIPTOR
constinteger  remote entry size = 172;   !NUMBER OF BYTES IN A REMOTE DESCRIPTOR
!NOTE THIS INCLUDES SPACE FOR UP TO 8 FEPS, ADJUST FOR FURTHER IN GROUPS OF 4.
constinteger  stream entry size = 200;  !NUMBER OF BYTES IN A STREAM DESCRIPTOR
constinteger  name entry size = 24
constinteger  qdescriptors = 15
constinteger  rdescriptors = 5
constinteger  sdescriptors = 13
conststring  (11) temp outfile = "TEMPCFILE"
conststring (11) link list name = "SPOOLLINK"
conststring  (15) array  qd(1 : q descriptors) =      c 
"QUEUE=",
"USER=",
"DELIVERY=",
"START=",
"PRIORITY=",
"TIME=",
"OUTPUTLIMIT=",
"FORMS=",
"MODE=",
"COPIES=",
"RERUN=",
"MAXLENGTH=",
"MAXACR=",
"QBY=",
"RESOURCELIMIT="
constbyteintegerarray  qdt(1 : q descriptors) =              c 
15,6,31,0,5,0,0,0,3,0,3,0,0,15,0;         !A 0 SPECIFIES PARAMETER IS AN INTEGER ELSE LENGTH OF STRING
conststring  (15) array  rd(1 : rdescriptors)= c 
"REMOTE=",
"STATUS=",
"FEP=",
"NETADDRESS=",
"PASSWORD="
constbyteintegerarray  rdt(1 : rdescriptors) = c 
15,12,0,255,7;                             !A 0 SPECIFIES PARAMETER IS AN INTEGER ELSE LENGTH OF STRING
conststring  (15) array  sd(1 : sdescriptors) =     c 
"STREAM=",
"REMOTE=",
"STATUS=",
"DEVICETYPE=",
"DEVICENO=",
"LIMIT=",
"FORMS=",
"LOWESTPRIORITY=",
"TYPE=",
"QUEUE=",
"HEADER=",
"UNITSIZE=",
"UNITNAME="
constbyteintegerarray  sdt(1 : sdescriptors) =           c 
15,15,11,2,0,0,0,5,6,255,15,0,7;        !A 0 SPECIFIES PARAMETER IS AN INTEGER ELSE LENGTH OF STRING
conststring  (13) array  stream types(0 : 5) =    c 
"OUTDEV",
"$OUTDEV",
"INDEV",
"JOB",
"PROC",
"$PROC"
conststring  (3) array  modes(0 : 2) =         c 
"ISO",
"EBC",
"BIN"
conststring  (15) array  remote status(0 : 3) =   c 
"CLOSED",
"OPEN",
"PRELOGON",
"PRELOGONTIED"
conststring  (15) array  stream status(0 : 1) =   c 
"UNALLOCATED",
"ALLOCATED"
conststring  (15) array  header types(1 : 3) =       c 
"LINEPRINTER",
"TAPEPUNCH",
"CARDPUNCH"
conststring  (2) array  device type(0 : 15) =   c 
"NA","PP","PR","CP","CR","MT","LP","GP","OP","MP","DO",
"NA","CT","SU","FE","NA"
conststring  (5) array  priorities(1 : 5) =       c 
"VLOW",
"LOW",
"STD",
"HIGH",
"VHIGH"


ownbyteintegerarray  temp qs name(0 : 2*name entry size -1) =  c 
           0(2*name entry size);       !AREA FOR DEFAULT CONFIGURATION OF 2 QUEUES
ownbyteintegerarray  temp rmts name(0 : name entry size -1) = c 
           0(name entry size);        !DITTO FOR ONE REMOTE
ownbyteintegerarray  temp strms name(0 : name  entry size-1) =   c 
           0(name  entry size);        !DITTO FOR ONE STREAM


ownbyteintegerarray  temp qs(0 : 2*queue entry size -1) =  c 
           0(2*queue entry size);       !AREA FOR DEFAULT CONFIGURATION OF 2 QUEUES
ownbyteintegerarray  temp rmts(0 : remote entry size -1) = c 
           0(remote entry size);        !DITTO FOR ONE REMOTE
ownbyteintegerarray  temp strms(0 : stream entry size-1) =   c 
           0(stream entry size);        !DITTO FOR ONE STREAM

recordformat  pointers f(integer  queues, queue entry size, queue displ,
    queue name displ, streams, stream entry size, stream displ,
    stream name displ, remotes, remote entry size, remote displ,
    remote name displ, ftp stations, station entry size,
    ftp station displ)



if  TARGET = 2900 start 
recordformat  queuef(string  (15) name,
   halfintegerarray  streams(0 : 15),
   string  (7) default user,
   string  (31) default delivery,
   integer  default start, default priority, default time,
   default output limit, default forms, default mode, default copies,
   default rerun, length, head, max length, maxacr,
   halfinteger  q by, general access, integer  resource limit,
   amount)
finish  else  start 
recordformat  queuef(string  (15) name,
   (shortintegerarray  streams(0 : 15) or  shortintegerarray  lines(0 : 15)),
   string  (7) default user,
   string  (31) default delivery,
   integer  default start, default priority, default time,
   default output limit, default forms, default mode, default copies,
   default rerun, length, head, max length, maxacr,
   shortinteger  q by, general access, integer  resource limit,
   amount)
finish 



recordformat  remotef(string  (15) name,
   integer  status, lowest stream, highest stream, fep,  old fep,
   prelog fep, prelog, timeout, polling,  command lock,
   byteinteger  unused1, unused2, n add type,
   (byteinteger  n add len, byteintegerarray  network address(0 : 63) c 
    or  string (64) TS address),
   byteintegerarray  fep route value(0 : max fep),string (31) description,
   string (7) password)



if  TARGET = 2900 start 
recordformat  stream f(string (15) name, string (7) unit name,
  integer  q no, halfintegerarray  queues(0 : 15),
  integer  status, bytes sent, bytes to go, block, part block,
           document, spare1, spare2, spare3,
  byteinteger  service, user abort, unit size, fep,
  integer  remote, abort retry count, offset,
           (integer  in comms stream or  integer  comms stream),
           integer  out comms stream,
           (integer  in stream ident or  integer  ident),
           integer  out stream ident,
 (integer  limit, account,
  byteinteger  device type, device no, forms, lowest priority,
               header type, header number, batch enable, invoc,
  string (55) unused or  integer  transfer status, tcc subtype,
           in block addr, out block addr,
  byteinteger  activity, station type, station ptr, suspend,
               in stream status, out stream status,
               timer, output buffer status, output transfer pending, sp1,
  halfinteger  kbmoved,
  integer  xspare1, xspare2, xspare3,
  record (pe) output transfer record))
finish  else  start 

recordformat  stream f(string (15) name, string (7) unit name,
  integer  q no, shortintegerarray  queues(0 : 15),
  integer  status, bytes sent, bytes to go, block, part blocks,
           document, string (6) barred user, (byteinteger  reallocate or  byteinteger  logical dap),
           integer  bin offset,  byteinteger  service, user abort, unit size, fep,
  integer  remote, byteinteger  abort retry count, connect fail expected,
           TS call accept,spb, integer   offset,
           (integer  in comms stream or  integer  comms stream),
           integer  out comms stream,
           (integer  in stream ident or  integer  ident),
           integer  out stream ident,
 (integer  limit, account,
  byteinteger  device type, device no, forms, lowest priority,
               header type, header number, batch enable, invoc,
  string (55) unused or  integer  transfer status, tcc subtype,
           in block addr, out block addr,
  byteinteger  activity, station type, station ptr, suspend,
               in stream status, out stream status,
               timer, output buffer status, output transfer pending, 
               new ftp data record,sp2,sp3,
  integer  aux document, pre abort status, bytes transferred,
  record (pe) output transfer record))
finish 




recordformat  fhf(integer  end, start, size, type, remotes,
   datetime, queues, streams)



   ownstring  (255) ns1, ns2

externalintegerfnspec  pack date and time(string  (8) date, time)
externalstringfnspec  itos(integer  i)
externalintegerfnspec  stoi(stringname  s)



externalroutine  read spool config( c 
   string  (6) infile owner, outfile owner,
   integer  in fsys, out fsys,
   string  (11) infile, outfile,
   integername  queues, qconad, remotes, rconad, streams,
   sconad, qnconad,snconad,rnconad, link list conad)
!***********************************************************************
!*                                                                     *
!*  PURPOSE OF THIS ROUTINE IS TO READ IN A SPOOLER CONFIGURATION FILE *
!*  WHICH IS IN TEXT FORMAT AND CREATE A FILE FOR PASSING ON TO THE    *
!*  SPOOLER PROCESS AS A DATA BASE.                                    *
!*                                                                     *
!***********************************************************************

stringfnspec  errs(integer  flag)
record (fhf)name  file header
record (queuef)name  queue entry
record (remotef)name  remote entry
record (streamf)name  stream entry
recordformat  nf(string (15) name, string (7) user)
record (nf)arrayformat  qaf(1:max queues)
record (nf)arrayformat  saf(1:max streams)
record (nf)arrayformat  raf(1:max remotes)
record (nf)arrayname  queue name entries
record (nf)arrayname  stream name entries
record (nf)arrayname  remote name entries
record (pointers f)name  pointers

string  (255) line, temps, temp1, temp2
integer  text pointer, text end, seg, gap, flag, i, j, k, l,
      value, conad, config size, headers, ptr conad
switch  qswt(1 : q descriptors), rswt(1 : rdescriptors),
   sswt(1 : sdescriptors)

stringfn  errs(integer  flag)
  integer  i; string (63) error
  if  TARGET = 2900 then  result  = derrs(flag) else  START 
    i = dflag(flag,error)
    result  = error
  FINISH 
end 

   routine  read line(stringname  line)
!***********************************************************************
!*                                                                     *
!*  READS A LINE OF TEXT TERMINATED BY A NEWLINE. SKIPPING LEADING     *
!*  NEWLINES AND SPACES. IGNORES SPACES IN LINE                        *
!*  WHEN TEXT POINTER = TEXT END (END OF FILE). RETURNS A NULL LINE IF *
!*  END OF FILE.                                                       *
!*                                                                     *
!***********************************************************************
   integer  sym, comment
      comment = 0
      line = ""
      text pointer = text pointer+1 c 
         while  text pointer < text end c 
         and  (byteinteger(text pointer) = ' ' c 
         or  byteinteger(text pointer) = nl)
      return  if  text pointer = text end
      sym = byteinteger(text pointer);  !READ A SYMBOL
      text pointer = text pointer+1
      while  sym # nl and  text pointer < text end cycle 
         line = line.to string(sym) unless  (sym = ' ' and  comment = 0);!NOT SPACES EXCEPT WITHIN COMMENT
         comment = 1 if  sym = '!'
         sym = byteinteger(text pointer)
         text pointer = text pointer+1
      repeat 
   end ;                                !OF ROUTINE READ LINE



   routine  create and connect(string  (6) name,
      string  (11) outfile, integer  fsys, size, mode,
      integername  conad)
!***********************************************************************
!*                                                                     *
!*  DESTROYS A FILE IF IT EXISTS. THEN CREATES A NEW FILE AND THEN     *
!*  CONNECTS IT. CONAD = 0 IF UNSUCCESSFUL SIZE IS GIVEN IN BYTES.     *
!*                                                                     *
!***********************************************************************
   integer  flag, seg, gap, ada
   string  (31) filename
      conad = 0;                        !INITIALLY ZERO
      filename = name.".".outfile
      flag = ddestroy(name,outfile,"",fsys,0);    !INCASE IT ALREADY EXISTED
      if  TARGET # 2900 then  flag = dcreate(name,outfile,fsys,(size+1023)>>10,4,ada) c 
       else  flag = dcreate(name,outfile,fsys,(size+1023)>>10,4)
                                        !CREATE FILE AND ZERO.
      if  flag = 0 start 
         seg = 0;  gap = 0
         if  TARGET # 2900 then  flag = dconnect(name,outfile,fsys,mode,seg,gap) c 
         else  flag = dconnect(name,outfile,fsys,mode,0,seg,gap)
         if  flag = 0 then  conad = seg<<seg shift c 
            else  print string("CONNECT ".filename." FAILS ". c 
            errs(flag).snl)
      finish  else  print string("CREATE ".filename." FAILS ". c 
         errs(flag).snl)
   end ;                                !OF ROUTINE CREATE AND CONNECT


!THE FOLLOWING VALUES ARE PASSED BACK TO THE CALLING ROUTINE
   queues = 0;                          !THE NUMBER OF QUEUES IN THE CONFIGURATION
   qconad = 0;                          !THE CONNECT ADDRESS OF THE QUEUE TABLE
   remotes = 0;                         !THE NUMBER OF REMOTES IN THE CONFIGURATION
   rconad = 0;                          !THE CONNECT ADDRESS OF THE REMOTES TABLE
   streams = 0;                         !THE NUMBER OF STREAMS IN THE CONFIGURATION
   sconad = 0;                          !THE CONNECT ADDRESS OF THE STREAM TABLE
   qnconad = 0;snconad = 0;rnconad = 0;  !the 'name' areas for queue/stream/remote tables
   headers = 0;                         !THE NUMBER OF STREAMS REQUIRING HEADERS
   if  infile owner # "" and  infile # "" start 
      seg = 0;  gap = 0;                !ANY SEGMENT ANY GAP
      if  TARGET # 2900 then  flag = dconnect(infile owner,infile,in fsys,r,seg,gap) c 
       else  flag = dconnect(infile owner,infile,in fsys,r,0,seg,gap)
                                        !CONNECT INPUT FILE TO READ
      if  flag = 0 start 
         conad = seg<<seg shift;               !TURN SEGMENT INTO A VIRTUAL ADDRESS
         file header == record(conad);  !MAP FILE HEADER
         text pointer = conad+file header_start;  !ADDR OF FIRST BYTE (USED BY READ LINE)
         text end = conad+file header_end;   !ADDR OF LAST BYTE + 1 (USED BY READ LINE)
         config size = max queues*queue entry size+max remotes c 
            *remote entry size+max streams*stream entry size+file header size + c 
          (max streams+max queues+max remotes)*name entry size
         create and connect(outfile owner,temp outfile,
            out fsys,config size,r!w,conad)
         create and connect(outfile owner, outfile."PTRS", out fsys, c 
          1024,r!w!shared, ptr conad)
         !This file contains the pointers to the main spooler database.
         if  conad # 0 and  ptr conad # 0 start ;          !SUCCESSFULLY CREATED CONFIG FILE

!*  QUEUE INPUT SECTION

            conad = conad+file header size
            !now initialise the pointer file.
            pointers == record(ptr conad + file header size)
            file header == record(ptr conad)
            file header_start = file header size
            file header_size = x'1000'
            read line(line);            !READ FIRST LINE IN FILE
            if   line -> ns1.("QUEUES=").ns2 and  ns1="" start ; !NUMBER OF QUEUES
               temps = ns2; temps = temp1 if  temps -> temp1.("!").temp2
                                        !REMOVE ANY COMMENTS
               queues = s to i(temps)
               if  1 <= queues <= max queues start 
                                        !VALID NUMBER OF QUEUES
                  qnconad = conad+queues*queue entry size
                  queue name entries == array(qnconad,qaf)
                  pointers_queues = queues
                  pointers_queue displ = file header size
                  pointers_queue name displ = pointers_queue displ + queues*queue entry size
                  pointers_queue entry size = queue entry size
                  cycle  i = 1,1,queues;!ROUND EACH QUEUE DESCRIPTOR
                     queue entry == record(conad+(i-1)* c 
                        queue entry size)
!MAP QUEUE ENTRY
                     cycle  j = 1,1,q descriptors;!READ EACH Q DESCRIPTOR
                        read line(line)
                        exit  if  line = ""; !A NULL LINE SIGNIFIES THE END OF FILE
                        if  line -> ns1.(qd(j)).ns2 and  ns1=""  start 
                                        !CORRECT FORMAT?
                           temps=ns2
                           temps = temp1 if  temps -> temp1.( c 
                              "!").temp2
!REMOVE COMMENTS
                           -> nextq if  temps = "NA" c 
                              or  temps = "NOTAPPLICABLE"
                           if  qdt(j) = 0 start ; !NUMERIC PARAMETER
                              value = stoi(temps)
                              -> failq if  value =  c 
                                 not assigned or  value < 0
                           finish  else  start ;  !STRING PARAMETER
                              -> failq unless  1 <= length( c 
                                 temps) <= qdt(j)
                           finish 
                           -> qswt(j);  !INTERPRET TEMPS
qswt(1):
!NAME OF QUEUE
                           queue entry_name = temps
                           queue name entries(i)_name = temps
                           -> nextq
qswt(2):
!DEFAULT USERNAME
                           queue entry_default user = temps
                           -> nextq
qswt(3):
!DEFAULT DELIVERY
                           queue entry_default delivery = temps
                           -> nextq
qswt(4):
!START BYTE IN FILE
                           queue entry_default start = value
                           -> next q
qswt(5):
!DEFAULT PRIORITY
                           cycle  k = 1,1,5
                              if  temps = priorities(k) start 
                                 queue entry_default priority = k
                                 -> nextq
                              finish 
                           repeat 
                           -> failq
qswt(6):
!DEFAULT CPU TIME
                           if  value > 0 start 
                              queue entry_default time = value
                              -> nextq
                           finish  else  -> failq
qswt(7):
!DEFAULT OUTPUT LIMIT 
                           if  value > 0 start 
                              queue entry_default output limit =  c 
                                 value
                              -> nextq
                           finish  else  -> failq
qswt(8):
!DEFAULT FORMS TYPE
                           if  value <= 255 start 
                              queue entry_default forms = value
                              -> nextq
                           finish  else  -> failq
qswt(9):
!DEFAULT MODE
                           cycle  k = 0,1,2
                              if  temps = modes(k) start 
                                 queue entry_default mode = k
                                 -> nextq
                              finish 
                           repeat 
                           -> failq
qswt(10):
!DEFAULT COPIES
                           if  0 < value <= 255 start 
                              queue entry_default copies = value
                              -> nextq
                           finish  else  -> failq
qswt(11):
!DEFAULT RERUN
                           if  temps = "YES" or  temps = "NO" c 
                              start 
                              queue entry_default rerun = yes c 
                                 if  temps = "YES"
                              -> next q
                           finish  else  -> failq
qswt(12):
!MAXIMUM LENGTH OF QUEUE
                           queue entry_max length = value
                           -> nextq
qswt(13):
!MAX ACR WITH ACCESS TO THIS QUEUE
                           if  0 < value <= 15 start 
                              queue entry_max acr = value
                              -> nextq
                           finish  else  -> failq
qswt(14):
!QUEUE BY ALGORITHM
                           queue entry_q by = 0
                           -> nextq
qswt(15):
!SET RESOURCE LIMIT FOR PRIORITY CALCULATION
if  value > 0 start 
queue entry_resource limit = value
->nextq
finishelse  -> failq
                        finish 
failq:                  print string("QUEUE ".i to s(i)." ". c 
                           queue entry_name." ENTRY ".qd(j). c 
                           " WRONG ".line.snl)
nextq:
                     repeat ;           !EACH QUEUE DESCRIPTOR
                     exit  if  line = "";    !END OF FILE?
                  repeat ;              !EACH QUEUE


!* REMOTE INPUT SECTION

                  read line(line);      !GET NUMBER OF REMOTES
                  if  line -> ns1.("REMOTES=").ns2 and  ns1=""  start 
                                        !IS IT NUMBER OF REMOTES?
                     temps=ns2; temps = temp1 if  temps -> temp1.("!").temp2
                                        !REMOVE COMMENTS
                     remotes = s to i(temps)
                     if  1 <= remotes <= max remotes start 
                                        !VALID NUMBER OF REMOTES?
                        rnconad = conad+queues*queue entry size+ c 
                         queues*name entry size +remotes*remote entry size
                        remote name entries == array(rnconad,raf)
                        pointers_remotes = remotes
                        pointers_remote displ = pointers_queue displ + c 
                         queues*(queue entry size+name entry size)
                        pointers_remote name displ = pointers_remote displ + c 
                         remotes*remote entry size
                        pointers_remote entry size = remote entry size
                        cycle  i = 1,1,remotes;   !ROUND EACH REMOTE
                           remote entry == record(conad+queues* c 
                              queue entry size+(i-1)* c 
                              remote entry size+queues*name entry size)
!MAP REMOTE ENTRY
                           cycle  j = 1,1,r descriptors
                              read line(line)
                              exit  if  line = "";!END OF FILE?
                              if  line -> ns1.(rd(j)).ns2 and  ns1=""  start 
                                        !CORRECT FORMAT?
                                 temps=ns2; temp2 = ""
                                 temps = temp1 if  temps ->  c 
                                    temp1.("!").temp2
!IGNORE COMMENTS
                                 -> nextr if  temps = "NA" c 
                                    or  temps = "NOTAPPLICABLE"
                                 if  rdt(j) = 0 start 
                                        !NUMERIC
                                    value = stoi(temps)
                                    -> failr if  value =  c 
                                       not assigned or  value < 0
                                 finish  else  start 
                                        !STRING
                                    -> failr unless  1 <=  c 
                                       length(temps) <= rdt(j)
                                 finish 
                                 -> rswt(j)
rswt(1):
!NAME OF REMOTE
                                 remote entry_name = temps
                                 remote name entries(i)_name = temps
                                 if  length(temp2)>0 and  charno(temp2,1)='*' c 
                                  start 
                                   temp2->("*").temp2
                                   if  length(temp2)>31 then  length(temp2)=31
                                   remote entry_description = temp2
                                 finish  else  remote entry_description = ""
                                  if  temps = "LOCAL" then  remote entry_status = 3
                                  !IE IF IT IS THE 'LOCAL' REMOTE THE INITS STATE MUST BE LOGGED ON.
                                 -> nextr
rswt(2):
!DEFAULT REMOTE STATUS
                                 cycle  k = 0,1,3
                                    if  temps = remote status( c 
                                       k) start 
                                       if  k<2 then  remote entry_status = k c 
                                       else  start 
                                        remote entry_status = 1;  !IE OPEN
                                        if  k=2 then  remote entry_prelog c 
                                         =1 else  remote entry_prelog=2
                                       finish 
                                       -> nextr
                                    finish 
                                 repeat 
                                 -> failr
rswt(3):
!DEFAULT FEP
                                 if  value <= 9 start 
                                    remote entry_prelog fep = value
                                    -> nextr
                                 finish  else  -> failr
rswt(4):
!DEFAULT NETWORK ADDRESS
                                 k = 0
                                 while  temps # "" cycle 
                                    temp1 = "" unless  temps ->  c 
                                       temps.("_").temp1
                                    if  temp1 = "" and  k = 0 start 
                                      !Then it is a 'text' logon address.
                                      remote entry_n add type = 2 {TS}
                                      cycle  k = 1,1,length(temps)
                                        remote entry_network address(k-1) = c 
                                         byteinteger(addr(temps)+k)
                                      repeat 
                                      k = length(temps)
                                      exit 
                                    finish 
                                    -> failr if  k = 32
                                    remote entry_n add type = 1 {NSI}
                                    l = stoi(temps)
                                    if  0 <= l <= 255 start 
                                       remote entry_ c 
                                          network address(k) = l
                                       k = k+1
                                    finish  else  -> failr
                                    temps = temp1
                                 repeat 
                                 remote entry_n add len = k
                                 -> nextr
rswt(5):
!THE REMOTE PASSWORD.
                               remote entry_password = temps
                               -> nextr
                              finish 
failr:                        print string("REMOTE ".i to s(i c 
                                 )." ".remote entry_name. c 
                                 " ENTRY ".rd(j)." WRONG ". c 
                                 line.snl)
nextr:
                           repeat ;     !EACH REMOTE DESCRIPTOR
                           exit  if  line = "";   !END OF FILE
                        repeat ;        !EACH REMOTE


!* STREAM INPUT SECTION

                        read line(line);!GET NUMBER OF STREAMS
                        if  line -> ns1.("STREAMS=").ns2 and  ns1=""  start 
                                        !IS IT NUMBER OF STREAMS?
                           temps=ns2
                           temps = temp1 if  temps -> temp1.( c 
                              "!").temp2
                                        !REMOVE COMMENTS
                           streams = s to i(temps)
                           if  1 <= streams <= max streams start 
                                        !VALID NUMBER OF STREAMS?
                              snconad = queues*queue entry size c 
                               +queues*name entry size +remotes*remote entry size + remotes*name entry size c 
                               +conad + streams*stream entry size
                              stream name entries == array(snconad,saf)
                              pointers_streams = streams
                              pointers_stream displ = pointers_remote displ + c 
                               remotes*(remote entry size+name entry size)
                              pointers_stream name displ = pointers_stream displ + c 
                               streams*stream entry size
                              pointers_stream entry size = stream entry size
                              cycle  i = 1,1,streams
                                        !ROUND EACH STREAM
                                 stream entry == record( c 
                                    queues*queue entry size+ c 
                                    remotes*remote entry size c 
                                    +(queues+remotes)*name entry size+conad+(i-1)* c 
                                    stream entry size)
!MAP STREAM ENTRY
                                 cycle  j = 1,1,s descriptors
                                        !ROUND EACH STREAM DESCRIPTOR
                                    read line(line)
                                    exit  if  line = ""
                                        !END OF FILE?
                                    if  line -> ns1.(sd(j)).ns2 and  ns1="" start 
                                        !CORRECT FORMAT?
                                       temps=ns2
                                       temps = temp1 if  temps ->  c 
                                          temp1.("!").temp2
!IGNORE COMMENTS
                                       -> nexts if  temps =  c 
                                          "NA" or  temps =  c 
                                          "NOTAPPLICABLE"
                                       if  sdt(j) = 0 start 
                                          !NUMERIC
                                          value = stoi(temps)
                                          -> fails if  value =  c 
                                             not assigned or  c 
                                             value < 0
                                       finish  else  start 
                                          !STRING
                                          -> fails unless  1 c 
                                             <= length(temps) c 
                                             <= sdt(j)
                                       finish 
                                       -> sswt(j)
sswt(1):
!NAME OF STREAM
                                       stream entry_name = temps
                                       stream name entries(i)_name = temps
                                       -> nexts
sswt(2):
!REMOTE FOR STREAM
                                       cycle  k = 1,1,remotes
                                          remote entry ==  c 
                                             record(conad+ c 
                                             queues* c 
                                             queue entry size+( c 
                                             k-1)* c 
                                             remote entry size+queues*name entry size)
                                          if  remote entry_ c 
                                             name = temps start 
                                          stream entry_remote = k
                                          remote entry_ c 
                                             lowest stream =  c 
                                             i if  c 
                                             remote entry_ c 
                                             lowest stream = 0
                                          -> fails unless  c 
                                             remote entry_ c 
                                             highest stream =  c 
                                             0 or  c 
                                             remote entry_ c 
                                             highest stream =  c 
                                             i-1
                                          remote entry_ c 
                                             highest stream = i
                                          -> nexts
                                          finish 
                                       repeat 
                                       -> fails
sswt(3):
!DEFAULT STREAM STATUS
                                       cycle  k = 0,1,1
                                          if  temps =  c 
                                             stream status(k) c 
                                             start 
                                          stream entry_status = k
                                          -> nexts
                                          finish 
                                       repeat 
                                       -> fails
sswt(4):
!DEVICE TYPE
                                       cycle  k = 0,1,15
                                          if  device type(k) =  c 
                                             temps start 
                                          stream entry_ c 
                                             device type = k
                                          -> fails if  c 
                                             stream entry_ c 
                                             remote = 0
                                          remote entry ==  c 
                                             record(conad+ c 
                                             queues* c 
                                             queue entry size+( c 
                                             stream entry_ c 
                                             remote-1)* c 
                                             remote entry size+queues*name entry size)
                                          if  remote entry_ c 
                                             name = "LOCAL" c 
                                             then   start 
                                               stream entry_ c 
                                               ident = k<<24
if  TARGET # 2900 and  k = 4 then  printstring("LOCAL CR not (yet) handled".snl) c 
 and  -> fails
                                             finish  else   c 
                                             stream entry_ c 
                                             ident = 14<<24
!FEP
                                          -> nexts
                                          finish 
                                       repeat 
                                       -> fails
sswt(5):
!DEVICE NO
                                       if  value <= 9 start 
                                          stream entry_ c 
                                             device no = value
                                          -> fails if  c 
                                             stream entry_ c 
                                             remote = 0
                                          remote entry ==  c 
                                             record(conad+ c 
                                             queues* c 
                                             queue entry size+( c 
                                             stream entry_ c 
                                             remote-1)* c 
                                             remote entry size+queues*name entry size)
                                          if  remote entry_ c 
                                             name = "LOCAL" c 
                                             then   c 
                                             stream entry_ c 
                                             ident =  c 
                                             stream entry_ c 
                                             ident!value<<16 c 
                                             else   c 
                                             stream entry_ c 
                                             ident =  c 
                                             stream entry_ c 
                                             ident! c 
                                             remote entry_fep<<16
                                          -> nexts
                                       finish  else  -> fails
sswt(6):
!DEFAULT LIMIT
                                       stream entry_limit = value
                                       -> nexts
sswt(7):
!DEFAULT FORMS
                                       if  value <= 255 start 
                                          stream entry_forms =  c 
                                             value
                                          -> nexts
                                       finish  else  -> fails
sswt(8):
!LOWEST PRIORITY
                                       cycle  k = 1,1,5
                                          if  temps =  c 
                                             priorities(k) start 
                                          stream entry_ c 
                                             lowest priority = k
                                          -> nexts
                                          finish 
                                       repeat 
                                       -> fails
sswt(9):
!STREAM TYPE
                                       cycle  k = 0,1,5
                                          if  temps =  c 
                                             stream types(k) start 
                                          stream entry_ c 
                                             service = k
                                          -> nexts
                                          finish 
                                       repeat 
                                       -> fails
sswt(10):
!QUEUES ATTACHED TO
                                      remote entry==record(conad+ c 
                                        queues*queue entry size+( c 
                                        stream entry_remote-1)* c 
                                        remote entry size+queues*name entry size)
                                       while  temps # "" cycle 
                                          temp1 = "" unless  c 
                                             temps -> temps.( c 
                                             "&").temp1
                                          cycle  k = 1,1,queues
                                          queue entry ==  c 
                                             record(conad+(k-1 c 
                                             )* c 
                                             queue entry size)
                                          if  queue entry_ c 
                                             name = temps start 
                                          cycle  l = 0,1,15
                                          if  stream entry_ c 
                                             queues(l) = 0 start 
                                          stream entry_queues c 
                                             (l) = k
                                          if  remote entry_name = "LOCAL" and  c 
                                           stream entry_service = 0 then  c 
                                           queue entry_general access = 1
                                          !IE OFFER ALL LOCAL OUTPUT QUEUES.
                                          -> out1
                                          finish 
                                          repeat 
                                          -> fails
out1:
                                          if  stream entry_ c 
                                             service # 2 start 
!NOT INPUT STREAMS
                                          cycle  l = 0,1,15
                                          if  queue entry_ c 
                                             streams(l) = 0 start 
                                          queue entry_streams c 
                                             (l) = i
                                          -> out2
                                          finish 
                                          repeat 
                                          -> fails
                                          finish  else  -> out2
                                          finish 
                                          repeat 
                                          -> fails
out2:                                     temps = temp1
                                       repeat 
                                       -> nexts
sswt(11):
!HEADER TYPE
                                       cycle  k = 1,1,3
                                          if  temps =  c 
                                             header types(k) start 
                                          stream entry_ c 
                                             header type = k
                                          headers = headers+1
                                          stream entry_ c 
                                             header number =  c 
                                             headers
                                          -> nexts
                                          finish 
                                       repeat 
                                       -> fails
sswt(12):
! UNIT SIZE
                                       if  value <= 255 start 
                                          stream entry_unitsize = value
                                          -> nexts
                                       finish  else  -> fails
sswt(13):
! UNIT NAME
                                       stream entry_unitname = temps
                                       -> nexts
                                    finish 
fails:                              print string("STREAM ". c 
                                       i to s(i)." ". c 
                                       stream entry_name. c 
                                       " ENTRY ".sd(j). c 
                                       " WRONG ".line.snl)
nexts:
                                 repeat ;    !EACH STREAM DESCRIPTOR
                                 exit  if  line = ""
                                        !END OF FILE
                              repeat ;  !EACH STREAM

                           finish  else  print string( c 
                              "INVALID NUMBER OF STREAMS ". c 
                              line.snl)
                        finish  else  print string( c 
                 "NUMBER OF STREAMS MUST BE NEXT IN CONFIG FILE NOT " c 
                           .line.snl)
                     finish  else  print string( c 
                        "INVALID NUMBER OF REMOTES ".line.snl)
                  finish  else  print string( c 
           "NUMBER OF REMOTES MUST BE NEXT IN CONFIG FILE NOT ". c 
                     line.snl)
               finish  else  print string( c 
                  "INVALID NUMBER OF QUEUES ".line.snl)
            finish  else  print string( c 
               "NUMBER OF QUEUES MUST BE FIRST IN CONFIG FILE NOT ". c 
               line.snl)

!* AT THIS POINT A CONFIG FILE IS CREATED AND CONNECTED

            flag = ddisconnect(outfile owner,temp outfile,
               out fsys,0)
            if  flag = 0 start ;        !CONFIG FILE DISCONNECTED TO CHANGE ITS SIZE
               conad = 0
               if  queues > 0 and  remotes > 0 c 
                  and  streams > 0  start 
                                        !MAKE SURE THERE IS SOMETHING IN IT
                  config size = (queues*queue entry size+ c 
                     remotes*remote entry size+streams* c 
                     stream entry size+ c 
                     (queues+streams+remotes)*name entry size + c 
                     file header size+1023)>>10
                  flag = dchsize(outfile owner,temp outfile,
                     out fsys,config size)
                  if  flag = 0 start ;  !SUCCESSFULL TRIMMED
                     flag = drename(outfile owner,temp outfile,
                        outfile,out fsys)
                     flag = dnewgen(outfile owner,outfile,
                        temp outfile,out fsys) c 
                        if  flag = already exists
                     if  flag = 0 start 
                        flag = dpermission(outfile owner,"",
                           "",outfile,out fsys,1,r)
                        print string("SET EEP ON ". c 
                           outfile owner.".".outfile. c 
                           " ON FSYS ".i to s(out fsys). c 
                           " FAILS ".errs(flag).snl) c 
                           if  flag # 0
                        seg = 0;  gap = 0
                        if  TARGET # 2900 then  flag = dconnect(out file owner, outfile,
                         out fsys,r!w!shared,seg,gap) else  c 
                         flag = dconnect(out file owner,outfile,
                           out fsys,r!w!shared,0,seg,gap)
                        if  flag = 0 start 
                           conad = seg<<seg shift
                           file header == record(conad)
                           file header_end = queues* c 
                              queue entry size+remotes* c 
                              remote entry size+streams* c 
                              stream entry size+c 
                              file header size+ (queues+streams+remotes)*name entry size
                           file header_start = file header size
                           file header_size = config size
                           file header_type = 0
                           file header_datetime =  c 
                              pack date and time(date,time)
                           file header_queues = queues
                           file header_remotes = remotes
                           file header_streams = streams
                           qconad = file header size+conad
                           rconad = file header size+conad+ c 
                              queues*queue entry size+queues*name entry size
                           sconad = file header size+conad+ c 
                              queues*queue entry size+remotes c 
                              *remote entry size+(queues+remotes)*name entry size
                        finish  else  print string("CONNECT ". c 
                           outfile owner.".".outfile." FAILS " c 
                           .errs(flag).snl)
                       flag = dpermission(outfile owner,"","", outfile."PTRS", c 
                       out fsys, 1, r)
                      if  flag # 0 then  printstring("Permission on POINTER file fails ".errs(flag).snl)
                     finish  else  print string( c 
                        "RENAME/NEWGEN ".outfile owner.".". c 
                        outfile." FAILS ".errs(flag).snl)
                  finish  else  print string("CHSIZE ". c 
                     outfile owner.".".temp outfile." FAILS ". c 
                     errs(flag).snl)
               finish  else  print string( c 
        "NO QUEUES, REMOTES OR STREAMS IN CONFIGURATION FILE". c 
                  snl)
               if  conad = 0 start 
                  flag = ddestroy(outfile owner,temp outfile,
                     "",out fsys,0)
                  print string("DESTROY ".outfile owner.".". c 
                     temp outfile." FAILS ".errs(flag).snl) c 
                     if  flag # 0
               finish 
            finish  else  print string("DISCONNECT ". c 
               outfile owner.".".temp outfile." FAILS ".errs( c 
               flag).snl)
         finish ;                       !CREATE AND CONNECT FAILURE
         flag = ddisconnect(infile owner,infile,in fsys,0)
         print string("DISCONNECT ".infile owner.".".infile. c 
            " FAILS ".errs(flag).snl) if  flag # 0
      finish  else  print string("CONNECT ".infile owner.".". c 
         infile." FAILS ".errs(flag).snl)
   finish 

!Now create the LINK LIST file.
  create and connect(outfile owner, link list name, out fsys, link list entries* c 
   link list entry size, r!w!shared, link list conad)
  if  link list conad = 0 then  printstring("DISASTER Link list create fails".snl) and  stop 
  flag = dpermission(outfile owner,"","",link list name,out fsys,1,r)
  if  flag # 0 then  printstring("Permission on link list file fails ".errs(flag).snl)

!* THIS NEXT SECTION IS ONLY ENTERED IF THE CONFIGURATION FILE WAS
!* NOT SUCCESSFULLY READ OR THE SPOOLER DATA BASE FILE NOT SUCCESSFULLY
!* CREATED.

   if  qconad = 0 or  rconad = 0 or  sconad = 0 start 
                                        !FAILED TO CREATE CONFIG FILE
      print string("DEFAULT CONFIG IN USE".snl)
      qconad = addr(tempqs(0));         !ADDRESS OF DEFAULT QUEUES
      queues = 2
      rconad = addr(temp rmts(0))
      remotes = 1
      sconad = addr(tempstrms(0));      !ADDRESS OF DEFAULT STREAMS
      streams = 1

      queue entry == record(qconad)
      queue entry = 0
      queue entry_name = "LP";          !DEFAULT LINE PRINTER QUEUE
      queue entry_streams(0) = 1;       !THE LP0 STREAM
      queue entry_default user = "SPOOLR"
      queue entry_default delivery = "Spooled Output"
      queue entry_default start = 32
      queue entry_default priority = 3; !STD
      queue entry_default copies = 1
      queue entry_default rerun = yes
      queue entry_max length = 100
      queue entry_max acr = 15;         !ACCESS BY ANY ONE
queue entry_resource limit = 1000

      queue entry == record(qconad+queue entry size)
      queue entry = 0
      queue entry_name = "JOURNAL";     !DEFAULT JOURNAL QUEUE
      queue entry_default start = 32
      queue entry_default priority = 3; !STD
      queue entry_default copies = 1
      queue entry_default rerun = yes
      queue entry_max length = 100
      queue entry_max acr = 9;          !PRIVILEGED ACCESS ONLY
      queue entry_resource limit = 1000
      qnconad = ADDR(TEMP QS NAME(0))
      queue name entries == array(qnconad,qaf)
      queue name entries(1)_name = "LP"
      queue name entries(2)_name = "JOURNAL"

      remote entry == record(rconad)
      remote entry = 0
      remote entry_name = "LOCAL"
      remote entry_status = 3;          !LOGGED ON
      remote entry_lowest stream = 1
      remote entry_highest stream = 1
      rnconad = ADDR(TEMP RMTS NAME(0))
      remote name entries == array(rnconad,raf)
      remote name entries(1)_name = "LOCAL"

      stream entry == record(sconad)
      stream entry = 0
      stream entry_name = "LP0"
      stream entry_remote = 1
      stream entry_status = 1;          !ALLOCATED
      stream entry_ident = x'06000000'; !LP ADAPTOR DEVICE 0
      stream entry_limit = 512
      stream entry_queues(0) = 1;       !THE LP QUEUE
      stream entry_device type = 6;     !LP
      stream entry_device no = 0
      stream entry_lowest priority = 1
      stream entry_header type = 1;     !LINE PRINTER
      stream entry_header number = 1
      stream entry_service = 0;       !OUTPUT DEVICE
      snconad = ADDR(TEMP STRMS NAME(0))
      stream name entries == array(snconad,saf)
      stream name entries(1)_name = "LP0"
   finish  else  print string("CONFIG ".in file owner.".". c 
      infile.snl)

! printstring("CONFIG returns".snl. %c
! "QCONAD ".itos(qconad).snl."SCONAD ".itos(sconad). %c
! "RCONAD ".itos(rconad).snl."QS ".itos(queues).snl)
! printstring("STRMS ".itos(streams).snl."RMTS ")
! queue entry == record(qconad)
! printstring(itos(remotes).snl.queue entry_name.snl)
! queue entry == record(qconad+queue entry size)
! printstring(queue entry_name.snl)
! remote entry == record(rconad); stream entry == record(sconad)
! printstring(remote entry_name.snl.stream entry_name.snl."END LIST".snl)
end ;                                   !OF ROUTINE READ SPOOL CAT
endoffile