CONSTSTRING (63) SEPVSN=" ** SEPRTN14  21/05/85 **
"
!
!***********************************************************************
!*                                                                     *
!*                  Conditional compilation constants                  *
!*                                                                     *
!***********************************************************************
!
CONSTINTEGER  FUNDS ON=0; ! Zero to suppress generation of FUNDS code
CONSTINTEGER  NEWCONNECT = 0; ! Zero for "old CONNECT mechanism".
CONSTINTEGER  NEWLOADER=1; ! 0 for old, 1 for new loader
CONSTINTEGER  NOTES ON=0; ! Zero to suppress generation of NOTES code
CONSTINTEGER  SYSPROCS=5; !NO F SYSTEM PROCESSES ALWAYS RUNNING
CONSTINTEGERNAME  USERNO=X'80C0005B'; !NO OF ACTIVE PROCESSES
!
INCLUDE  "SS0302S_SSOWNF"
!
!***********************************************************************
!*                                                                     *
!*                           Record formats                            *
!*                                                                     *
!***********************************************************************
!
! This format out of alphabetic sequence since DPERMF requires it
RECORDFORMAT  PRMSF(STRING (6) USER, BYTEINTEGER  UPRM)
!
RECORDFORMAT  AFRECF(STRING (11) NAME, INTEGER  KBYTES, STRING (8) DATE,
    STRING (6) TAPE, INTEGER  CHAPTER,FLAGS)
RECORDFORMAT  ARF(STRING (31) NAME, INTEGER  TYPE)
RECORDFORMAT  COMF(INTEGER  OCPTYPE,IPLDEV,SBLKS,SEPGS,NDISCS,                  C 
      DLVNADDR,GPCTABSIZE,GPCA,SFCTABSIZE,SFCA,SFCK,DIRSITE,      C 
      DCODEDA,SUPLVN,WASKLOKCORRECT,DATE0,DATE1,DATE2,            C 
      TIME0,TIME1,TIME2,EPAGESIZE,USERS,CATTAD,DQADDR,            C 
      BYTEINTEGER  NSACS,RESV1,SACPORT1,SACPORT0,                 C 
      NOCPS,RESV2,OCPPORT1,OCPPORT0,                              C 
      INTEGER  ITINT,CONTYPEA,GPCCONFA,FPCCONFA,SFCCONFA,         C 
      BLKADDR,RATION,SMACS,TRANS,LONGINTEGER  KMON,               C 
      INTEGER  DITADDR,SMACPOS,SUPVSN,PSTVA,SECSFRMN,SECSTOCD,    C 
      SYNC1DEST,SYNC2DEST,ASYNCDEST,MAXPROCS,INSPERSEC,ELAPHEAD,  C 
      COMMSRECA,STOREAAD,PROCAAD,SFCCTAD,DRUMTAD,TSLICE,FEPS,SP1, C 
      SP2,SP3,SP4,SP5,SP6,SP7,SP8,                                C 
      LSTL,LSTB,PSTL,PSTB,HKEYS,HOOT,SIM,CLKX,CLKY,CLKZ,          C 
      HBIT,SLAVEOFF,INHSSR,SDR1,SDR2,SDR3,                        C 
      SDR4,SESR,HOFFBIT,S2,S3,S4,END)
RECORDFORMAT  DAHF(INTEGER  DATAEND,DATASTART,SIZE,FILETYPE,DATE,TIME,FORMAT,
   RECORDS)
RECORDFORMAT  DHF(INTEGER  DATAEND,DATASTART,SIZE,FILETYPE,SUM,DATETIME,
   PSTART,SPARE)
RECORDFORMAT  DPERMF(INTEGER  BYTESRETURNED,OWNP,EEP,SPARE,
    RECORD (PRMSF) ARRAY  PRMS(0:15))
RECORDFORMAT  E31F(INTEGER  FILES,TOTSIZE,CHFILES,CHSIZE,TFILES,TSIZE)
RECORDFORMAT  E4F(INTEGER  FILES,USEDESC,FREEDESC,INDEX,MAXSECDESC,
   FREESECDESC,MAXPERMDESC,FREEPERMDESC,MAXC3,FREEC3,MAXC4,FREEC4)
! %RECORDFORMAT FDF(%INTEGER LINK,DSNUM, %BYTEINTEGER STATUS,ACCESSROUTE,
!    VALID ACTION,CUR STATE, %BYTEINTEGER MODE OF USE,MODE,FILE ORG,DEV CODE,
!     %BYTEINTEGER REC TYPE,FLAGS,LM,RM, %INTEGER ASVAR,AREC,RECSIZE,MINREC,
!    MAXREC,MAXSIZE,LASTREC,CONAD,CURREC,CUR,END,TRANSFERS,DARECNUM,CURSIZE,
!    DATASTART, %STRING(31) IDEN, %INTEGER KEYDESC0,KEYDESC1,RECSIZEDESC0,
!    RECSIZEDESC1, %BYTEINTEGER F77FLAG,F77FORM,F77ACCESS,F77STATUS,
!     %INTEGER F77RECL,F77NREC,IDADDR, %BYTEINTEGER F77BLANK,F77UFD,SPARE1,
!    SPARE2)
RECORDFORMAT  FHF(INTEGER  END,START,SIZE,TYPE,SPARE0,DATETIME,SPARE1,SPARE2)
RECORDFORMAT  E9F(INTEGER  ARFILES,ARKBYTES,BUFILES,BUKBYTES,IXSIZE, C 
   FILEDES,FREEFDES,PERMDES,FREEPDES)
RECORDFORMAT  FRECF(STRING (11) NAME, INTEGER  SP12,KBYTES,
    BYTEINTEGER  ARCH,CODES,CCT,OWNP,EEP,USE,CODES2,SSBYTE,FLAGS,SP29,SP30,
   SP31)
RECORDFORMAT  FRF(INTEGER  CONAD,FILETYPE,DATASTART,DATEND,SIZE,RUP,EEP,MODE,
   USERS,ARCH, STRING (6) TRAN, STRING (8) DATE,TIME, INTEGER  COUNT,SPARE1,
   SPARE2)
RECORDFORMAT  HF(INTEGER  DATAEND,DATASTART,FILESIZE,FILETYPE,SUM,DATETIME,
   FORMAT,RECORDS)
RECORDFORMAT  INFOF(INTEGER  VSN,STATE, STRING (7) IDENT,USER,
    STRING (15) DEST,SRCE,OUTPUT, STRING (31) NAME,DELIVERY,
    STRING (7) ARRAY  VOL LABEL(1:8), INTEGER  DT RECEIVED,DT STARTED,
   DT OUTPUT STARTED,DT DELETED,DATASTART,DATALENGTH,TIME,OUTPUT LIMIT,
   PHYSICAL SIZE,PRIORITY,START AFTER DT,AHEAD, BYTEINTEGER  FORMS,MODE,
   COPIES,ORDER,RERUN,TAPES,DISCS,FAILS)
RECORDFORMAT  JTABF(INTEGER  START,LENGTH,TYPE)
RECORDFORMAT  LNF(BYTEINTEGER  TYPE, STRING (6) NAME, INTEGER  REST,POINT,DR1)
RECORDFORMAT  PDHF(INTEGER  DATAEND,DATASTART,SIZE,FILETYPE,SUM,DATETIME,
   ADIR,COUNT)
RECORDFORMAT  PF(INTEGER  DEST,SRCE,(INTEGER  P1,P2,P3,P4,P5,P6 OR  C 
   STRING (23) S))
RECORDFORMAT  PRINTF(STRING (42) FNAME, BYTEINTEGER  TYPE, STRING (8) DATE,
    INTEGER  SIZE,ERRMESS)
! N.B. PRMSF declared above.
RECORDFORMAT  RF(INTEGER  CONAD,FILETYPE,DATASTART,DATAEND)
!
!***********************************************************************
!*                                                                     *
!*                              Constants                              *
!*                                                                     *
!***********************************************************************
!
CONSTBYTEINTEGERARRAY  FSYM(1:5)=   '1','+','-','0',' '
CONSTBYTEINTEGERARRAY  REPT(1:5)=   1,1,3,2,1
!
CONSTINTEGER  ABASEFILE=x'00800000'; !start address of basefile
CONSTINTEGER  CLISTSIZE=x'300000'; !MAX SIZE OF COMPILATION LISTING FILE
CONSTINTEGER  CODE=2
CONSTINTEGER  DEFJCPL=120; !DEFAULT JOB CPULIMIT - SECONDS
CONSTINTEGER  EBCDICBIT=x'20'
CONSTINTEGER  MACHINE=2960; ! Used by CHARGE routine to choose
                         ! charging formula.  Machine may be
                         ! equal to 2980 or 2972 or other
                         ! values - see the text of CHARGE in BCOM.
                         ! If MACHINE=0 then the formula will be
                         ! selected at run time according to the
                         ! processor type determined by grope.
                         ! MACHINE=2960 also causes slight
                         ! variations in METER and DETACHOBEY.
CONSTINTEGER  MAXJCPL=7200; !MAX CPULIMIT FOR DETACHED JOBS - SECONDS
CONSTINTEGER  SSCHARFILETYPE=3
CONSTINTEGER  SSCORRUPTOBJFILETYPE=5
CONSTINTEGER  SSDATAFILETYPE=4
CONSTINTEGER  SSDIRFILETYPE=2
CONSTINTEGER  SSFFORMAT=1
CONSTINTEGER  SSMAXWORKSIZE=x'200000'; !Max size for compiler workfile.
CONSTINTEGER  SSOBJFILETYPE=1
CONSTINTEGER  SSOPTFILETYPE=9
CONSTINTEGER  SSPDFILETYPE=6
CONSTINTEGER  SSUFORMAT=3
CONSTINTEGER  SSVFORMAT=2
!
IF  FUNDS ON#0 THENSTART 
CONSTINTEGERNAME  SCARCEWORD=x'80C00084'
FINISH 
!
CONSTSTRING (4) LASTFN = "}{|~"; ! This can be used instead of a file name
!       as a parameter to CONNECT, etc., to mean "the last file I nominated".
!
CONSTSTRING (4) ARRAY  PPER(0:15)= "None","R   ","W   ","WR  ","E   ","RE  ",
"WE  ","All ",
"P   ","RP  ","WP  ","WRP ","EP  ","REP ","WEP ","WREP"
!
!***********************************************************************
!*                                                                     *
!*                     %SYSTEM Routine/fn/map spec                     *
!*                                                                     *
!***********************************************************************
!
SYSTEMINTEGERFNSPEC  CHECKFILENAME(STRING (31) FILE, INTEGER  TYPE)
IF  NEWLOADER#0 THEN  START 
SYSTEMINTEGERFNSPEC  CURRENTLL
FINISH 
SYSTEMINTEGERFNSPEC  DIRTOSS(INTEGER  FLAG)
SYSTEMINTEGERFNSPEC  IOCP(INTEGER  EP,PARM)
SYSTEMINTEGERFNSPEC  PARMAP
SYSTEMINTEGERFNSPEC  PSTOI(STRING (63) S)
SYSTEMINTEGERFNSPEC  STARTSWITH(STRINGNAME  A, STRING (255) B, INTEGER  CHOP)
SYSTEMINTEGERFNSPEC  STOREMATCH(INTEGER  L,A1,A2)
SYSTEMINTEGERFNSPEC  TRAIL SPACES(INTEGER  LINE END,LINE START,TRANS)
!
SYSTEMINTEGERMAPSPEC  COMREG(INTEGER  I)
!
IF  NEWLOADER#0 THEN  START 
SYSTEMLONGINTEGERFNSPEC  LOADEP(STRING (31) NAME, INTEGERNAME  TYPE,FLAG,
    INTEGER  LOADLEVEL)
FINISH 
!
SYSTEMROUTINESPEC  CASTOUT(STRINGNAME  S)
SYSTEMROUTINESPEC  CHANGEFILESIZE(STRING (31) FILE, INTEGER  NEWSIZE,
    INTEGERNAME  FLAG)
SYSTEMROUTINESPEC  CHOPLDR(STRINGNAME  A, INTEGER  I)
SYSTEMROUTINESPEC  CONNECT(STRING (31) FILE, INTEGER  MODE,HOLE,PROT,
    RECORD (RF) NAME  R, INTEGERNAME  FLAG)
SYSTEMROUTINESPEC  DEFINE(INTEGER  CHAN, STRING (31) IDEN, INTEGERNAME  AFD,
   FLAG)
SYSTEMROUTINESPEC  DESTROY(STRING (31) FILE, INTEGERNAME  FLAG)
SYSTEMROUTINESPEC  DFDFOUT(STRING (31) OUT, INTEGER  CHAN, INTEGERNAME  FLAG)
SYSTEMROUTINESPEC  DISCONNECT(STRING (31) FILE, INTEGERNAME  FLAG)
SYSTEMROUTINESPEC  ENTER(INTEGER  MODE,DR0,DR1, STRING (255) PARAM)
SYSTEMROUTINESPEC  ETOI(INTEGER  AD,L)
SYSTEMROUTINESPEC  EXAMINEMACRO(STRINGNAME  M,C, INTEGER  B,A,S,
    INTEGERNAME  FLAG)
SYSTEMROUTINESPEC  FILL(INTEGER  LENGTH,FROM,FILLER)
SYSTEMROUTINESPEC  FILPS(STRINGNAME  DPF,S)
IF  NEWLOADER=0 THEN  START 
SYSTEMROUTINESPEC  FINDENTRY(STRING (31) ENTRY, INTEGER  TYPE,DAD,
    STRINGNAME  FILE, INTEGERNAME  DR0,DR1,FLAG)
FINISH 
SYSTEMROUTINESPEC  FINFO(STRING (31) FILE, INTEGER  MODE,
    RECORD (FRF) NAME  FR, INTEGERNAME  FLAG)
SYSTEMROUTINESPEC  FSTATUS(STRING (31) FILE, INTEGER  ACT,VALUE,
    INTEGERNAME  FLAG)
SYSTEMROUTINESPEC  INITCLIVARS
SYSTEMROUTINESPEC  JOURNALOFF
IF  NEWLOADER=0 THEN  START 
SYSTEMROUTINESPEC  LOAD(STRING (31) NAME, INTEGER  TYPE, INTEGERNAME  FLAG)
FINISH 
SYSTEMROUTINESPEC  MACOPEN
SYSTEMROUTINESPEC  MODDIRFILE(INTEGER  EP, STRING (31) DIRFILE,
    STRING (32) ENTRY,FILENAME, INTEGER  TYPE,DR0,DR1, INTEGERNAME  FLAG)
SYSTEMROUTINESPEC  MODPDFILE(INTEGER  EP, STRING (31) PDFILE,
    STRING (11) MEMBER, STRING (31) INFILE, INTEGERNAME  FLAG)
SYSTEMROUTINESPEC  MOVE(INTEGER  LENGTH,FROM,TO)
SYSTEMROUTINESPEC  NEWGEN(STRING (31) S,T, INTEGERNAME  FLAG)
SYSTEMROUTINESPEC  OUTFILE(STRING (31) FILE, INTEGER  FILESIZE,HOLE,PROT,
    INTEGERNAME  CONAD,FLAG)
SYSTEMROUTINESPEC  PHEX(INTEGER  I)
SYSTEMROUTINESPEC  PRINTMESS(INTEGER  N)
SYSTEMROUTINESPEC  PSYSMES(INTEGER  ROOT,FLAG)
SYSTEMROUTINESPEC  SENDFILE(STRING (31) FILE, STRING (16) DEVICE,
    STRING (24) NAME, INTEGER  COPIES,FORMS, INTEGERNAME  FLAG)
SYSTEMROUTINESPEC  SETFNAME(STRING (40) NAME)
SYSTEMROUTINESPEC  SETPAR(STRING (255) S)
SYSTEMROUTINESPEC  SETUSE(STRING (31) FILE, INTEGER  MODE,VALUE)
SYSTEMROUTINESPEC  SETWORK(INTEGERNAME  AD,FLAG)
SYSTEMROUTINESPEC  UCTRANSLATE(INTEGER  ADDRESS,LENGTH)
IF  NEWLOADER#0 THEN  START 
SYSTEMROUTINESPEC  UNLOAD2(INTEGER  LOCLL,FAIL)
FINISH 
!
SYSTEMSTRINGFNSPEC  ITOS(INTEGER  N)
SYSTEMSTRINGFNSPEC  NEXTTEMP
SYSTEMSTRING (255) FNSPEC  PRINTPARMS(LONGINTEGER  P)
SYSTEMSTRINGFNSPEC  SPAR(INTEGER  N)
SYSTEMSTRINGFNSPEC  SUBSTRING(STRINGNAME  S, INTEGER  I,J)
SYSTEMSTRING (8) FNSPEC  UNPACK DATE(INTEGER  P)
SYSTEMSTRING (8) FNSPEC  UNPACK TIME(INTEGER  P)
!
SYSTEMSTRING (255) MAPSPEC  CONTROL LINE(INTEGERNAME  FLAG)
!
!***********************************************************************
!*                                                                     *
!*               External/internal routine/fn/map specs                *
!*                                                                     *
!***********************************************************************
!
EXTERNALINTEGERFNSPEC  DDESTROY(STRING (6) USER, STRING (11) FILE,
    STRING (6) DATE, INTEGER  FSYS,TYPE)
IF  FUNDSON#0 THENSTART 
EXTERNALINTEGERFNSPEC  DDONATE(STRING (6) USER, INTEGER  FSYS,UNITS)
FINISH 
EXTERNALINTEGERFNSPEC  DEXECMESS(STRING (6) USER, C 
INTEGER  SACT,LEN,ADDR)
EXTERNALINTEGERFNSPEC  DFILENAMES(STRING (6) USER,
    RECORD (AFRECF) ARRAYNAME  INF, INTEGERNAME  FILENUM,MAXREC,NFILES,
    INTEGER  FSYS,TYPE)
EXTERNALINTEGERFNSPEC  DFSTATUS(STRING (6) USER, STRING (11) FILE,
    INTEGER  FSYS,ACT,VALUE)
EXTERNALINTEGERFNSPEC  DFSYS(STRING (6) USER, INTEGERNAME  FSYS)
EXTERNALINTEGERFNSPEC  DMESSAGE2(STRING (6) USER, INTEGERNAME  LEN,
    INTEGER  ACT,INVOC,FSYS,ADR)
EXTERNALINTEGERFNSPEC  DPERMISSION(STRING (6) OWNER,USER, STRING (8) DATE,
    STRING (11) FILE, INTEGER  FSYS,TYPE,AD)
EXTERNALINTEGERFNSPEC  DRESTORE(STRING (6) USER, STRING (11) FILE,
    STRING (8) DATE, INTEGER  FSYS,TYPE)
EXTERNALINTEGERFNSPEC  DSFI(STRING (6) USER, INTEGER  FSYS,TYPE,SET,ADR)
EXTERNALINTEGERFNSPEC  DSPOOL(RECORD (PF) NAME  P, INTEGER  LEN,ADR)
EXTERNALINTEGERFNSPEC  INSTREAM
EXTERNALINTEGERFNSPEC  OUTPOS
EXTERNALINTEGERFNSPEC  OUTSTREAM
EXTERNALINTEGERFNSPEC  UINFI(INTEGER  I)
!
EXTERNALROUTINESPEC  DEFINFO(INTEGER  CHAN, STRINGNAME  FILENAME,
    INTEGERNAME  STATUS)
EXTERNALROUTINESPEC  PROMPT(STRING (255) S)
EXTERNALROUTINESPEC  SETMODE(STRING (255) S)
EXTERNALROUTINESPEC  TRANSFERS(STRING (255) S)
!
EXTERNALSTRINGFNSPEC  DATE
EXTERNALSTRINGFNSPEC  TIME
EXTERNALSTRINGFNSPEC  UCSTRING(STRING (255) S)
EXTERNALSTRINGFNSPEC  UINFS(INTEGER  N)
!
!***********************************************************************
!*                                                                     *
!*                            Own variables                            *
!*                                                                     *
!***********************************************************************
!
!
!***********************************************************************
!*                                                                     *
!*                         Extrinsic variables                         *
!*                                                                     *
!***********************************************************************
!
! %EXTRINSICINTEGER DIRDISCON; !SET TO 1 WHEN DIRECTORY DISCONNECTED
IF  FUNDS ON#0 THENSTART 
! %EXTRINSICINTEGER SCARCITYFOUND
FINISH 
!
! %EXTRINSICSTRING(11) AVD; ! Active directory.
! %EXTRINSICSTRING(40) SSFNAME
!
!***********************************************************************
!*                                                                     *
!*                         External variables                          *
!*                                                                     *
!***********************************************************************
!
!
!***********************************************************************
!*                                                                     *
!*                         End of declarations                         *
!*                                                                     *
!***********************************************************************
!
!
!
ROUTINE  CLOSEST(INTEGER  CHAN)
!SAME AS CLOSESTREAM BUT DOES NOT CHECK FOR VALIDITY OF CHAN
INTEGER  FLAG
FLAG=IOCP(16,CHAN); !CLOSESTREAM CALL ON IOCP
END ; !OF CLOSEST
!
!
INTEGERFN  LENASA(INTEGER  FF,TRANS)
!*RETURNS THE NUMBER OF BYTES REQUIRED TO PRINT A FORMAT EFFECTOR
INTEGER  I
INTEGER  SYM
SYM=BYTEINTEGER(FF); !AVOID WRITING TO FF
IF  TRANS#0 THEN  ETOI(ADDR(SYM)+3,1)
!  %FOR I=1,1,5 %CYCLE
!     %IF SYM = FSYM(I) %THEN %EXIT
!  %REPEAT
I=ADDR(FSYM(1))
*ldtb_x'18000005'
*lda_I; ! Byte vector descriptor to FSYM(1:5).
*lb_SYM
*swne_ L = DR 
*jcc_8,<NOTINC>
*inca_1
NOTINC:
*cyd_0
*stuh_ B 
*isb_I
*st_I
RESULT =REPT(I)
END ; ! OF LENASA
!
!
ROUTINE  INTASA(INTEGER  FF,TRANS, INTEGERNAME  OUTP)
!*
!* MAPS FORMAT EFFECTORS AS FOLLOWS:
!*   1 = 12        (NEWPAGE)
!*   + = 13        (CR)
!*   - = 10,10,10  (3 NEWLINES)
!*   0 = 10,10     (2 NEWLINES)
!*     = 10        (NEWLINE)
!*
CONSTBYTEINTEGERARRAY  VALS(1:5)= C 
12,13,10,10,10
INTEGER  I
INTEGER  SYM
SYM=BYTEINTEGER(FF); !AVOID WRITING TO FF
IF  TRANS#0 THEN  ETOI(ADDR(SYM)+3,1)
!  %FOR I=1,1,5 %CYCLE
!     %IF SYM = FSYM(I) %THEN %EXIT
!  %REPEAT
I=ADDR(FSYM(1))
*ldtb_x'18000005'
*lda_I; ! Byte vector descriptor to FSYM(1:5).
*lb_SYM
*swne_ L = DR 
*jcc_8,<NOTINC>
*inca_1
NOTINC:
*cyd_0
*stuh_ B 
*isb_I
*st_I
MOVE(REPT(I),ADDR(VALS(I)),OUTP)
OUTP=OUTP+REPT(I)
END ; ! OF INTASA
!
!
INTEGERFN  {file length} FLC(INTEGER  MODE,INCONAD,OUTFORM, INTEGERNAME  FLAG)
INTEGER  INP,INTOP,OUTLEN,RECORDS,FORMAT,INLEN,RLEN
INTEGER  FE,LEN,I,LRECL,TRANS
RECORD (DAHF) NAME  INH
FLAG=0
FE=(MODE&2)>>1; !=1 IF FIRST CHAR IS FORMAT EFFECTOR
INH==RECORD(INCONAD)
INP=INCONAD+INH_DATASTART
INTOP=INCONAD+INH_DATAEND
INLEN=INH_DATAEND-INH_DATASTART
TRANS=INH_FORMAT&EBCDICBIT; !EBCDIC FILE IF SET
IF  MODE&1#0 START ; !DATA TO CHARACTER
   FORMAT=INH_FORMAT&x'F'
   IF  FORMAT=SSVFORMAT START ; !VARIABLE LENGTH RECORD
      OUTLEN=0
      WHILE  INP<INTOP CYCLE 
         RLEN=(BYTEINTEGER(INP)<<8)!BYTEINTEGER(INP+1)
         IF  RLEN<2 THENSTART 
            FLAG=311; !CORRUPT FILE
            RESULT =0
         FINISH 
         IF  FE#0 AND  RLEN>2 THEN  LEN=LENASA(INP+2,TRANS) ELSE  LEN=1
         OUTLEN=OUTLEN+RLEN-2+LEN-FE-TRAIL SPACES(INP+RLEN-1,INP+2+FE,TRANS)
         INP=INP+RLEN
      REPEAT 
      RESULT =OUTLEN+FE; !FE FOR EXTRA NL AT END OF FILE
   FINISHELSEIF  FORMAT=SSFFORMAT START ; !FIXED LENGTH RECORDS
      LRECL=INH_FORMAT>>16; !RECORD LENGTH
      RECORDS=INLEN//LRECL; !NUMBER OF RECORDS
      IF  FE=0 THENSTART 
         OUTLEN=INLEN+RECORDS; !ALLOW ONE NL PER RECORD
      FINISHELSESTART 
         OUTLEN=INLEN-RECORDS+1; !  - FE CHARS + LAST NL
      FINISH 
      I=INP
      WHILE  I<INTOP CYCLE 
         OUTLEN=OUTLEN-TRAIL SPACES(I+LRECL-1,I+FE,TRANS)
         IF  FE#0 THEN  OUTLEN=OUTLEN+LENASA(I,TRANS)
         I=I+LRECL
      REPEAT 
      RESULT =OUTLEN
   FINISHELSEIF  FORMAT=SSUFORMAT THENRESULT =INLEN
   FLAG=267; !INVALID FILETYPE
   SETFNAME("")
   RESULT =0
FINISHELSESTART ; !CHARACTER TO CHARACTER
   OUTLEN=1; !FOR EXTRA NL AT END
   WHILE  INP<INTOP CYCLE 
      OUTLEN=OUTLEN+LENASA(INP,TRANS)
      FOR  I=INP,1,INTOP-1 CYCLE 
         IF  BYTEINTEGER(I)=NL THENEXIT 
      REPEAT 
      IF  I#INP THEN  OUTLEN=OUTLEN+I-INP-1
      INP=I+1
   REPEAT 
   RESULT =OUTLEN
FINISH 
END ; !OF FLC
!
!
ROUTINE  SORTNAMES(RECORD (ARF) ARRAYNAME  R, INTEGER  M,N)
INTEGER  I,J,K,L,N1
RECORD (ARF) X
 ! There are N - M + 1 elements to be sorted.
L=M-1; ! L is never changed in this routine.  Nor are M and N.
!  N1 = 1
!  %WHILE N1<N-L %CYCLE
!     N1 = 2 * N1
!  %REPEAT
!  N1 is now the smallest (+ve integral) power of 2 which
!  is not less than N-M+1.  There is probably a faster way
!  to find this, but I can't be bothered with it just now.
!  Here it is - using the bit twiddling expression
!    1 << ((32 - SHZ(N-L-1)) & 31)
*lss_N; *isb_L; *isb_1; *shz_ TOS ; *lb_32; *sbb_ TOS 
*lss_1; *rot_ B ; *st_N1
!
!
CYCLE 
   N1=N1//2
 ! N1 is now zero, or else a power of 2 less than N-M+1.
   RETURNIF  N1=0
 ! N1 is now a power of 2 less than N-M+1.
   I=L; ! = M - 1.
   CYCLE 
      I=I+1
      J=I+N1
      EXITIF  J>N
      K=I
      WHILE  R(J)_NAME<R(K)_NAME CYCLE 
 ! J = K + N1,  K>=M,  J<=N.
         X=R(J)
         R(J)=R(K)
         R(K)=X
         J=K
         K=K-N1
         EXITIF  K<M
      REPEAT 
 ! K<M or R(J)_NAME>=R(K)_NAME.
 ! Every N1th. element from the Kth. to the (I+N1)th. is
 ! in ascending order.
   REPEAT 
REPEAT 
END ; !OF SORTNAMES
!
!
INTEGERFN  {PRINT INDEX PERMS} PXP(STRING (255) BEFORE,AFTER)
! PRINT .ALL PERMISSIONS, IF ANY.
RECORD (DPERMF) DPERM
INTEGER  N,I,FLAG
FLAG=DPERMISSION(UINFS(1),UINFS(1),"","",UINFI(1),8,ADDR(DPERM))
N=(DPERM_BYTESRETURNED-16)//8; !NO. OF INDIV PERMS
IF  N>0 START 
   PRINTSTRING(BEFORE)
   I=0
   WHILE  I<N CYCLE 
      PRINTSTRING(DPERM_PRMS(I)_USER." ".PPER(DPERM_PRMS(I)_UPRM))
      IF  OUTPOS+15>UINFI(15) THEN  NEWLINE ELSE  SPACES(3)
      I=I+1
   REPEAT 
   PRINTSTRING(AFTER)
FINISH 
RESULT =FLAG
END ; ! of PRINT INDEX PERMS.
!
!
ROUTINE  OUTOUT(INTEGER  START,LEN)
INTEGER  DR0,DR1,FLAG; !MUST STAY TOGETHER
DR0=LEN
DR1=START
FLAG=IOCP(19,ADDR(DR0))
END ; !OF OUTOUT
!
!
!< SINGLE SPACES
INTEGERFN  SINGLE SPACES(INTEGER  LENGTH,FROM,TO)
! Discards multiple spaces from LENGTH bytes at FROM, closing
! the text up so that only single spaces remain, and planting the
! compacted text at TO.  It is permissible to give TO=FROM to
! achieve 'compaction in place'.  It is not permissible (but
! there is no check to prevent it) to give FROM<TO<FROM+LENGTH.
! The %RESULT of the %FN gives the length of the compacted text.
!>
LONGINTEGER  FROMDESCR,BLOCKLIM,NEWFROM
INTEGER  TOBASE
! TOBASE will be a copy of the original value of TO.  TO is
! updated as the routine works through the text, and has the
! destination address for the next block of text to be moved
! into the compacted string.  On exit, TO - TOBASE is used
! to calculate the total length of the compacted text.
!
! FROMDESCR is a descriptor to the text remaining unprocessed
! in the uncompacted string.  Except possibly at the start of the
! routine, the first byte in the text specified by FROMDESCR will
! not be a space.  It will in fact be the first byte after a sequence
! of more than one space.
!
! BLOCKLIM is a descriptor specifying the residue of the area
! indicated by FROMDESCR after the first space in that area.  Thus
! the text between FROMDESCR and BLOCKLIM is terminated by exactly one
! space.  The routine will move this
! block of text to TO (and update TO), and thus it will build up
! a compacted text containing no multiple spaces.
!
! NEWFROM is a descriptor for the residue of the srea indicated by
! BLOCKLIM, starting at the first non-space.  After a block of text
! has been moved into the compacted text, FROMDESCR can be replaced
! by NEWFROM and the next block of text can be located.
!
! The routine moves text from the original text into the compacted
! text in blocks each of which is terminated by exactly one space (i.e.,
! the penultimate character is not a space).  These blocks are planted
! one after another in the compacted text, which consequently ends up
! containing no multiple spaces.
!
! The routine performs the compaction in the minimum possible number
! of moves.  It only moves a block of text whose terminating space is
! followed (in the original text) by at least one more space.  If it
! finds a space which is not followed by another in the original text,
! it does not treat that space as terminating a block to be moved.
! Instead, it goes on looking for multiple spaces.  Single spaces are
! distinguished from multiple spaces by comparing BLOCKLIM with
! NEWFROM.
!
! The routine also avoids doing a move if the destination and source
! addresses are the same.  This arises with the first move of a
! 'compaction in place'.
!
RESULT =0 IF  LENGTH<=0
TOBASE=TO
*ldtb_x'58000000'; *ldb_LENGTH; *lda_FROM
 ! DR has a string descriptor to the area of store.
*std_FROMDESCR
!     %CYCLE
!        %CYCLE
L1:*swne_ L = DR ,0,32; ! %MASK=0,%REF=SP.
*jcc_8,<NOMORE>
!           %IF another space has been found %THEN %START
*modd_1
!           %FINISH
NOMORE:
*std_BLOCKLIM
 !
 ! DR points just after the next unprocessed space in the row
 ! (or just after the end of the original text, if the FROMDESCR
 ! area contains no spaces).
*sweq_ L = DR ,0,32; ! DR points to the first non-space.
!        %EXIT %IF the BLOCKLIM area is all spaces, or if there
!                  were no spaces at all in the FROMDESCR area.
*jcc_8,<DONE>
*cyd_0
*ucp_BLOCKLIM
*jcc_8,<L1>
!        %REPEAT %UNTIL we find a multiple space.
DONE:
*std_NEWFROM
*lss_FROMDESCR+4
*ucp_TO; ! Check whether source address=destination address.
*irsb_BLOCKLIM+4; ! Gives length of text to move.  Doesn't change CC.
*jcc_8,<NOMOVE>
!        %IF the text needs moving %THEN %START
*slsd_FROMDESCR
*lda_TO
*ldb_ TOS 
*mv_ L = DR ; ! Close up the string, leaving only one space.
*cyd_0
*stuh_ B ; ! Leaves updated TO address in Acc.
*ld_NEWFROM
*j_<MOVED>
!        %FINISH %ELSE %START
NOMOVE:
*uad_TO; ! Simply update TO.
!        %FINISH
MOVED:
*st_TO
*std_FROMDESCR
*jaf_11,<L1>; ! Go back to scan for next space.
!     %REPEAT %UNTIL there's no text left.
 !
RESULT =TO-TOBASE
 !
END ; !OF TOBASE
!
!
ROUTINESPEC  JOIN(RECORD (JTABF) ARRAYNAME  TAB, INTEGER  FIRSTCELL,LASTCELL,
    STRING (31) OUT, INTEGER  FE, INTEGERNAME  FLAG)
ROUTINESPEC  JOIN2(RECORD (JTABF) ARRAYNAME  TAB, INTEGER  FIRSTCELL,
   LASTCELL, STRING (31) OUT, INTEGER  FE,GAP, INTEGERNAME  FLAG)
ROUTINESPEC  JOINFILES(STRING (255) FILENAMES, RECORD (JTABF) ARRAYNAME  TAB,
    INTEGER  MODE,FIRSTCELL, INTEGERNAME  LASTCELL,FLAG)
ROUTINE  SETINPUT(STRING (31) IN, INTEGERNAME  FLAG)
!CHECKS THAT IN EXISTS AND IS ".IN" OR A CHARACTER FILE
!CALLS DEFINE(81,IN....) AND SELECTINPUT(81)
INTEGER  AFD, TF
RECORD  (RF) RR
IF  NEWCONNECT=0 THEN  TF = 0
IF  "*"#IN#".IN" START ; !INPUT FROM A FILE
   CONNECT(IN,0,0,0,RR,FLAG); ! {SEQ}
   RETURN  IF  FLAG#0
   IF  NEWCONNECT=0 THEN  TF = -1
   IF  RR_FILETYPE#SSCHARFILETYPE THENSTART 
      FLAG=267
      ->ERR
   FINISH 
 !INVALID FILETYPE
   COMREG(46)=RR_CONAD; !FOR COMPILER SOURCE MAPPING
FINISHELSE  COMREG(46)=0; !CANNOT MAP
DEFINE(81,IN,AFD,FLAG)
->ERR IF  FLAG#0
SELECTINPUT(81)
ERR:
IF  NEWCONNECT#0 AND  TF#0 THEN  SETUSE (IN, -1, 0)
END ; !OF SETINPUT
!
!
ROUTINE  FCONV(INTEGER  MODE,INCONAD,OUT,RECFM, INTEGERNAME  FLAG)
!INITIAL VERSION ONLY CONVERTS DATA FILES TO CHARACTER
! **** **** Ought to check file types and stop in good order **** ****
! **** **** if asked to convert unacceptable types.          **** ****
INTEGER  INP,OUTP,RLEN,INTOP,FORMAT,TRANS,FE,RECLEN,I
RECORD (DAHF) NAME  INH
 !
 !{SEQ} - Files for conversion should be sequential-connected.
 !
FLAG=0; !DEFAULT O.K.
FE=(MODE&2)>>1; !FOR FORMAT EFFECTORS
INH==RECORD(INCONAD)
INP=INCONAD+INH_DATASTART; !START OF DATA
INTOP=INCONAD+INH_DATAEND; !END OF DATA +1
FORMAT=INH_FORMAT&x'F'
TRANS=INH_FORMAT&EBCDICBIT; !EBCDIC FILE IF SET
OUTP=OUT
IF  MODE&1#0 THENSTART ; !DATA TO CHARACTER
   IF  FORMAT=SSVFORMAT START ; !VARIABLE LENGTH RECORDS
      WHILE  INP<INTOP CYCLE 
         RECLEN=(BYTEINTEGER(INP)<<8)!BYTEINTEGER(INP+1)
 !LENGTH INCLUDES LENGTH BYTES
         RLEN=RECLEN-TRAIL SPACES(INP+RECLEN-1,INP+2+FE,TRANS)
         IF  FE#0 AND  RLEN>2 THENSTART 
            INTASA(INP+2,TRANS,OUTP); !OUTPUT FORMAT EFFECTOR
            MOVE(RLEN-3,INP+3,OUTP); !OUTPUT REST OF RECORD
            IF  TRANS#0 THEN  ETOI(OUTP,RLEN-3)
            OUTP=OUTP+RLEN-3
         FINISHELSESTART 
            MOVE(RLEN-2,INP+2,OUTP)
            IF  TRANS#0 THEN  ETOI(OUTP,RLEN-2)
 !TRANSLATE IF NEC
            OUTP=OUTP+RLEN-1
            BYTEINTEGER(OUTP-1)=NL
         FINISH 
         INP=INP+RECLEN
      REPEAT 
   FINISHELSEIF  FORMAT=SSFFORMAT START 
      RECLEN=INH_FORMAT>>16; !FIXED RECORD LENGTH
      WHILE  INP<INTOP CYCLE 
         RLEN=RECLEN-TRAIL SPACES(INP+RECLEN-1,INP+FE,TRANS)
         IF  FE#0 THENSTART 
            INTASA(INP,TRANS,OUTP)
            MOVE(RLEN-1,INP+1,OUTP)
            IF  TRANS#0 THEN  ETOI(OUTP,RLEN-1)
            OUTP=OUTP+RLEN-1
         FINISHELSESTART 
            MOVE(RLEN,INP,OUTP)
            IF  TRANS#0 THEN  ETOI(OUTP,RLEN)
            OUTP=OUTP+RLEN+1
            BYTEINTEGER(OUTP-1)=NL
         FINISH 
         INP=INP+RECLEN
      REPEAT 
   FINISHELSEIF  FORMAT=SSUFORMAT START 
 !UN-STRUCTURED - PRESUMABLY CONTAINS OWN NEWLINES
      MOVE(INTOP-INP,INP,OUTP)
   FINISHELSESTART 
      FLAG=267
      SETFNAME("")
   FINISH 
FINISHELSESTART ; !CHARACTER TO CHARACTER
   WHILE  INP<INTOP CYCLE 
      INTASA(INP,TRANS,OUTP); !FIRST CHAR IS FE
      FOR  I=INP,1,INTOP-1 CYCLE 
         IF  BYTEINTEGER(I)=NL THENEXIT 
      REPEAT 
      IF  I#INP THENSTART 
         MOVE(I-INP-1,INP+1,OUTP)
         OUTP=OUTP+I-INP-1
      FINISH 
      INP=I+1
   REPEAT 
FINISH 
IF  FE#0 THEN  BYTEINTEGER(OUTP)=NL; !ADD NL TO LAST LINE
END ; !OF FCONV
!
!
ROUTINE  SETOUTPUT(STRING (31) OUT, INTEGERNAME  FLAG)
!CALLS DEFINE(82,OUT) AND SELECTOUTPUT(82)
INTEGER  AFD
DEFINE(82,OUT,AFD,FLAG)
IF  FLAG=0 THEN  SELECTOUTPUT(82)
END ; !OF SETOUTPUT
!
!
!*
!*
IF  FUNDS ON#0 THENSTART 
ROUTINESPEC  FUNDS(STRING (255) S)
FINISH 
IF  NOTES ON#0 THENSTART 
FINISH 
ROUTINESPEC  LIST(STRING (255) S)
!*
!*
SYSTEMROUTINE  FILEANAL(STRING (31) FILE, RECORD (ARF) ARRAYNAME  R,
    INTEGERNAME  COUNT,FLAG)
INTEGER  PSTART,HASHCONST,I,CONAD,POINT,MAX,LDA,LIST
INTEGER  LINK,MARK,SHAD
CONSTBYTEINTEGERARRAY  HEADOFFSET(16:20)= C 
   4,16,28,32,36
CONSTBYTEINTEGERARRAY  IDENOFFSET(16:20)= C 
8,16,8,8,12
STRING (255) S
RECORD (PDHF) NAME  PDH
RECORD (DHF) NAME  DH
RECORD (RF) RR
RECORD (LNF) ARRAYFORMAT  HAF(0:10000)
RECORD (LNF) ARRAYNAME  H
MAX=COUNT; !MAX NO OF ELEMENTS IN ARRAY R
COUNT=0; !NUMBER FILLED BY ANALYSE
CONNECT(FILE,0,0,0,RR,FLAG)
RETURN  IF  FLAG#0
CONAD=RR_CONAD
IF  RR_FILETYPE=SSOBJFILETYPE START ; !OBJECT FILE
   LDA=CONAD+INTEGER(CONAD+24); !ABS ADDR LDATA
   FOR  LIST=16,1,20 CYCLE 
      LINK=INTEGER(LDA+HEADOFFSET(LIST)); !HEAD OF RIGHT LIST
      WHILE  LINK#0 CYCLE 
         COUNT=COUNT+1
         ->FULL IF  COUNT>MAX
         SHAD = CONAD + LINK + IDENOFFSET(LIST)
         UNLESS  LIST # 16 OR  0 < BYTEINTEGER(SHAD) < 32 THEN  C 
         SHAD = CONAD + LINK + 20
            !iput code entry type
         UNLESS  0 < BYTEINTEGER(SHAD) < 32 THEN  START 
            PRINTSTRING("bad ep..list=")
            WRITE(LIST,1)
            NEWLINE
         FINISH 
         R(COUNT)_NAME = STRING(SHAD)
         R(COUNT)_TYPE=LIST
         LINK=INTEGER(CONAD+LINK)
      REPEAT 
   REPEAT 
   ->ERR
FINISH 
IF  RR_FILETYPE=SSDIRFILETYPE START ; !DIRECTORY FILE
   DH==RECORD(CONAD); !DIRECTORY HEADER
   HASHCONST=INTEGER(CONAD+DH_DATASTART); !NO OF ITEMS IN HASH TABLE
   H==ARRAY(CONAD+DH_DATASTART+4,HAF); !MAP ONTO HASH ARRRAY
   PSTART=CONAD+DH_PSTART
   POINT=4; !FIRST STRING
 ! %CYCLE THROUGH PLIST
   WHILE  BYTEINTEGER(POINT+PSTART)#0 CYCLE 
      S=STRING(POINT+PSTART)
      IF  '='#CHARNO(S,1)#255 AND  LENGTH(S)>7 AND  CHARNO(S,7)='.' THENSTART 
 ! NOT AN ALIAS OR EMPTY STRING
         COUNT=COUNT+1
         ->FULL IF  COUNT>MAX; !ARRAY R IS FULL
         R(COUNT)_NAME=S
         R(COUNT)_TYPE=SSOBJFILETYPE
 !NOW LOOK FOR ENTRY NAMES THAT POINT TO THIS NAME
         FOR  MARK=0,1,1 CYCLE ; ! 0 for procedure entries,
 ! 1 for data entries.
            FOR  I=0,1,HASHCONST-1 CYCLE 
               IF  H(I)_POINT=POINT AND  H(I)_NAME#".EMPTY" AND  C 
                  H(I)_NAME#"" AND  H(I)_TYPE&1=MARK THENSTART 
                  COUNT=COUNT+1
                  ->FULL IF  COUNT>MAX
                  IF  H(I)_TYPE&x'80'#0 THEN  C 
                     R(COUNT)_NAME=H(I)_NAME.STRING(CONAD+DH_PSTART+H(I) C 
                     _REST) ELSE  R(COUNT)_NAME=H(I)_NAME
                  R(COUNT)_TYPE=MARK+16; ! 16 for procedure, 17 for data.
               FINISH 
            REPEAT 
         REPEAT 
      FINISH 
      POINT=POINT+LENGTH(S)+1; !MOVE ON TO NEXT STRING IN PLIST
   REPEAT 
 !NOW LOOK FOR ALIASES
   POINT=4; !FIRST STRING IN POINTER LIST
   WHILE  BYTEINTEGER(POINT+PSTART)#0 CYCLE 
      S=STRING(POINT+PSTART)
      IF  CHARNO(S,1)='=' START 
         COUNT=COUNT+1
         ->FULL IF  COUNT>MAX
         R(COUNT)_NAME=SUBSTRING(S,2,LENGTH(S))
 !REMOVE '='
         R(COUNT)_TYPE=21; !ALIASED NAME
 !NOW LOOK FOR ALIASES THAT POINT HERE.
         FOR  I=0,1,HASHCONST-1 CYCLE 
            IF  H(I)_POINT=POINT AND  H(I)_NAME#".EMPTY" AND  C 
               H(I)_NAME#"" THENSTART 
               COUNT=COUNT+1
               ->FULL IF  COUNT>MAX
               IF  H(I)_TYPE&x'80'#0 THEN  C 
                  R(COUNT)_NAME=H(I)_NAME.STRING(CONAD+DH_PSTART+H(I)_REST) C 
                  ELSE  R(COUNT)_NAME=H(I)_NAME
               R(COUNT)_TYPE=16
            FINISH 
         REPEAT 
      FINISH 
      POINT=POINT+LENGTH(S)+1; !MOVE ON TO NEXT STRING IN PLIST
   REPEAT 
   ->ERR
FINISH ; !END OF DIRECTORY FILE
IF  RR_FILETYPE=SSPDFILETYPE START ; !PARTITIONED FILE
   PDH==RECORD(CONAD)
   IF  PDH_COUNT<=MAX THEN  COUNT=PDH_COUNT ELSESTART 
      FLAG=300
      COUNT=MAX
   FINISH 
 !CHECK IF ENOUGH ROOM IN ARRAY R
   ->ERR IF  COUNT=0; !NO MEMBERS
   POINT=CONAD+PDH_ADIR+4
   FOR  I=COUNT,-1,1 CYCLE 
      R(I)_NAME=STRING(POINT+(I-1)*32)
      R(I)_TYPE=19; !MEMBER OF A PDFILE
   REPEAT 
   ->ERR
FINISH 
FULL:

FLAG=300; !USER DID NOT PROVIDE ENOUGH ROOM IN R
COUNT=COUNT-1; !RESET COUNT
ERR:
IF  NEWCONNECT#0 THEN  SETUSE (LASTFN, -1, 0)
END ; !OF FILEANAL
!
!
EXTERNALROUTINE  CONCAT(STRING (255) S)
!THIS VERSION ONLY READS FROM .IN AND ONLY ACCEPTS CHARACTER FILES
CONSTINTEGER  MAX=64; !MAX NO. OF INPUT FILES
RECORD (RF) RR
RECORD (HF) NAME  H
INTEGERARRAY  FSTART,FLEN(1:64)
STRING (18) ARRAY  FILE(1:64)
INTEGER  OUTCONAD,OUTLENGTH,OUTP,I,J,FLAG,CHR,K
STRING (31) NAME,MEMBER
STRING (255) NAME  LINE
STRING (7) OWNNAMEDOT

OUTLENGTH=32; !LENGTH OF HEADER
I=0
OWNNAMEDOT=UINFS(1)."."; !FOR REMOVAL OF OWN NAME FROM FILENAMES
PROMPT("Conc:")
CYCLE 
   LINE==CONTROL LINE(FLAG)
   FLAG = 25 AND  -> ERR IF  FLAG#0; !end of file detected
   UCTRANSLATE(ADDR(LINE)+1,LENGTH(LINE))
   CHR=STARTSWITH(LINE,OWNNAMEDOT,-1); ! REMOVE OWN NAME
   EXITIF  LINE=".END"
   IF  I=MAX THENSTART ; !TOO MANY INPUT FILES
      FLAG=277
      -> ERR
   FINISH 
   CONNECT(LINE,0,0,0,RR,FLAG); !{SEQ}
   IF  FLAG#0 THEN  PSYSMES(8,FLAG) {CONNECT FAILS} ELSEIF  C 
      RR_FILETYPE#SSCHARFILETYPE THENSTART 
 ! INVALID FILETYPE
      SETFNAME(LINE)
      PSYSMES(8,267)
   FINISHELSESTART 
      UNLESS  LINE->NAME.("_").MEMBER THEN  NAME=LINE
 !REMOVE MEMBER
      I=I+1
      FILE(I)=NAME
      FSTART(I)=RR_CONAD+RR_DATASTART
      FLEN(I)=RR_DATAEND-RR_DATASTART
      OUTLENGTH=OUTLENGTH+FLEN(I)
   FINISH 
REPEAT 
 !NOW GENERATE OUTPUT FILE
IF  I=0 THENSTART ; !NO FILES
   FLAG=305
   ->ERR
FINISH 
PROMPT("File:")
LINE==CONTROL LINE(FLAG)
FLAG = 25 AND  -> ERRD IF  FLAG#0; !end of file detected
UCTRANSLATE(ADDR(LINE)+1,LENGTH(LINE))
CHR=STARTSWITH(LINE,OWNNAMEDOT,-1); ! REMOVE OWN NAME
FOR  J=I,-1,1 CYCLE ; !CHECK FOR OUTPUT = INPUT
   IF  LINE=FILE(J) THENSTART 
      FLAG=266
      -> ERRD
   FINISH 
REPEAT 
OUTFILE(LINE,OUTLENGTH,0,0,OUTCONAD,FLAG); !{SEQ}
-> ERRD IF  FLAG#0
H==RECORD(OUTCONAD)
H_DATASTART=32
H_DATAEND=OUTLENGTH
H_FILETYPE=SSCHARFILETYPE
OUTP=OUTCONAD+32
FOR  J=1,1,I CYCLE 
   MOVE(FLEN(J),FSTART(J),OUTP)
   OUTP=OUTP+FLEN(J)
   IF  NEWCONNECT#0 THEN  DISCONNECT (FILE(I),K); ! Ignore flag.
REPEAT 
IF  NEWCONNECT#0 THEN  DISCONNECT (LINE,K); ! Ignore flag.
WRITE(I,1)
PRINTSTRING(" Files concatenated into file: ".LINE)
NEWLINE
IF  NEWCONNECT#0 THEN  -> ERR
ERRD:
IF  NEWCONNECT#0 THEN  START 
   FOR  J=1,1,I CYCLE 
      DISCONNECT (FILE(I),K); ! Ignore flag.
   REPEAT 
FINISH 
ERR:
COMREG(24)=FLAG
IF  FLAG#0 THEN  PSYSMES(7,FLAG)
END ; !OF CONCAT
!
!
!
EXTERNALROUTINE  ANALYSE(STRING (255) S)
LONGINTEGER  LONGTYPE
INTEGER  I,P,RECFM,TYPE,FLAG,OFM,LDA,J,MAX,FILETYPE
INTEGER  COST,ALIASHEAD,OPTI,CHAR,NS,CPF
SWITCH  HIST(1:9)
STRING (31) FNAME,REST,TEMPLATE
STRING (19) HSTR
STRING (8) OPTIONS
RECORD (FRF) FR
RECORD (DAHF) NAME  DAH
INTEGER  FILES,ENTRIES,DATAENTRIES,ALIASEDNAMES,ALIASES
INTEGER  HASHCONST,PLENGTH,PSTART,PUSED
RECORD (DHF) NAME  DH
CONSTINTEGER  PSET=1; !PERMISSIONS
CONSTINTEGER  ESET=2; !ENTRIES
CONSTINTEGER  ASET=4; !ALIASES
CONSTINTEGER  RSET=8; !REFS
CONSTINTEGER  FSET=16; !FILES
CONSTINTEGER  MSET=32; !MEMBERS
CONSTINTEGER  SSET=64; !STRUCTURE
CONSTINTEGER  HSET=128; !HISTORY
CONSTBYTEINTEGERARRAY  OPTL(1:8)= C 
'P','E','A','R','F','M','S','H'
CONSTINTEGER  MAXOPTL=8
CONSTSTRING (9) ARRAY  ONAME(1:7)= C 
"CODE","GLA","PLT","SST","UST","INITCMN","INITSTACK"
RECORD (ARF) ARRAY  INITIALR(1:100); !MAY NEED TO CHANGE THIS
CONSTINTEGER  MAXINITIALR=100
CONSTINTEGER  MAXR=6553; !MAXIMUM VALUE OF R
RECORD (ARF) ARRAYFORMAT  RAF(1:MAXR)
RECORD (ARF) ARRAYNAME  R
STRING (2) CHARCH
STRING (32) CURALIASED,OUT,FILE
RECORD (RF) RR
RECORD (HF) NAME  H
CONSTSTRING (22) ARRAY  LISTNAME(16:20)= C 
"Procedure entries","Data entries","Procedure refs",
"Dynamic procedure refs","Data refs"
CONSTINTEGER  MAXTYPENAME=9
CONSTSTRING (14) ARRAY  TYPENAME(0:MAXTYPENAME)= C 
 "NON-STANDARD", "OBJECT",
        "DIRECTORY", "CHARACTER", "DATA",
"CORRUPT OBJECT", "PARTITIONED","NON-STANDARD","NON-STANDARD","OPTION FILE"

ROUTINE  PRINTSORTEDLIST(INTEGER  START,FINISH)
!PRINTS THE NAMES IN RECORDARRAY R FROM START TO FINISH IN ALPHA ORDER
!LENGTH OF EACH NAME ASSUMED <=11 BUT IF GREATER THEN MORE THAN ONE COLUMN
!ALLOWED FOR PRINTING
   INTEGER  I
   RETURNIF  FINISH<START
   SORTNAMES(R,START,FINISH)
   FOR  I=START,1,FINISH CYCLE 
      IF  OUTPOS+LENGTH(R(I)_NAME)>UINFI(15) THEN  NEWLINE
      PRINTSTRING(R(I)_NAME)
      SPACE UNTIL (OUTPOS//12)*12=OUTPOS
   REPEAT 
   NEWLINE
END ; !OF PRINTSORTEDLIST
!
!

ROUTINE  PPMS; ! PRINTPERMISSIONS
   RECORD (DPERMF) DPERM
   INTEGER  I,N
   STRING (31) NAME
   STRING (6) OWNER
 ! **** **** READ THIS **** ****
 ! The 8-bit in OWNP means that the file may not be destroyed.
 ! The 8-bit in EEP means "all permissions if any", but it is ignored
 ! in Director 13 and later.  Consequently the masks in the code below
 ! should be 15 (instead of 7) for OWNP, but 7 for EEP.  But this
 ! presupposes a corresponding change in ZPERMIT (namely a "3"
 ! instead of a "2" in a couple of places), and that depends on
 ! a decision about a satisfactory user interface in PERMIT.
 ! Also the strings in PPER may need to be changed: "P" for
 ! "Protect" is not self-explanatory, especially since all the
 ! other letters indicate what you can do to a file, not what
 ! you can't do.
   PRINTSTRING("Access Permissions:")
   IF  FNAME->OWNER.(".").NAME START 
      IF  OWNER#UINFS(1) THENSTART ; !                 NOT MY FILE SO LIMITED INFO AVAILABLE
         FLAG=DPERMISSION(OWNER,UINFS(1),"",NAME,-1,10,ADDR(I))
         PRINTSTRING("   Self:".PPER(I&7)); NEWLINE
         ->NUSERS
      FINISH 
   FINISHELSE  NAME=FNAME
 ! Append process invocation number to temporary file names:
   IF  LENGTH(NAME)>1 AND  CHARNO(NAME,1)='T' AND  CHARNO(NAME,2)='#' THEN  C 
      NAME=NAME.ITOS(UINFI(13))
   FLAG=DPERMISSION(UINFS(1),UINFS(1),"",NAME,UINFI(1),4,ADDR(DPERM))
   PRINTSTRING("   Self:".PPER(DPERM_OWNP&15)."  Others:".PPER(DPERM_EEP&7))
   N=(DPERM_BYTESRETURNED-16)//8; !NO. OF INDIVIDUAL PERMISSIONS
   NEWLINE UNLESS  N=0
   I=0
   WHILE  I<N CYCLE 
      PRINTSTRING(DPERM_PRMS(I)_USER."  ".PPER(DPERM_PRMS(I)_UPRM))
      IF  OUTPOS+15>UINFI(15) THEN  NEWLINE ELSE  SPACES(3)
      I=I+1
   REPEAT 
   FLAG{PRINT INDEX PERMS}=PXP("
Permissions for all files:
","")
   NEWLINE
NUSERS:
   I=FR_USERS
   PRINTSTRING("Current users:")
   WRITE(I,1)
   NEWLINE
END ; !OF PRINTPERMISSIONS
!
!
TEMPLATE="FILE,OPTIONS=,OUT="
COST=OUTSTREAM
UCTRANSLATE(ADDR(S)+1,LENGTH(S))
FILPS(TEMPLATE,S)
IF  PARMAP&1=0 OR  PARMAP>7 THENSTART 
   FLAG=263
   ->ERR
FINISH 
FILE=SPAR(1)
OPTIONS=SPAR(2)
OPTI=0
R==ARRAY(ADDR(INITIALR(1)),RAF); !MAP R ONTO INITIALR TO START WITH
IF  OPTIONS#"" START 
   FOR  I=LENGTH(OPTIONS),-1,1 CYCLE 
      CHAR=CHARNO(OPTIONS,I)
      IF  CHAR='*' THENSTART ; ! ALL OPTIONS
         OPTI=-1
         EXIT 
      FINISH 
      FOR  J=MAXOPTL,-1,1 CYCLE 
         IF  CHAR=OPTL(J) THENSTART 
            OPTI=OPTI!(1<<(J-1))
            EXIT 
         FINISH 
      REPEAT 
   REPEAT 
FINISH 
OUT=SPAR(3)
IF  OUT#"" START ; !OUTPUT DEV OR FILE SPECIFIED
   SETOUTPUT(OUT,FLAG)
   ->ERR IF  FLAG#0
FINISH 
UNLESS  FILE->FNAME.("_") THEN  FNAME=FILE
 !REMOVE MEMBER FOR FINFO CALL
FINFO(FNAME,0,FR,FLAG)
->ERR IF  273#FLAG#0; !UNLESS ON OFFER OR OK
IF  LENGTH(FR_TRAN)=6 START ; !FILE IS ON OFFER
   PRINTSTRING("File ".FILE." is on OFFER to ".FR_TRAN)
   NEWLINE
   ->ERR
FINISH 
 ! If the file wasn't connected in this process at the time we called
 ! FINFO, then we are about to increase the user count when we call
 ! CONNECT, so to keep our records straight we will increment the count
 ! in FR.
IF  FR_CONAD=0 THEN  FR_USERS=FR_USERS+1
CONNECT(FILE,0,0,0,RR,FLAG); !CONNECT IN READ MODE
IF  FLAG#0 THEN  -> ERRX
H==RECORD(RR_CONAD)
FILETYPE=RR_FILETYPE
UNLESS  0<=INTEGER(RR_CONAD+12)<=MAXTYPENAME THEN  FILETYPE=0
 !OLD OBJECT FILE
CHARCH=""
IF  FR_ARCH&x'01'#0 THEN  CHARCH="*"; !CHERISHED
IF  FR_ARCH&x'80'#0 THEN  CHARCH="**"; !ARCHIVE REQUEST OUTSTANDING
PRINTSTRING("File: ".CHARCH.FILE)
PRINTSTRING("   Type: ".TYPENAME(FILETYPE)."   Length:")
WRITE(RR_DATAEND-RR_DATASTART,1)
PRINTSTRING(" Bytes")
NEWLINE
PRINTSTRING("Last altered: ".UNPACKDATE(H_DATETIME)." at ".UNPACKTIME C 
   (H_DATETIME))
NEWLINE
IF  OPTI&PSET#0 THEN  PPMS; ! PRINTPERMISSIONS
!******************************** OBJECT *************************
IF  FILETYPE=SSOBJFILETYPE START ; !OBJECT
   LDA=RR_CONAD+INTEGER(RR_CONAD+24)
   OFM=RR_CONAD+INTEGER(RR_CONAD+28); !START OF OBJECT FILE MAP
   P=RR_CONAD+INTEGER(LDA+48); !P POINTS TO START OF OBJDATA
   IF  OPTI&HSET#0 THENSTART ; !PRINT HISTORY
      NS=0
      WHILE  BYTEINTEGER(P)#0 CYCLE 
         TYPE=BYTEINTEGER(P)
         UNLESS  1<=TYPE<=9 THENEXIT 
         SPACES(NS) UNLESS  TYPE=7
         ->HIST(BYTEINTEGER(P))
HIST(1):!SOURCE FILE NAME
         PRINTSTRING("Source      : ".STRING(P+1))
         ->NEXT
HIST(2):!PARMS
         LONGTYPE=0; !OLD OBJECT FILES ONLY HAVE 4 BYTES OF PARM INFO
         MOVE(BYTEINTEGER(P+1),P+2,ADDR(LONGTYPE))
 !NEED TO MOVE TO ALIGN ON INTEGER BOUNDARY
         PRINTSTRING("Parms set   : ")
         PRINTSTRING(PRINTPARMS(LONGTYPE))
         ->NEXT
HIST(3):!START OF LINKED OBJECT
         PRINTSTRING("Components  : ")
         NS=NS+3; !FOR INDENTATION
         ->NEXT
HIST(4):!OBJECT FILE NAME
         NEWLINE
         SPACES(NS)
         PRINTSTRING("Object      : ".STRING(P+1))
         ->NEXT
HIST(5):!DATE LINKED
         MOVE(4,P+2,ADDR(I)); !PUT IN WORD
         PRINTSTRING("Linked      : ".UNPACKDATE(I)." at ".UNPACKTIME(I))
         ->NEXT
HIST(6):!DATE COMPILED
         MOVE(4,P+2,ADDR(I)); !PUT IN WORD
         PRINTSTRING("Last altered: ".UNPACKDATE(I)." at ".UNPACKTIME(I))
         ->NEXT
HIST(7):!END OF LINKED OBJECT
         NS=NS-3
         SPACES(NS)
         PRINTSTRING("END")
         ->NEXT
HIST(8):!ANY TEXT
         I=P+2; !START OF TEXT
         J=P+1+BYTEINTEGER(P+1); !END OF TEXT
         WHILE  I<=J CYCLE 
            PRINTSYMBOL(BYTEINTEGER(I))
            IF  BYTEINTEGER(I)=NL THEN  SPACES(NS)
            I=I+1
         REPEAT 
         ->NEXT
HIST(9):!THE COMPILER
         PRINTSTRING("Compiler  : ")
         PRINTSTRING(STRING(P+1))
         ->NEXT
NEXT:    
         NEWLINE
         P=P+2+BYTEINTEGER(P+1); !MOVE P TO POINT TO NEXT ITEM
      REPEAT 
   FINISH 
   IF  OPTI&ESET#0 OR  OPTI&RSET#0 START ; !ENTRIES AND OR REFS SET
      MAX=MAXINITIALR
      FILEANAL(FILE,R,MAX,FLAG)
      IF  FLAG=300 START ; !NOT ENOUGH ROOM
         I=x'40000'
         SETWORK(I,FLAG)
         IF  FLAG#0 THEN  ->ERR
         R==ARRAY(I,RAF)
         MAX=MAXR
         FILEANAL(FILE,R,MAX,FLAG)
      FINISH 
      ->ERR IF  FLAG#0
      I=1
      WHILE  I<=MAX CYCLE 
         TYPE=R(I)_TYPE
         IF  (16<=TYPE<=17 AND  OPTI&ESET#0) OR  (18<=TYPE<=20 AND  C 
            OPTI&RSET#0) THENSTART 
            PRINTSTRING(LISTNAME(TYPE))
            PRINTSTRING(":
")
            FOR  J=I,1,MAX+1 CYCLE 
               IF  J=MAX+1 OR  R(J)_TYPE#TYPE START 
                  PRINTSORTEDLIST(I,J-1)
                  I=J
                  EXIT 
               FINISH 
            REPEAT 
         FINISHELSE  I=I+1
      REPEAT 
      NEWLINE
   FINISH 
   IF  OPTI&SSET#0 START 
      PRINTSTRING("Area         Offset          Length")
      NEWLINE
      FOR  P=1,1,7 CYCLE 
         I=OFM+4+12*(P-1)
         IF  INTEGER(I+4)>0 START 
            REST=ONAME(P)
            PRINTSTRING(REST)
            SPACES(12-LENGTH(REST))
            PHEX(INTEGER(I))
            SPACES(8)
            PHEX(INTEGER(I+4))
            NEWLINE
         FINISH 
      REPEAT 
   FINISH 
FINISH 
!******************************** DATA *************************
IF  FILETYPE=SSDATAFILETYPE START 
 !DATAFILE
   DAH==RECORD(RR_CONAD)
   RECFM=DAH_FORMAT&x'03'; !FORMAT
   PRINTSTRING("Format: ")
   IF  DAH_FORMAT&EBCDICBIT#0 THEN  PRINTSYMBOL('E'); !EBCDIC FILE
   IF  RECFM=3 THEN  PRINTSTRING("Un-structured") ELSESTART 
 !FIXED OR VARIABLE
      IF  RECFM=1 THEN  PRINTSTRING("F") ELSE  PRINTSTRING("V")
      WRITE(DAH_FORMAT>>16,1); !RECORD SIZE
      PRINTSTRING("   Records:")
      WRITE(DAH_RECORDS,1)
   FINISH 
FINISH 
!******************************** DIRECTORY *************************
IF  FILETYPE=SSDIRFILETYPE AND  OPTI&x'56'#0 THENSTART 
 !DIRECTORY FILE - FILES, ENTRIES,
 !STRUCTURE OR ALIASES SET
   ALIASHEAD=0
   MAX=MAXINITIALR
   FILEANAL(FILE,R,MAX,FLAG); !GET MORE INFORMATION
   IF  FLAG=300 START ; !NOT ENOUGH ROOM
      I=x'40000'
      SETWORK(I,FLAG)
      IF  FLAG#0 THEN  ->ERR
      R==ARRAY(I,RAF)
      MAX=MAXR
      FILEANAL(FILE,R,MAX,FLAG)
   FINISH 
   ->ERR IF  FLAG#0
   IF  OPTI&ESET#0 START ; !LIST ENTRIES
      I=1
      WHILE  I<=MAX CYCLE 
         IF  R(I)_TYPE=SSOBJFILETYPE START 
 !FILENAME
            PRINTSTRING("
File: ".R(I)_NAME)
            NEWLINE
            I=I+1
            CPF=16; ! 16 for procedures and 17 for data.
            HSTR="Procedure entries:
"
            CYCLE 
               IF  I<=MAX START 
                  FOR  J=I,1,MAX+1 CYCLE 
                     IF  J=MAX+1 OR  R(J)_TYPE#CPF START 
 !PRINT ENTRY NAMES
                        IF  J>I START 
                           PRINT STRING(HSTR)
                           PRINTSORTEDLIST(I,J-1)
                           I=J
                        FINISH 
                        EXIT 
                     FINISH 
                  REPEAT 
               FINISH 
               CPF=CPF+1
               HSTR="Data entries:
"
            REPEATUNTIL  CPF>17
         FINISHELSE  I=I+1
      REPEAT 
   FINISHELSESTART ; !DEFAULT ONLY LIST FILENAMES
      IF  FSET&OPTI#0 START ; !FILENAMES ONLY
         IF  MAX>0 START 
            PRINTSTRING("Files:
")
            FOR  I=1,1,MAX CYCLE 
               IF  R(I)_TYPE=SSOBJFILETYPE START 
                  PRINTSTRING(R(I)_NAME)
                  NEWLINE
               FINISH 
            REPEAT 
         FINISH 
      FINISH 
   FINISH 
   IF  OPTI&ASET#0 START ; !PRINT ALIASES
      PRINTSTRING("
Name                     Alias
")
      I=1
      WHILE  I<=MAX CYCLE 
         IF  R(I)_TYPE=21 START ; !ALIASED NAME
            CURALIASED=R(I)_NAME
            I=I+1
            EXITIF  I>MAX
            FOR  J=I,1,MAX CYCLE 
               IF  R(J)_TYPE#16 THENEXIT 
               PRINTSTRING(CURALIASED)
               SPACE UNTIL  OUTPOS>=25
               PRINTSTRING(R(J)_NAME)
               NEWLINE
            REPEAT 
            I=J
         FINISHELSE  I=I+1
      REPEAT 
   FINISH 
   IF  OPTI&SSET#0 THENSTART 
      I=1; FILES=0; ENTRIES=0
      DATAENTRIES=0; ALIASEDNAMES=0; ALIASES=0
      WHILE  I<=MAX CYCLE 
         IF  R(I)_TYPE=SSOBJFILETYPE THENSTART 
            I=I+1
            FILES=FILES+1
            J=I
            WHILE  J<=MAX AND  R(J)_TYPE=16 CYCLE 
               J=J+1
            REPEAT 
            ENTRIES=ENTRIES+J-I; !PROCEDURE ENTRIES
            I=J
            WHILE  J<=MAX AND  R(J)_TYPE=17 CYCLE 
               J=J+1
            REPEAT 
            DATAENTRIES=DATAENTRIES+J-I; !DATA ENTRIES
            I=J
         FINISHELSESTART 
            IF  R(I)_TYPE=21 THENSTART ; !ALIASED NAME
               ALIASEDNAMES=ALIASEDNAMES+1
               I=I+1
               J=I
               WHILE  J<=MAX AND  R(J)_TYPE=16 CYCLE 
                  J=J+1
               REPEAT 
               ALIASES=ALIASES+J-I; !ADD ALIASES
               I=J
            FINISH 
         FINISH 
      REPEAT 
      DH==RECORD(RR_CONAD); !MAP DIR HEADER
      HASHCONST=INTEGER(RR_CONAD+DH_DATASTART); !LENGTH OF HASH TABLE
      PSTART=RR_CONAD+DH_PSTART
      PLENGTH=INTEGER(PSTART)
      PUSED=4; !NOW FIND END OF PLIST
      WHILE  BYTEINTEGER(PSTART+PUSED)#0 CYCLE 
         PUSED=PUSED+BYTEINTEGER(PSTART+PUSED)+1
      REPEAT 
      I=ENTRIES+DATAENTRIES+ALIASES; !TOTAL ENTRIES
      NEWLINE
      PRINTSTRING("Files : "); WRITE(FILES,1); NEWLINE
      PRINTSTRING("Aliased names : "); WRITE(ALIASEDNAMES,1)
      NEWLINES(2)
      PRINTSTRING("       Entries         Hash list          Plist")
      NEWLINE
      PRINTSTRING("Procedure :"); WRITE(ENTRIES,3)
      PRINTSTRING("      Used  :"); WRITE(I,3)
      PRINTSTRING("      Used  :"); WRITE(PUSED,4)
      PRINTSTRING(" bytes"); NEWLINE
      PRINTSTRING("Data      :"); WRITE(DATAENTRIES,3)
      PRINTSTRING("      Free  :"); WRITE(HASHCONST-I,3)
      PRINTSTRING("      Free  :"); WRITE(PLENGTH-PUSED,4)
      PRINTSTRING(" bytes"); NEWLINE
      PRINTSTRING("Alias     :"); WRITE(ALIASES,3)
      PRINTSTRING("      %Full :"); WRITE(I*100//HASHCONST,3)
      PRINTSTRING("      %Full :"); WRITE(PUSED*100//PLENGTH,4)
      NEWLINE
   FINISH 
FINISH 
!******************************** PARTITIONED *************************
!***********************************************************************
!*                                                                     *
!*             Routine for sorting the records of an array             *
!*                                                                     *
!***********************************************************************
ROUTINE  NSORT(RECORD (PRINTF) ARRAYNAME  P, INTEGERARRAYNAME  X, INTEGER  N)
! DECLARE INTEGER ARRAY X, BOUNDS 1:NUM, IN CALLING ROUTINE
   INTEGER  I,J,K,M,W
   RETURNUNLESS  N>0
!
   FOR  I=1,1,N CYCLE 
      X(I)=I
   REPEAT 
!
   M=1
   M=M<<1 WHILE  M<=N
   M=M-1
!
   CYCLE 
      M=M>>1
      EXITIF  M=0
      FOR  I=1,1,N-M CYCLE 
         K=I
         WHILE  K>0 CYCLE 
            J=K+M
!
            EXITIF  P(X(K))_FNAME<=P(X(J))_FNAME
            W=X(J)
            X(J)=X(K)
            X(K)=W
!
            K=K-M
         REPEAT 
      REPEAT 
   REPEAT 
END ; ! OF NSORT
!
!
!***********************************************************************
!*                                                                     *
!*    Routine for cycling round a specified pd file, picking up the    *
!*    names of all its members, together with their type, date last    *
!*     altered and size, and moving this data into an array, which     *
!*                   will be sorted at a later stage                   *
!*                                                                     *
!***********************************************************************
ROUTINE  PDFILE(STRING (42) S, INTEGER  PDFILESTART,FMEMS,
    RECORD (PRINTF) ARRAYNAME  RESULT, INTEGERNAME  NEXTFREE)
   STRING (255) JUNK
   STRING (35) NAME
   STRING (8) MDATE
   INTEGER  OFFSET,I,J,MOFF,TYPE,MEMSIZE,PDMEMS,AOFM,CODESIZE,CODEOFFSET
   OFFSET=INTEGER(PDFILESTART+24)
!
   FOR  I=1,1,FMEMS CYCLE 
      J=I-1
      MOFF=INTEGER(PDFILESTART+OFFSET+J<<5)
      NAME=STRING(PDFILESTART+OFFSET+4+J<<5)
      TYPE=INTEGER(PDFILESTART+MOFF+12)
      IF  TYPE = 0 THEN  TYPE = 3; ! treat as standard character file
      UNLESS  1<=TYPE<=6 THEN  TYPE=0
      IF  TYPE=0 THEN  MEMSIZE=0 AND  MDATE="**/**/**" ELSE  C 
         MDATE=UNPACKDATE(INTEGER(PDFILESTART+MOFF+20)) AND  C 
         MEMSIZE=INTEGER(PDFILESTART+MOFF)-INTEGER(PDFILESTART+MOFF+4)
      JUNK=S.",".NAME
      IF  LENGTH(JUNK)>41 THEN  LENGTH(JUNK)=41 AND  JUNK=JUNK."*"
      RESULT(NEXTFREE)_FNAME=JUNK
      RESULT(NEXTFREE)_TYPE=TYPE
      RESULT(NEXTFREE)_DATE=MDATE
      RESULT(NEXTFREE)_SIZE=MEMSIZE
      RESULT(NEXTFREE)_ERRMESS=0
      IF  TYPE=1 START 
         AOFM=PDFILESTART+MOFF+INTEGER(PDFILESTART+MOFF+28)
 !address of object file map
         CODESIZE=INTEGER(AOFM+8); !size and offset of code from object file map
         CODEOFFSET=INTEGER(AOFM+4)
         IF  ((PDFILESTART+MOFF+CODEOFFSET)!! C 
            (PDFILESTART+MOFF+CODEOFFSET+CODESIZE))&x'FFFC0000'#0 THEN  C 
            RESULT(NEXTFREE)_ERRMESS=1
      FINISH 
      NEXTFREE=NEXTFREE+1
!
      IF  TYPE=6 START 
         PDMEMS=INTEGER(PDFILESTART+MOFF+28)
         PDFILE(JUNK,PDFILESTART+MOFF,PDMEMS,RESULT,NEXTFREE) UNLESS  PDMEMS<=0
      FINISH 
!
   REPEAT 
!
END ; !OF PDFILE
!
!
!***********************************************************************
!*                                                                     *
!*                      Main routine starts here                       *
!*                                                                     *
!***********************************************************************
ROUTINE  PDANAL(STRING (31) FILE, INTEGER  CONAD, INTEGERNAME  FLAG)
   CONSTINTEGER  MAXX=512
   CONSTSTRING (44) OBJECT=" is object code and crosses segment boundary"
   CONSTSTRING (1) NL="
"
   RECORD (PRINTF) ARRAYFORMAT  PRINTFAF(1:4300)
   RECORD (PRINTF) ARRAYNAME  RESULT
   INTEGERARRAY  X(1:MAXX)
   CONSTSTRING (5) ARRAY  TYPEF(1:7)="N-st","Obj","Dir",
                      "Char","Data","C-Ob","Pd"
   STRING (35) P1,P2
   CONSTSTRING (4) UL="===="
   INTEGER  FMEMS,NEXTFREE,I,J,K
   STRING (31) SP
   K=x'20000'
   SETWORK(K,FLAG)
   PSYSMES(8,FLAG) ANDRETURNIF  FLAG#0
   RESULT==ARRAY(K,PRINTFAF)
   FMEMS=INTEGER(RR_CONAD+28)
   IF  FMEMS=0 THEN  PRINTSTRING(FILE." does not have any members") ANDRETURN 
   PRINTSTRING("Number of members in file ".FILE." = ")
   WRITE(FMEMS,4)
   NEWLINES(2)
   PRINTSTRING("NAME"); SPACES(25); PRINTSTRING("TYPE")
   SPACES(8); PRINTSTRING("DATE"); SPACES(9); PRINTSTRING("SIZE")
   NEWLINE
   PRINTSTRING(UL); SPACES(25); PRINTSTRING(UL); SPACES(8)
   PRINTSTRING(UL); SPACES(9); PRINTSTRING(UL); NEWLINE
   NEXTFREE=1
   PDFILE(FILE,RR_CONAD,FMEMS,RESULT,NEXTFREE)
   NEXTFREE=NEXTFREE-1
   IF  NEXTFREE>MAXX START 
      PRINTSTRING(" PDANAL fails: > 512 members") ANDRETURN 
   FINISH 
   X(I)=I FOR  I=1,1,NEXTFREE
   NSORT(RESULT,X,NEXTFREE)
   FOR  I=1,1,NEXTFREE CYCLE 
      J=X(I)
      RESULT(J)_FNAME->P1.(",").P2
      SP=""
      WHILE  P2->P1.(",").P2 CYCLE 
         SP=SP."  "
         P2=SP."_".P2
      REPEAT 
      PRINTSTRING(P2)
      SPACES(29-LENGTH(P2))
      PRINTSTRING(TYPEF(RESULT(J)_TYPE+1))
      SPACES(10-LENGTH(TYPEF(RESULT(J)_TYPE+1)))
      PRINTSTRING(RESULT(J)_DATE)
      SPACES(4)
      WRITE(RESULT(J)_SIZE,6)
      IF  RESULT(J)_ERRMESS#0 START 
         PRINTSTRING(NL."** Member ".P2.OBJECT.NL)
      FINISHELSE  NEWLINE
   REPEAT 
END ; !OF PDANAL
!
!
IF  FILETYPE=SSPDFILETYPE START 
 !PD FILE
   IF  OPTI&MSET#0 START 
      PDANAL(FILE,RR_CONAD,FLAG)
      IF  FLAG#0 THEN  PRINTSTRING("PDANAL has failed")
   FINISHELSESTART 
      MAX=MAXINITIALR; !NO OF ELEMENTS IN ARRAY R
      FILEANAL(FILE,R,MAX,FLAG)
      IF  FLAG=300 START ; !NOT ENOUGH ROOM
         I=x'40000'
         SETWORK(I,FLAG)
         IF  FLAG#0 THEN  ->ERR
         R==ARRAY(I,RAF)
         MAX=MAXR
         FILEANAL(FILE,R,MAX,FLAG)
      FINISH 
      ->ERR IF  FLAG#0
      IF  MAX>0 START ; !MUST BE SOME MEMBERS
         PRINTSTRING("Members:")
         NEWLINE
         PRINTSORTED LIST(1,MAX)
      FINISH 
      NEWLINE
   FINISH 
FINISH 
ERR:
IF  NEWCONNECT#0 THEN  SETUSE (FILE, -1, 0)
ERRX:
NEWLINE
IF  COST#OUTSTREAM THENSTART 
   SELECTOUTPUT(COST)
   CLOSEST(82)
FINISH 
COMREG(24)=FLAG
IF  FLAG#0 THEN  PSYSMES(16,FLAG)
END ; !OF ANALYSE
!
!
EXTERNALROUTINE  TIDYDIR(STRING (255) S)
CONSTINTEGER  MAXR=1500
RECORD (ARF) ARRAY  R(1:MAXR)
RECORD (RF) RR
INTEGER  MACNPTR,MACNH,TFNPTR,TFNH
RECORD (RF) MACRR
STRING (31) MACRONAME,DUMMYS
CONSTSTRING (9) TEMPDIR="T#TIDYDIR"
STRING (31) DIR
INTEGER  HASHUSED,PLISTUSED,NEWHASH,NEWPLIST,POINT,MAX
INTEGER  I,J,FLAG,PERCENT
REAL  FACTOR
STRING (36) TEMPLATE
TEMPLATE="DIRECTORY=".SSOWN_AVD.",FULLPERCENT=70"
UCTRANSLATE(ADDR(S)+1,LENGTH(S))
FILPS(TEMPLATE,S)
IF  PARMAP>3 THENSTART ; ! TOO MANY PARAMS
   FLAG=263
   ->ERR
FINISH 
IF  PARMAP&1#0 THEN  DIR=SPAR(1) ELSE  DIR=SSOWN_AVD
IF  PARMAP&2#0 THENSTART 
   PERCENT=PSTOI(SPAR(2))
   UNLESS  10<=PERCENT<=100 THENSTART 
      FLAG=202; !INVALID PARAMETER
      SETFNAME(SPAR(2))
      ->ERR
   FINISH 
FINISHELSE  PERCENT=70; !DEFAULT
CONNECT(DIR,3,0,0,RR,FLAG); !CHECK WRITE ACCESS FOR LATER
IF  FLAG#0 THEN  -> ERRX
IF  RR_FILETYPE#SSDIRFILETYPE THENSTART 
   SETFNAME(DIR)
   FLAG=267; !INVALID FILETYPE
   ->ERR
FINISH 
MAX=MAXR
FILEANAL(DIR,R,MAX,FLAG); !GET INFO
IF  FLAG#0 THEN  ->ERR
IF  MAX#0 THENSTART 
   I=INTEGER(RR_CONAD+RR_DATASTART); !LENGTH OF HASH TABLE
   J=INTEGER(RR_CONAD+INTEGER(RR_CONAD+24)); !LENGTH OF PLIST
   DESTROY(TEMPDIR,FLAG); !IGNORE FLAG
   MODDIRFILE(10,TEMPDIR,"","",0,I,J+1023,FLAG)
   IF  FLAG#0 THEN  ->ERR; !CREATING NEW DIR
   MACNH=MAX
   MACNPTR=MAXR
   FOR  I=1,1,MAX CYCLE 
      IF  R(I)_TYPE=SSOBJFILETYPE START 
         MODDIRFILE(3,TEMPDIR,"",R(I)_NAME,0,0,0,FLAG)
 !INSERT
 ! <<<< <<<< <<<< <<<< <<<<
         IF  FLAG#0 THENSTART 
            MODDIRFILE(2,TEMPDIR,"",R(I)_NAME,0,0,0,J)
            IF  FLAG=267 THENSTART ; ! It might have been a macro.
               CONNECT(R(I)_NAME,0,0,0,MACRR,FLAG)
               IF  FLAG=0 THENSTART 
                  IF  MACRR_FILETYPE#SSCHARFILETYPE THEN  FLAG=267 ELSESTART 
                     INITCLIVARS
                     MACOPEN
                     EXAMINEMACRO(MACRONAME,DUMMYS,
                        MACRR_DATAEND-MACRR_DATASTART,
                        MACRR_CONAD+MACRR_DATASTART,0,FLAG)
                     IF  FLAG#0 THENSTART 
                        IF  FLAG=x'80000800' THEN  FLAG=336 ELSEIF  C 
                           FLAG=x'80001000' THEN  FLAG=337
                     FINISHELSESTART 
                        MODDIRFILE(9,TEMPDIR,MACRONAME,R(I)_NAME,0,0,0,FLAG)
                        IF  FLAG#0 THEN  C 
                           MODDIRFILE(2,TEMPDIR,"",R(I)_NAME,0,0,0,J) ELSE  C 
                           START 
                           R(I)_TYPE=SSCHARFILETYPE
                           IF  MACNPTR>MACNH THENSTART 
                              R(MACNPTR)_NAME=MACRONAME
                              MACNPTR=MACNPTR-1
                           FINISH 
                        FINISH 
                     FINISH 
                  FINISH 
                  IF  NEWCONNECT#0 THEN  SETUSE (R(I)_NAME, -1, 0)
               FINISH 
            FINISH 
            IF  FLAG#0 THENSTART 
               PRINT STRING("File ".R(I)_NAME." removed: ")
               PRINTMESS(FLAG)
               R(I)_TYPE=0
            FINISH 
         FINISH 
 ! >>>> >>>> >>>> >>>> >>>>
      FINISH 
      IF  R(I)_TYPE=21 START ; !ALIAS
         FOR  J=I+1,1,MAX CYCLE 
            IF  R(J)_TYPE#16 THENEXIT ; !LAST REACHED
            MODDIRFILE(9,TEMPDIR,R(J)_NAME,"=".R(I)_NAME,0,0,0,FLAG)
         REPEAT 
      FINISH 
   REPEAT 
   CONNECT(TEMPDIR,0,0,0,RR,FLAG); !NOW REPACKED
   IF  FLAG#0 THEN  ->ERR
   POINT=RR_CONAD+INTEGER(RR_CONAD+24)+4; !START OF PLIST
   PLISTUSED=POINT; !FOR SUMMING SIZE OF PLIST
   WHILE  BYTEINTEGER(POINT)#0 CYCLE 
      POINT=POINT+BYTEINTEGER(POINT)+1
   REPEAT 
   PLISTUSED=POINT-PLISTUSED+4
   MACNH=MACNPTR
   TFNPTR=MACNH
   FOR  I=MAX,-1,1 CYCLE 
      IF  R(I)_TYPE=SSCHARFILETYPE THENSTART 
         R(TFNPTR)=R(I)
         TFNPTR=TFNPTR-1
      FINISH 
   REPEAT 
   TFNH=TFNPTR
   MAX=TFNH
   FILEANAL(TEMPDIR,R,MAX,FLAG); !GET INFO IN ARRAY
   IF  FLAG#0 THEN  -> ERRY
FINISH 
IF  MAX=0 THENSTART 
   NEWHASH=160; ! Same as DEFAULT HASHCONST in NEWDIRECTORY.
   NEWPLIST=856; ! Same as DEFAULT PLENGTH in NEWDIRECTORY.
FINISHELSESTART 
   IF  TFNH<MACNH THENSTART 
      FOR  I=1,1,MAX CYCLE 
         IF  R(I)_TYPE=SSOBJFILETYPE THENSTART 
            FOR  TFNPTR=TFNH+1,1,MACNH CYCLE 
               IF  R(I)_NAME=R(TFNPTR)_NAME THEN  R(I)=R(TFNPTR)
            REPEAT 
         FINISH 
      REPEAT 
   FINISH 
   HASHUSED=0
   FOR  I=1,1,MAX CYCLE ; !COUNT HASH LIST ENTRIES
      IF  16<=R(I)_TYPE<=17 THEN  HASHUSED=HASHUSED+1
   REPEAT 
   FACTOR=PLISTUSED/HASHUSED; !FOR CALCULATING NEW PLIST
   IF  FACTOR<2 THEN  FACTOR=2; !MINIMUM
   IF  FACTOR>20 THEN  FACTOR=20; !MAXIMUM
   NEWHASH=HASHUSED*100//PERCENT; !MAKE IT PERCENT FULL
   NEWPLIST=INT(NEWHASH*FACTOR); !IN SAME PROPORTION AS OLD DIR
   IF  NEWHASH<100 OR  (NEWHASH<160 AND  NEWPLIST<856) THENSTART 
 ! USE DEFAULTS FOR SMALL DIRS
      NEWHASH=160
      NEWPLIST=856
   FINISH 
FINISH 
IF  NEWCONNECT#0 THEN  SETUSE (TEMPDIR, -1, 0)
DESTROY(TEMPDIR,FLAG); !IGNORE FLAG
MODDIRFILE(10,TEMPDIR,"","",0,NEWHASH,NEWPLIST,FLAG)
IF  FLAG#0 THEN  ->ERR; !REMAKE DIR WITH NEW SIZES
IF  MAX#0 THENSTART 
   MACNPTR=MAXR
   FOR  I=1,1,MAX CYCLE 
      IF  R(I)_TYPE=SSOBJFILETYPE START 
         MODDIRFILE(3,TEMPDIR,"",R(I)_NAME,0,0,0,FLAG)
 !INSERT
         IF  FLAG#0 THEN  MODDIRFILE(2,TEMPDIR,"",R(I)_NAME,0,0,0,J)
 !REMOVE
      FINISH 
 ! <<<< <<<< <<<<
      IF  R(I)_TYPE=SSCHARFILETYPE THENSTART 
         FLAG=0
         IF  MACNPTR>MACNH THENSTART 
            MACRONAME=R(MACNPTR)_NAME
            MACNPTR=MACNPTR-1
         FINISHELSESTART 
            CONNECT(R(I)_NAME,0,0,0,MACRR,FLAG)
            IF  FLAG=0 THENSTART 
               EXAMINEMACRO(MACRONAME,DUMMYS,MACRR_DATAEND-MACRR_DATASTART,
                  MACRR_CONAD+MACRR_DATASTART,0,FLAG)
               IF  FLAG=x'80000800' THEN  FLAG=336 ELSEIF  C 
                  FLAG=x'80001000' THEN  FLAG=337
               IF  NEWCONNECT#0 THEN  SETUSE (R(I)_NAME, -1, 0)
            FINISH 
         FINISH 
         IF  FLAG=0 THENSTART 
            MODDIRFILE(9,TEMPDIR,MACRONAME,R(I)_NAME,0,0,0,FLAG)
            IF  FLAG#0 THEN  MODDIRFILE(2,TEMPDIR,"",R(I)_NAME,0,0,0,J)
         FINISH 
      FINISH 
 ! >>>> >>>> >>>>
      IF  R(I)_TYPE=21 START ; !ALIAS
         FOR  J=I+1,1,MAX CYCLE 
            IF  R(J)_TYPE#16 THENEXIT ; !LAST REACHED
            MODDIRFILE(9,TEMPDIR,R(J)_NAME,"=".R(I)_NAME,0,0,0,FLAG)
         REPEAT 
      FINISH 
   REPEAT 
FINISH 
IF  NEWLOADER#0 AND  NEWCONNECT=0 THEN  SETUSE(DIR,-1,0); ! Reduce use count
NEWGEN(TEMPDIR,DIR,FLAG)
SSOWN_DIRDISCON=1; !TELL LOADER TO REBUILD SEARCH LIST
IF  NEWCONNECT#0 THEN  -> ERR
ERRY:
IF  NEWCONNECT#0 THEN  SETUSE (TEMPDIR, -1, 0)
ERRX:
IF  NEWCONNECT#0 THEN  DISCONNECT (DIR, I); ! Ignore flag.
ERR:
COMREG(24)=FLAG
IF  FLAG#0 THEN  PSYSMES(94,FLAG)
END ; !OF TIDYDIR
!
!
EXTERNALROUTINE  FILES(STRING (255) S)
STRING (31) OUT,USER,TEMPLATE
STRING (31) PATTERN,PATS,PATT,PATU,NAME,OPTIONS
INTEGER  PATTYPE,ARCHSET,CHERSET,CHERISH,HAZARD,PERLINE,EXTRA,CHAR
INTEGER  AFILE,FSYS
CONSTINTEGER  MAXPA=201
INTEGER  FILENUM,NFILES,MAXREC,COUNT,FLAG,FLAG4,I,POS,COST,PROC,FINISHED
!FLAG4 is for a specific call on DSFI 4
INTEGER  NPERM,NTEMP,PERMK,TEMPK
RECORD (E31F) E31
RECORD (E4F) E4
RECORD (E9F) E9
INTEGER  TLIMIT,MAXFSIZE

!
!

INTEGERFN  MATCH(STRING (31) NAME,PATTERN)
 ! RETURNS A BOOLEAN RESULT ON
 ! MATCHING A NAME WITH A PATTERN
 ! WHICH CONTAINS "*" SYMBOLS
 ! TO REPRESENT AN ARBITRARY
 ! NO OF CHARACTERS
   CONSTINTEGER  TRUE=1,FALSE=0
   SWITCH  TYP(1:4)
   NAME=UCSTRING(NAME)
   IF  PATTYPE=0 START ; !FIRST TIME - ANALYSE PATTERN
      IF  PATTERN->PATS.("*").PATT THENSTART 
         IF  PATS#"" THEN  PATTYPE=3 ELSESTART 
            IF  PATT->PATS.("*") THEN  PATTYPE=1 ELSE  PATTYPE=2
         FINISH 
      FINISHELSE  PATTYPE=4
   FINISH ; ! FINISHED ANALYSING
 !
 ! 1: *PATS*
 ! 2: *PATT
 ! 3: PATS*PATT
 ! 4: NAME
 !
   ->TYP(PATTYPE); ! BRANCH ON TYPE
TYP(4):
   IF  PATTERN=NAME THENRESULT =TRUE ELSERESULT =FALSE
TYP(1):
TYP(3):
   UNLESS  NAME->PATU.(PATS).NAME THENRESULT =FALSE
   IF  PATTYPE=1 THENRESULT =TRUE
   IF  PATU#"" THENRESULT =FALSE
TYP(2):
   IF  LENGTH(NAME)>=LENGTH(PATT) AND  C 
      STOREMATCH(LENGTH(PATT),ADDR(PATT)+1,
      ADDR(NAME)+LENGTH(NAME)-LENGTH(PATT)+1)#0 THENRESULT =TRUE ELSE  C 
      RESULT =FALSE
END ; ! OF MATCH
!
!

ROUTINE  FILESA
!THIS HAS TO BE IN A SEPARATE ROUTINE TO AVOID USING TOO MUCH STACK
!STACK IS NOT UN-DECLARED AT THE END OF A BEGIN-END BLOCK
   CONSTINTEGER  ARCHFLSIZE=500; ! Do 500 at a time.
   RECORD (AFRECF) ARRAY  APA(0:ARCHFLSIZE-1)
   NEWLINE
   FILENUM=0; !FIRST FILE TO BE PROVIDED - MOST RECENT
   CYCLE 
      MAXREC=ARCHFLSIZE; !MAX NO OF FILES ACCEPTABLE
      FLAG=DIRTOSS(DFILENAMES(USER,APA,FILENUM,MAXREC,NFILES,FSYS,1))
      IF  FLAG#0 THEN  MAXREC=0
      IF  FILENUM=0 THENSTART 
         PRINTSTRING("Archived files : "); WRITE(NFILES,1)
         NEWLINES(2)
         IF  FLAG#0 THENRETURN 
      FINISH 
      E31=0
!      FLAG=DSFI(USER,FSYS,31,0,ADDR(E31)); !DSFI ENTRY 31
 !      %IF E31_TOTSIZE > 0 %THEN %START
 !         PRINTSTRING("    Total size : ")
 !  WRITE(E31_TOTSIZE,1)
 !         PRINTSYMBOL('K')
 !      %FINISH
      I=0
      WHILE  I<MAXREC CYCLE 
         NAME=APA(I)_NAME
         IF  PATTERN="" OR  MATCH(NAME,PATTERN)=1 START 
            PRINTSTRING(NAME)
            SPACES(13-LENGTH(NAME))
            PRINTSTRING(APA(I)_DATE)
            WRITE(APA(I)_KBYTES,5)
            NEWLINE
         FINISH 
         I=I+1
      REPEAT 
      FILENUM=FILENUM+MAXREC
   REPEATUNTIL  FILENUM>=NFILES
END ; !OF FILESA
!
!
TEMPLATE="NAMES=*,OPTIONS=I,OUT="
FLAG=0
PERLINE=UINFI(15)//14; !NO OF FILENAMES PER LINE
COST=OUTSTREAM
UCTRANSLATE(ADDR(S)+1,LENGTH(S))
FILPS(TEMPLATE,S)
IF  PARMAP>7 THENSTART 
   FLAG=263
   ->ERR
FINISH 
PATTERN=SPAR(1); !MASK FOR FILENAMES
IF  PATTERN->USER.(".").PATTERN THENSTART 
   FSYS=-1
   FLAG=DFSYS(USER,FSYS)
FINISHELSESTART 
   USER=UINFS(1)
   FSYS=UINFI(1)
FINISH 
IF  FLAG#0 THEN  START 
   PRINTSTRING("No information available about user ".USER)
   NEWLINE
   RETURN 
FINISH 
PATTYPE=0; !INITIALISE
CHERISH=0
HAZARD=0
EXTRA=0
AFILE=0
PROC=0
COUNT=0
FINISHED=0
OPTIONS=SPAR(2)
IF  OPTIONS="" THEN  OPTIONS="I"
IF  OPTIONS="*" THEN  OPTIONS="ESAP"; !ALL POSSIBLE INFO
FOR  I=LENGTH(OPTIONS),-1,1 CYCLE 
   CHAR=CHARNO(OPTIONS,I)
   IF  CHAR='C' THEN  CHERISH=1 ELSEIF  CHAR='H' THEN  HAZARD=1 ELSEIF  C 
      CHAR='S' THEN  PERLINE=1 ELSEIF  CHAR='A' THEN  AFILE=1 ELSEIF  C 
      CHAR='P' THEN  PROC=1 ELSEIF  CHAR='E' THENSTART 
 ! PRINT EXTRA INFO
      EXTRA=1
      PERLINE=1
   FINISHELSEIF  CHAR='I' THENSTART 
      CHERISH=1
      HAZARD=1
   FINISH 
REPEAT 
IF  PERLINE=1 AND  CHERISH=0=HAZARD THENSTART ; ! DEAL WITH S ON ITS OWN
   CHERISH=1
   HAZARD=1
FINISH 
OUT=SPAR(3)
IF  OUT#"" START 
   SETOUTPUT(OUT,FLAG)
   ->ERR IF  FLAG#0
FINISH 
IF  PATTERN="*" THEN  PATTERN=""
E4=0
FLAG4=DSFI(USER,FSYS,4,0,ADDR(E4))
IF  FLAG4=0 THEN  NFILES=E4_FILES ELSE  NFILES=MAXPA
BEGIN 
   RECORD (FRECF)ARRAY  PA(0:NFILES-1)
   RECORD (FRECF)NAME  P

   ROUTINE  FLSORT(INTEGER  M,N)
   ! This routine sorts the records for FLIST held in %RECORD (FRECF)%ARRAY PA.
      INTEGER  I,J,K,L,N1
      RECORD (FRECF) X
    ! There are N - M + 1 elements to be sorted.
      L=M-1; ! L is never changed in this routine.  Nor are M and N.
   !  N1 = 1
   !  %WHILE N1<N-L %CYCLE
   !     N1 = 2 * N1
   !  %REPEAT
   !  N1 is now the smallest (+ve integral) power of 2 which
   !  is not less than N-M+1.  There is probably a faster way
   !  to find this, but I can't be bothered with it just now.
   !  Here it is - using the bit twiddling expression
   !    1 << ((32 - SHZ(N-L-1)) & 31)
      *lss_N; *isb_L; *isb_1; *shz_ TOS ; *lb_32; *sbb_ TOS 
      *lss_1; *rot_ B ; *st_N1
   !
   !
      CYCLE 
         N1=N1//2
    ! N1 is now zero, or else a power of 2 less than N-M+1.
         RETURNIF  N1=0
    ! N1 is now a power of 2 less than N-M+1.
         I=L; ! = M - 1.
         CYCLE 
            I=I+1
            J=I+N1
            EXITIF  J>N
            K=I
            WHILE  UCSTRING(PA(J)_NAME)<UCSTRING(PA(K)_NAME) CYCLE 
    ! J = K + N1,  K>=M,  J<=N.
               X=PA(J)
               PA(J)=PA(K)
               PA(K)=X
               J=K
               K=K-N1
               EXITIF  K<M
            REPEAT 
    ! K<M or PA(J)_NAME>=PA(K)_NAME.
    ! Every N1th. element from the Kth. to the (I+N1)th. is
    ! in ascending order.
         REPEAT 
      REPEAT 
   END ; ! of FLSORT.
   !LIST ALL FILENAMES
   IF  PROC=1 THENSTART 
      FILENUM=0
      FLAG=DFILENAMES(USER,PA,FILENUM,NFILES,COUNT,FSYS,0)
    ! **** FLAG needs translating via DIRTOSS ****
    ! **** to give Subsystem error number ****
      IF  FLAG#0 THENSTART 
         FINISHED=-1
         -> STOP
      FINISH 
      NPERM=0; NTEMP=0
      PERMK=0; TEMPK=0
      FOR  I=0,1,NFILES-1 CYCLE 
         P==PA(I)
         IF  CHARNO(P_NAME,1)#'#' THENSTART 
            IF  P_CODES&x'0C'=0 THENSTART ; !     PERMANENT
               NPERM=NPERM+1
               PERMK=PERMK+P_KBYTES
            FINISHELSESTART ; !TEMPORARY
               NTEMP=NTEMP+1
               TEMPK=TEMPK+P_KBYTES
            FINISH 
         FINISH 
      REPEAT 
      E9=0
      FLAG=FLAG4!DSFI(USER,FSYS,9,0,ADDR(E9))!DSFI(USER,FSYS,11,0,ADDR(TLIMIT))!DSFI(USER,FSYS,12,0,ADDR(MAXFSIZE))
      !Unless all calls on DSFI are successful, then fail
      IF  FLAG#0 THEN  START 
         PRINTSTRING("No information available about user ".USER)
         NEWLINE
         FINISHED=-1
         -> STOP
      FINISH 
      NEWLINE
      PRINTSTRING("Disc files  :"); WRITE(NPERM,5)
      PRINTSTRING("    Temp files  :"); WRITE(NTEMP,5)
      PRINTSTRING("    Archived files  :");WRITE(E9_ARFILES,5);NEWLINE
      PRINTSTRING("Total size  :"); WRITE(PERMK,5)
      PRINTSTRING("K   Temp total  :"); WRITE(TEMPK,5)
      PRINTSYMBOL('K'); NEWLINE
      PRINTSTRING("Total limit :"); WRITE(TLIMIT,5)
      PRINTSTRING("K   Maxfilesize :"); WRITE(MAXFSIZE,5)
      PRINTSYMBOL('K'); NEWLINE
      PRINTSTRING("Index size  :"); WRITE(E4_INDEX+1,5); !allow 1 extra Kbyte for fixed area
      PRINTSYMBOL('K')
      NEWLINES(2)
      PRINTSTRING("Index space unused:")
      NEWLINE
      PRINTSTRING("File Descs  :"); WRITE(E4_FREEDESC,5)
      PRINTSTRING("    Sect Descs  :"); WRITE(E4_FREESECDESC,5)
      PRINTSTRING("    Perm Descs  :"); WRITE(E4_FREEPERMDESC,5)
      NEWLINE
      PRINTSTRING("Archived File Descs  :");WRITE(E9_FREEFDES,5)
      PRINTSTRING("    Archived Perm Descs  :");WRITE(E9_FREEPDES,5)
      NEWLINES(2)
    ! NOW PRINT .ALL PERMISSIONS, IF ANY - BUT ONLY IF USER IS YOURSELF
      IF  USER=UINFS(1) START 
         FLAG{PRINT INDEX PERMS}=PXP(".ALL Access Permissions
   
","

")
      FINISH 
   FINISH 
   UNLESS  CHERISH=HAZARD=0 START 
      IF  COUNT=0 THENSTART 
         FILENUM=0
         FLAG=DFILENAMES(USER,PA,FILENUM,NFILES,COUNT,FSYS,0)
    ! **** FLAG needs translating via DIRTOSS ****
    ! **** to give subsystem error flag ****
         IF  FLAG#0 THENSTART 
            FINISHED=-1
            -> STOP
         FINISH 
      FINISH 
      COUNT=NFILES
      FLSORT(0,COUNT-1)
      POS=0
      IF  EXTRA=1 THEN  PRINTSTRING("  Name           Kbytes  OWNP   EEP")
      NEWLINES(2)
      FOR  I=0,1,COUNT-1 CYCLE 
         P==PA(I)
         NAME=P_NAME
         CHERSET=P_CODES&x'10'; !CHERISH STATUS SET
         ARCHSET=(P_ARCH>>7)&(P_CODES>>4); !ARCHIVE REQUEST SET
         IF  LENGTH(NAME)<2 OR  SUBSTRING(NAME,1,2)#"T#" OR  EXTRA=1 THENSTART 
    !OMIT T# FILES
            IF  CHARNO(NAME,1)#'#' AND  (PATTERN="" OR  C 
               MATCH(NAME,PATTERN)=1) THENSTART 
               IF  (CHERISH=1 AND  CHERSET#0) OR  (HAZARD=1 AND  CHERSET=0) THEN  C 
                  START 
                  IF  ARCHSET#0 THEN  PRINTSTRING("**") ELSEIF  CHERSET#0 THEN  C 
                     PRINTSTRING("* ") ELSE  PRINTSTRING("  ")
                  PRINTSTRING(NAME)
                  SPACES(LENGTH(NAME)-12)
                  IF  EXTRA=1 START ; !PRINT SIZE,OWNP,EEP,CON
                     SPACES(14-LENGTH(NAME))
                     WRITE(P_KBYTES,5)
                     SPACES(3)
                     PRINTSTRING(PPER(P_OWNP&15))
                     SPACES(3)
                     PRINTSTRING(PPER(P_EEP&7))
                  FINISH 
                  POS=POS+1
                  IF  (POS//PERLINE)*PERLINE#POS THEN  C 
                     SPACES(12-LENGTH(NAME)) ELSE  NEWLINE
               FINISH 
            FINISH 
         FINISH 
      REPEAT 
   FINISH 
STOP:
END 
IF  FINISHED#0 THEN  RETURN 
IF  AFILE#0 THEN  FILESA; !LIST FILES ON ARCHIVE
ERR:
NEWLINE
IF  COST#OUTSTREAM THENSTART 
   SELECTOUTPUT(COST)
   CLOSEST(82)
FINISH 
COMREG(24)=FLAG
IF  FLAG#0 THEN  PSYSMES(20,FLAG)
END ; !OF FILES
!
!
EXTERNALROUTINE  COPY(STRING (255) S)
INTEGER  OLDCONAD,NEWCONAD,OLDLEN,DUMMY,FLAG
RECORD (RF) RR,RN
STRING (31) OLD,NEW,NEWFILE,NEWMEMBER
STRING (7) TEMPLATE
TEMPLATE="FROM,TO"
UCTRANSLATE(ADDR(S)+1,LENGTH(S))
FILPS(TEMPLATE,S)
IF  PARMAP#3 THENSTART ; ! WRONG NO OF PARAMS
   FLAG=263
   -> ERRX
FINISH 
OLD=SPAR(1)
NEW=SPAR(2)
CONNECT(OLD,0,0,0,RR,FLAG); !{SEQ}
IF  FLAG#0 THEN  -> ERRX
IF  NEWCONNECT=0 THEN  SETUSE(OLD,1,0); !SET USE TO AVOID COPY(A,A) ETC
OLDCONAD=RR_CONAD
OLDLEN=INTEGER(RR_CONAD)
IF  NEW->NEWFILE.("_").NEWMEMBER START 
 !COPY INTO PD FILE
   MODPDFILE(2,NEWFILE,NEWMEMBER,"",FLAG)
 !DESTROY MEMBER IF NECC
   MODPDFILE(1,NEWFILE,NEWMEMBER,OLD,FLAG); !ADD NEW MEMBER
   ->ERR
FINISH 
CONNECT(NEW,0,OLDLEN,0,RN,FLAG); !CHECK FOR COPY INTO PDFILE
IF  NEWCONNECT#0 THEN  SETUSE (LASTFN, -1, 0)
IF  FLAG=0 AND  RN_FILETYPE=SSPDFILETYPE THENSTART 
   FLAG=310
   ->ERR
FINISH 
OUTFILE(NEW,OLDLEN,OLDLEN,0,NEWCONAD,FLAG); !{SEQ}
->ERR IF  FLAG#0
MOVE(OLDLEN,OLDCONAD,NEWCONAD)
DISCONNECT(NEW,DUMMY); !IGNORE FAILURE
ERR:
SETUSE(OLD,-1,0); !REMOVE USE
ERRX:
COMREG(24)=FLAG
IF  FLAG=0 THEN  PRINTSTRING(NEW." is a copy of ".OLD."
") ELSE  PSYSMES(9,FLAG)
END ; !OF COPY
!
!
EXTERNALROUTINE  NEWPDFILE(STRING (255) FILE)
INTEGER  FLAG
RECORD (FRF) FR
UCTRANSLATE(ADDR(FILE)+1,LENGTH(FILE))
FINFO(FILE,0,FR,FLAG)
IF  FLAG=0 THENSTART ; ! FILE ALREADY EXISTS
   FLAG=219
   ->ERR
FINISH 
MODPDFILE(4,FILE,"","",FLAG)
IF  FLAG#0 THEN  ->ERR
!**VERY TEMP*** WHEN DIRECTOR CORRECTED REMOVE COMMENT FROM NEXT LINE
 !PERMIT(FILE,UINFS(1),15,FLAG);          !PERMIT READ,WRITE EXECUTE AND PROTECT
ERR:

COMREG(24)=FLAG
IF  FLAG=0 THEN  PRINTSTRING("New partitioned file  '".FILE."' created
") ELSE  PSYSMES(51,FLAG)
END ; !OF NEWPDFILE
!
!
EXTERNALROUTINE  CONVERT(STRING (255) S)
!INITIAL VERSION JUST CONVERTS DATA FILE TO CHAR FILE
STRING (31) IN,OUT
INTEGER  OUTLENGTH,OUTCONAD,FLAG,DUMMY
RECORD (RF) RR
RECORD (HF) NAME  H
STRING (7) TEMPLATE
TEMPLATE="IN,OUT"
UCTRANSLATE(ADDR(S)+1,LENGTH(S))
FILPS(TEMPLATE,S)
IF  PARMAP#3 THENSTART ; ! WRONG NO OF PARAMS
   FLAG=263
   -> ERRX
FINISH 
IN=SPAR(1)
OUT=SPAR(2)
CONNECT(IN,0,0,0,RR,FLAG); !{SEQ}
-> ERRX IF  FLAG#0
IF  NEWCONNECT=0 THEN  SETUSE(IN,1,0); !SET USE TO AVOID CONVERT(A,A)
IF  RR_FILETYPE#SSDATAFILETYPE THENSTART ; ! INVALID FILETYPE
   FLAG=267
   ->ERR
FINISH 
OUTLENGTH=FLC(1,RR_CONAD,0,FLAG) {file length}
->ERR IF  FLAG#0
OUTFILE(OUT,OUTLENGTH+32,0,0,OUTCONAD,FLAG); !{SEQ}
->ERR IF  FLAG#0
H==RECORD(OUTCONAD)
H_DATAEND=OUTLENGTH+32
H_DATASTART=32
H_FILETYPE=SSCHARFILETYPE
FCONV(1,RR_CONAD,OUTCONAD+32,0,FLAG)
DISCONNECT(OUT,DUMMY)
->ERR IF  FLAG#0
PRINTSTRING("Data file ".IN." converted to character file ".OUT)
NEWLINE
ERR:
SETUSE(IN,-1,0); !REMOVE USE
ERRX:
COMREG(24)=FLAG
IF  FLAG#0 THEN  PSYSMES(54,FLAG)
END ; !OF CONVERT
!
!
EXTERNALROUTINE  DELETEDOC(STRING (255) S)
STRING (255) PARM
STRING (63) MESSAGE
RECORD (PF) P
STRING (11) IDENT
INTEGER  I,J,FLAG,TRANS
COMREG(24)=0
SETPAR(S)
CYCLE 
   PARM=SPAR(0)
   RETURN  IF  PARM=""
   TRANS=STARTSWITH(PARM,"T",-1)
   I=PSTOI(PARM); !CHECK NUMERIC
   UNLESS  1<=I<=999999 THENSTART 
      FLAG=202; !INVALID PARAMETER
      SETFNAME(PARM)
      ->ERR
   FINISH 
   IDENT=PARM
   WHILE  LENGTH(IDENT)<4 OR  LENGTH(IDENT)=5 CYCLE 
      IDENT="0".IDENT
   REPEAT ; !FOUR CHARS LONG
   IF  LENGTH(IDENT)=4 THEN  IDENT=ITOS(UINFI(1)).IDENT; !TO MAKE SPOOLR IDENT
   WHILE  LENGTH(IDENT)<6 CYCLE 
      IDENT="0".IDENT
   REPEAT 
   MESSAGE="COMMAND DELETE ".IDENT
   J=LENGTH(MESSAGE)
   P=0
   IF  TRANS=0 THEN  FLAG=DSPOOL(P,J,ADDR(MESSAGE)+1) ELSE  C 
   FLAG=DEXECMESS("FTRANS",0,J,ADDR(MESSAGE)+1)
   IF  FLAG#0 THENSTART 
      IF  FLAG=205 THEN  FLAG=318 {DOC NOT QUEUED} ELSEIF  FLAG=213 THEN  C 
         FLAG=317 {OTHER USERS DOC} ELSEIF  FLAG=236 THEN  C 
         FLAG=284 {SPOOLR FAILS} ELSEIF  FLAG<200 THEN  FLAG=DIRTOSS(FLAG)
      SETFNAME(PARM)
   FINISH 
   ERR:
   
   COMREG(24)=FLAG IF  FLAG#0
   IF  FLAG#0 THEN  PSYSMES(97,FLAG)
REPEAT 
END ; !OF DELETEDOC
!
!
EXTERNALROUTINE  DOCUMENTS(STRING (255) S)
CONSTSTRING (9) DOCINFO="T#DOCINFO"
RECORD (RF) R
RECORD (FHF) NAME  FH
RECORD (INFOF) NAME  INFO
STRING (64) MESSAGE
STRING (63) PARAM1
STRING (31) OUT
STRING (15) QUEUE,LAST QUEUE,TEMPLATE
STRING (11) IDENT
INTEGER  LM,LI,I,J,ENTRIES,FLAG,ST,COST
!
! **** ****
CONSTINTEGER  OFFSET=7; ! If FSYS numbers can get larger than 99,
 ! then this should be declared as
! %INTEGER OFFSET: see below.
! **** ****
!
CONSTSTRING (15) ARRAY  STATES(-1:7)= C 
"Completed","Deleted","Queued","Sending","Running",
"Receiving","Processing","Transferring","Held"
CONSTSTRING (5) ARRAY  PR(0:5)= C 
"OLD","Vlow","Low","Std","High","Vhigh"
CONSTSTRING (6) ARRAY  MOD(0:2)= C 
"ISO","EBCDIC","Binary"
CONSTSTRING (3) ARRAY  RERUN(0:1)= C 
"No","Yes"

ROUTINE  GET SPOOLR INFO
   RECORD (PF) P
   FLAG=DSPOOL(P,LENGTH(MESSAGE),ADDR(MESSAGE)+1)
   IF  FLAG#0 THENSTART 
      IF  FLAG>200 THEN  FLAG=284 ELSE  FLAG=DIRTOSS(FLAG)
      RETURN 
   FINISH 
   I=DFSTATUS(UINFS(1),DOCINFO.ITOS(UINFI(13)),UINFI(1),5,0)
 !MAKE TEMP
   CONNECT(DOCINFO,3,0,0,R,FLAG)
   IF  FLAG#0 THENRETURN 
   FH==RECORD(R_CONAD)
   ENTRIES=(FH_END-FH_START)//256
   IF  ENTRIES>0 AND  INTEGER(R_CONAD+32)#1 THENSTART 
 ! WRONG VSN
      FLAG=284
      RETURN 
   FINISH 
END ; !OF GET SPOOLR FILE
!
!

ROUTINE  PS(STRING (63) TYPE,VALUE)
   RETURNIF  VALUE=""
   IF  OUTPOS#0 THENSTART 
      PRINTSTRING(", ")
      IF  OUTPOS+LENGTH(TYPE)+LENGTH(VALUE)+2>72 THEN  NEWLINE
   FINISH 
   PRINTSTRING(TYPE."=".VALUE)
END ; !OF PS
!
!

STRINGFN  DT(INTEGER  PACKED)
   RESULT =UNPACKDATE(PACKED)." ".UNPACKTIME(PACKED)
END ; !OF DT
!
!
!*
!*
FLAG = 0
TEMPLATE="NUMBER=,OUT="
IF  NEWCONNECT#0 THEN  R = 0
UCTRANSLATE(ADDR(S)+1,LENGTH(S))
FILPS(TEMPLATE,S)
COST=OUTSTREAM
UNLESS  0<=PARMAP<=3 THENSTART ; ! WRONG NO OF PARAMS
   FLAG=263
   ->ERR
FINISH 
PARAM1=SPAR(1)
OUT=SPAR(2)
IF  OUT#"" THENSTART 
   SETOUTPUT(OUT,FLAG)
   IF  FLAG#0 THEN  ->ERR
FINISH 
IF  STARTSWITH(PARAM1,"T",-1)#0 THEN  START 
   TRANSFERS(PARAM1)
   ->ERR
FINISH 
DESTROY(DOCINFO,I); !IGNORE FLAG
IF  PARAM1#"" AND  '0'<=CHARNO(PARAM1,1)<='9' THENSTART 
 !IDENT GIVEN
   IDENT<-PARAM1
   I=PSTOI(IDENT); !CHECK NUMERIC
   UNLESS  1<=I<=999999 THENSTART 
      FLAG=202; !INVALID PARAMETER
      SETFNAME(IDENT)
      ->ERR
   FINISH 
   LI=LENGTH(IDENT)
   IF  LI<6 THENSTART 
 !
 ! **** ****
 ! OFFSET = 7 would be necessary if we had to cope with UINFI(1)>99.
 ! **** ****
 !
      IF  LI<=4 THENSTART 
         MESSAGE=ITOS(UINFI(1))
         LM=LENGTH(MESSAGE); ! I'll assume that MESSAGE is non-null,
 ! i.e., that LM>0 ,
 ! and also that LM<=2,
 ! i.e., that UINFI(1)<100.
 !
 ! **** ****
 ! If UINFI(1) can be > 99, we will need to do:
 ! %IF LM>2 %THEN OFFSET = LM + 5
 ! **** ****
 !
      FINISHELSE  LM=0
      MOVE(LI,ADDR(IDENT)+1,ADDR(IDENT)+OFFSET-LI)
      FILL(6-LI,ADDR(IDENT)+1,'0')
      MOVE(LM,ADDR(MESSAGE)+1,ADDR(IDENT)+OFFSET-4-LM)
      LENGTH(IDENT)=OFFSET-1
   FINISH 
   MESSAGE="COMMAND FIND ".IDENT.",".DOCINFO.ITOS(UINFI(13))
   GET SPOOLR INFO
   IF  FLAG#0 THEN  ->ERR
   IF  ENTRIES#1 THENSTART ; !OTHER USERS DOC
      FLAG=317
      SETFNAME(PARAM1)
      ->ERR
   FINISH 
   INFO==RECORD(R_CONAD+32)
   IF  INFO_PRIORITY<0 THENSTART 
      IF  INFO_STATE=1 THEN  INFO_STATE=7; !HELD, NOT QUEUED
      INFO_PRIORITY=-INFO_PRIORITY
   FINISH 
   ST=INFO_STATE
   IF  ST=0 AND  INFO_DT STARTED#0 THEN  ST=-1
 !COMPLETED
   PS("Name",INFO_NAME)
   MESSAGE=STATES(ST)
   IF  INFO_DT DELETED#0 THEN  MESSAGE=MESSAGE." at ".DT(INFO_DT DELETED)
   PS("State",MESSAGE)
   PS("Queue",".".INFO_DEST)
   PS("Source",INFO_SRCE)
   PS("Out",INFO_OUTPUT)
   PS("Received",DT(INFO_DT RECEIVED))
   IF  INFO_DT STARTED#0 THEN  PS("Started",DT(INFO_DT STARTED))
   IF  INFO_TIME>0 THEN  PS("Time",ITOS(INFO_TIME)."s") ELSESTART 
      I=(INFO_DATALENGTH+1023)>>10
      PS("Size",ITOS(I)."K")
   FINISH 
   PS("Priority",PR(INFO_PRIORITY))
   IF  INFO_START AFTER DT#0 THEN  PS("Start after",DT(INFO_START AFTER DT))
   IF  INFO_FORMS#0 THEN  PS("Forms",ITOS(INFO_FORMS))
   PS("Mode",MOD(INFO_MODE))
   IF  INFO_COPIES>1 THEN  PS("Copies",ITOS(INFO_COPIES))
   IF  INFO_ORDER>1 THEN  PS("Order",ITOS(INFO_ORDER))
   IF  INFO_TIME>0 THEN  PS("Rerun",RERUN(INFO_RERUN))
   IF  INFO_TAPES>0 THEN  PS("Tape decks",ITOS(INFO_TAPES))
   IF  INFO_DISCS>0 THEN  PS("Disc drives",ITOS(INFO_DISCS))
   MESSAGE=""
   FOR  I=8,-1,1 CYCLE 
      MESSAGE=MESSAGE.INFO_VOL LABEL(I)
      IF  MESSAGE#"" AND  CHARNO(MESSAGE,LENGTH(MESSAGE))#',' THEN  C 
         MESSAGE=MESSAGE.","
   REPEAT 
   IF  MESSAGE#"" THENSTART 
      LENGTH(MESSAGE)=LENGTH(MESSAGE)-1; ! Discard final comma.
      PS("Volumes",MESSAGE)
   FINISH 
   IF  INFO_FAILS>0 THEN  PS("Fails",ITOS(INFO_FAILS))
   NEWLINE
!*
FINISHELSESTART ; !QUEUE INFO WANTED
!*
   QUEUE<-PARAM1
   IF  QUEUE#"" THENSTART 
      IF  CHARNO(QUEUE,1)='.' THEN  CHOPLDR(QUEUE,1) ELSESTART 
         FLAG=202; !INVALID PARAMETER
         SETFNAME(QUEUE)
         ->ERR
      FINISH 
   FINISH 
   MESSAGE="COMMAND QUEUE ".QUEUE.",".DOCINFO.ITOS(UINFI(13))
   GET SPOOLR INFO
   IF  FLAG#0 THEN  ->TER
   IF  ENTRIES<1 THENSTART 
      PRINTSTRING("No documents found")
      IF  QUEUE#"" THEN  PRINTSTRING(" for .".QUEUE)
      NEWLINE
      ->TER
   FINISH 
   LAST QUEUE=""
   NEWLINE; SPACES(24)
   PRINTSTRING("Ident   Date      Time  Priority  Size   Ahead")
   FOR  I=1,1,ENTRIES CYCLE 
      INFO==RECORD(R_CONAD+I*256-224)
      IF  INFO_DEST#LAST QUEUE THENSTART ; !ADD SUBHEADING FOR Q
         NEWLINE
         PRINTSTRING("Queue .".INFO_DEST)
         NEWLINES(2)
         LAST QUEUE=INFO_DEST
      FINISH 
      IF  INFO_PRIORITY<0 THENSTART 
         PRINT SYMBOL('*')
         INFO_PRIORITY=-INFO_PRIORITY
      FINISH 
      PRINTSTRING(INFO_NAME)
 ! If the FSYS in IDENT is the same as the user's FSYS,
 ! then strip it off:
      IF  PSTOI(SUBSTRING(INFO_IDENT,1,2))=UINFI(1) THENSTART 
         J=3
         WHILE  CHARNO(INFO_IDENT,J)='0' AND  J<6 CYCLE 
            J=J+1
         REPEAT 
         INFO_IDENT=SUBSTRING(INFO_IDENT,J,6)
      FINISH 
      IF  OUTPOS>23 OR  OUTPOS+LENGTH(INFO_IDENT)>27 THEN  NEWLINE
      SPACES(28-OUTPOS-LENGTH(INFO_IDENT))
      PRINTSTRING(INFO_IDENT)
      SPACES(30-OUTPOS)
      PRINTSTRING(DT(INFO_DT RECEIVED))
      PRINTSTRING("   ".PR(INFO_PRIORITY))
      SPACES(56-OUTPOS)
      IF  INFO_TIME>0 THENSTART 
         WRITE(INFO_TIME,5)
         PRINTSTRING("s")
         IF  INFO_AHEAD=0 AND  1<INFO_STATE<6 THENSTART 
            SPACES(6)
            PRINT STRING(STATES(INFO_STATE))
         FINISHELSESTART 
            WRITE(INFO_AHEAD,6)
            PRINTSTRING("s")
         FINISH 
      FINISHELSESTART 
         WRITE((INFO_DATALENGTH+1023)>>10,5)
         PRINTSTRING("K")
         IF  INFO_AHEAD=0 AND  1<INFO_STATE<6 THENSTART 
            SPACES(6)
            PRINT STRING(STATES(INFO_STATE))
         FINISHELSESTART 
            WRITE((INFO_AHEAD+1023)>>10,6)
            PRINTSTRING("K")
         FINISH 
      FINISH 
      NEWLINE
   REPEAT 
   NEWLINE
TER:
   IF  QUEUE="" OR  QUEUE="FTP" THEN  TRANSFERS("")
FINISH 
ERR:
IF  NEWCONNECT#0 AND  R_CONAD#0 THEN  DISCONNECT (DOCINFO,I)
IF  COST#OUTSTREAM THENSTART 
   SELECTOUTPUT(COST)
   CLOSEST(82)
FINISH 
COMREG(24)=FLAG
IF  FLAG#0 THEN  PSYSMES(96,FLAG)
END ; !OF DOCUMENTS
!
!
ROUTINE  DETACHOBEY(INTEGER  MODE, STRING (255) S)
!MODE=0      NORMAL DETACH MODE
!MODE=1        DETACHJOB MODE - CALLS OBEYJOB TO EXECUTE
RECORD (PF) P
RECORD (JTABF) ARRAY  TAB(1:16)
CONSTSTRING (5) DETFILE="T#DET"
STRING (15) IDENT
STRING (255) INPUT,MESSAGE,WORK,DSTR,PRIORITY
STRING (255) NAME  LINE
STRING (31) CONTROL
RECORD (RF) RR
INTEGER  SECS,FLAG,TOP,I,CIST,CALLERSMODE
STRING (8) SSECS
STRING (27) TEMPLATE
BYTEINTEGER  CHAR
TEMPLATE="FILE,SECONDS=".ITOS(DEFJCPL).",CONTROL="
UCTRANSLATE(ADDR(S)+1,LENGTH(S))
FILPS(TEMPLATE,S)
IDENT=""
MESSAGE=""
CIST=-1; !TO SHOW NO SELECT DONE
IF  PARMAP&3#3 OR  PARMAP>7 THENSTART ; ! WRONG NO OF PARAMS
   FLAG=263
   ->ERR
FINISH 
INPUT=SPAR(1)
SSECS=SPAR(2)
SECS=PSTOI(SSECS)
UNLESS  0<SECS<=MAXJCPL THENSTART ; !LIMIT HELD AS SECS
   FLAG=202
   SETFNAME(SSECS)
   ->ERR
FINISH 
CONTROL=SPAR(3)
IF  CONTROL#"" THENSTART ; !READ FURTHER PARAMS FROM CONTROL
   ! See if input is coming from someone typing at a console.
   IF  CONTROL=".IN" AND  UINFI(2)=1 THEN  CALLERSMODE=1 ELSE  CALLERSMODE=0
   CIST=INSTREAM
   SETINPUT(CONTROL,FLAG)
   IF  FLAG#0 THEN  ->ERR
   PROMPT("DOC param:")
   CYCLE 
      IF  FLAG=0 THEN  LINE==CONTROL LINE(FLAG) ELSE  FLAG=-1
      EXITIF  FLAG<0
      CASTOUT(LINE)
      EXITIF  LINE=".END"
      IF  LINE->DSTR.(",").WORK THEN  START 
         ! More than one param provided.
         ! If running in foreground with input from the console then
         ! warn and offer another chance else fatal error.
         PRINTSTRING( "**Syntax error - Only one param per line")
         IF  CALLERSMODE#0 THEN  PRINTSTRING("...Try again
")       AND  CONTINUE  ELSE  START 
            FLAG=320; !Illegal parameter format
            NEWLINE
            ->ERR
         FINISH 
      FINISH 
      IF  MACHINE=2960 THENSTART 
         IF  STARTSWITH(LINE,"PRTY=",0)#0 AND  UINFI(4)>9 THEN  LINE="PRTY=STD"
      FINISH 
      IF  LINE->DSTR.("NAME=").WORK AND  DSTR="" THEN  IDENT=WORK ELSEIF  C 
      LINE->DSTR.("OUT=.").WORK AND  DSTR="" THEN  LINE="OUT=".WORK ELSE  C 
      IF  LINE->DSTR.("OUTNAME=").WORK AND  DSTR="" THEN  START 
         FLAG=CHECKFILENAME(WORK,5);  ! Check for valid own filename
         ! However this is not enough since CHECKFILENAME is quite happy
         ! with an all numeric filename so .......
         IF  LENGTH(WORK)>7 AND  CHARNO(WORK,7)='.' THEN  CHAR=CHARNO(WORK,8) C 
         ELSE  CHAR=CHARNO(WORK,1)
         UNLESS  'A'<=CHAR<='Z' THEN  SSOWN_SSFNAME=WORK AND  FLAG=220
         IF  FLAG#0 THEN  START 
            IF  CALLERSMODE#0 THEN  START 
               PRINTSTRING("**Syntax error - Invalid filename ".WORK."...Try again
")
               FLAG=0
               CONTINUE 
            FINISH  ELSE  ->ERR
         FINISH 
      FINISH  ELSE  IF  STARTSWITH(LINE,"PRTY=",0)#0 THEN  PRIORITY=LINE
      MESSAGE=MESSAGE.",".LINE
   REPEAT 
FINISH 
TOP=16
JOINFILES(INPUT,TAB,0,1,TOP,FLAG)
->ERR IF  FLAG#0
JOIN(TAB,1,TOP,DETFILE,0,FLAG)
->ERR IF  FLAG#0
CONNECT(DETFILE,3,0,0,RR,FLAG)
->ERR IF  FLAG#0
INTEGER(RR_CONAD+24)=MODE; !TO INDICATE TYPE OF PROCESSING
DISCONNECT(DETFILE,FLAG)
IF  IDENT="" THENSTART 
   IDENT<-INPUT; !FIRST 15 CHAS OF INPUT FILENAMES
   MESSAGE=MESSAGE.",NAME=".IDENT
FINISH 
MESSAGE="DOCUMENT SRCE=".DETFILE.ITOS(UINFI(13)).",DEST=BATCH,TIME=".ITOS C 
   (SECS).",START=".ITOS(RR_DATASTART).",LENGTH=".ITOS C 
   (RR_DATAEND-RR_DATASTART).MESSAGE
P=0; ! CLEAR OUT RECORD
FLAG=DSPOOL(P,LENGTH(MESSAGE),ADDR(MESSAGE)+1)
IF  203<=FLAG<=204 THENSTART ; ! QUEUE FULL:
   FLAG=331
   ->ERR
FINISH 
IF  FLAG=237 THENSTART ; ! Invalid OUT=
   FLAG=339
   ->ERR
FINISH 
IF  FLAG=225 THENSTART 
   SETFNAME(PRIORITY)
   FLAG=202
   ->ERR
FINISH 
! We could also check for 238 (invalid OUTLIM=) and 239 (invalid OUTNAME=),
! but both of those are adequately handled by the following code:
! ** This is not true for 239 at any rate, SPOOLR doesn't check.
! ** Invalid OUTNAME is intercepted above.
IF  P_P3#0#P_P1 START 
   P_P3=P_P3+9; !ALLOW FOR "DOCUMENT "
   PRINTSTRING("
Incorrect parameter - ")
   FOR  I=P_P3-1,-1,1 CYCLE ; !P3 POINTS TO COMMA AT END OF INVALID PARAM
      IF  CHARNO(MESSAGE,I)=',' THENSTART ; !PREVIOUS COMMA
         WHILE  I<P_P3 CYCLE 
            I=I+1
            PRINTSYMBOL(CHARNO(MESSAGE,I))
         REPEAT 
         EXIT 
      FINISH 
   REPEAT 
   FLAG=0
   ->ERR
FINISH 
->ERR IF  FLAG#0
PRINTSTRING(INPUT." is Batch queue entry")
WRITE(P_P2&x'FFFFFF',1); !SPOOLER IDENT LESS FSYS
PRINT STRING(".  Time limit ".ITOS(SECS)." secs.
")
ERR:
COMREG(24)=FLAG
IF  FLAG#0 THEN  PSYSMES(13,FLAG)
IF  CIST>=0 THENSTART 
   SELECTINPUT(CIST)
   CLOSEST(81)
FINISH 
END ; !OF DETACHOBEY
!
!
EXTERNALROUTINE  DETACH(STRING (255) S)
DETACHOBEY(1,S)
END ; !OF DETACH
!
!
EXTERNALROUTINE  DETACHJOB(STRING (255) S)
DETACHOBEY(0,S)
END ; !OF DETACHJOB
!
!
EXTERNALROUTINE  DISCARD(STRING (255) CFILE)
STRING (80) FILE,DATE
INTEGER  FLAG,COUNT,CIST,INFILE
ROUTINE  GETFILEANDDATE
   STRING (255) NAME  LINE
   STRING (255) LINE1
   INTEGER  FLAG
   PROMPT("File Date:")
   LINE==CONTROL LINE(FLAG)
   IF  FLAG#0 THENSTART ; !SIGNAL END OF LIST
      FILE=".END"
      RETURN 
   FINISH 
 ! Remove multiple spaces:
   LENGTH(LINE)=SINGLE SPACES(LENGTH(LINE),ADDR(LINE)+1,ADDR(LINE)+1)
 ! Remove leading space (there can be at most one, after SINGLE SPACES):
   IF  CHARNO(LINE,1)=' ' THENSTART 
      CHARNO(LINE,1)=LENGTH(LINE)-1
      LINE==STRING(ADDR(LINE)+1)
   FINISH 
   UNLESS  LINE->FILE.(" ").DATE THENSTART 
      FILE=LINE
      DATE=""
   FINISH 
   UCTRANSLATE(ADDR(FILE)+1,LENGTH(FILE))
   IF  DATE->DATE.(" ").LINE1 THENSTART 
   FINISH ; !REMOVE REST OF LINE
END ; !OF GETFILEANDDATE
!
!
COUNT=0
CIST=-1
IF  CFILE#"" START ; !READ NAMES FROM CFILE
   UCTRANSLATE(ADDR(CFILE)+1,LENGTH(CFILE))
   SETINPUT(CFILE,FLAG)
   ->ERR IF  FLAG#0
   CIST=INSTREAM
   INFILE=1
FINISHELSE  INFILE=0; !INPUT FROM .IN
CYCLE 
   GETFILEANDDATE
   ->SUMMARY IF  FILE=".END"; !TERMINATOR
   UNLESS  1<=LENGTH(FILE)<=11 AND  LENGTH(DATE)=8 START 
      IF  INFILE=0 THEN  PRINTSTRING("Wrong format - should be:
<filename> <date>
e.g.
DESFILE 23/11/78
")
   FINISHELSESTART 
      FLAG=DDESTROY(UINFS(1),FILE,DATE,UINFI(1),1)
 !DESTROY ARCHIVED FILE
      IF  FLAG#0 START 
         IF  INFILE=0 THEN  PRINTSTRING("Not found
")
      FINISHELSE  COUNT=COUNT+1
   FINISH 
REPEAT 
SUMMARY:

NEWLINES(2)
PRINTSTRING("Number of files discarded:")
WRITE(COUNT,1)
NEWLINES(2)
FLAG=0
ERR:
IF  CIST>=0 THENSTART 
   SELECTINPUT(CIST)
   CLOSEST(81)
FINISH 
COMREG(24)=FLAG
IF  FLAG#0 THEN  PSYSMES(27,FLAG)
END ; !OF DISCARD
!
!
EXTERNALROUTINE  CHERISH(STRING (255) S)
STRING (31) FILE
INTEGER  FLAG
SETPAR(S)
FLAG=0
CYCLE 
   FILE=SPAR(0)
   ->ERR IF  FILE=""; !END OF LIST
   FSTATUS(FILE,1,0,FLAG); !SET CHERISH BIT
   IF  FLAG#0 THEN  PSYSMES(5,FLAG)
 !IGNORE FAILURE IN DISCONNECT
REPEAT 
ERR:

COMREG(24)=FLAG
END ; !OF CHERISH
!
!
EXTERNALROUTINE  HAZARD(STRING (255) S)
STRING (31) FILE
INTEGER  FLAG
SETPAR(S)
FLAG=0
CYCLE 
   FILE=SPAR(0)
   IF  FILE="" THEN  ->ERR
   FSTATUS(FILE,0,0,FLAG); !REMOVE CHERISH STATUS
   IF  FLAG#0 THEN  PSYSMES(22,FLAG)
   FSTATUS(FILE,2,0,FLAG); !REMOVE 'ARCHIVE REQUESTED'
REPEAT 
ERR:

COMREG(24)=FLAG
END ; !OF HAZARD
!
!
EXTERNALROUTINE  ARCHIVE(STRING (255) S)
STRING (31) FILE
INTEGER  DUMMY,FLAG
SETPAR(S)
FLAG=0
CYCLE 
   FILE=SPAR(0)
   IF  FILE="" THEN  ->ERR
   FSTATUS(FILE,3,0,FLAG)
   IF  FLAG#0 THEN  PSYSMES(3,FLAG) ELSESTART 
      FSTATUS(FILE,1,0,DUMMY)
 !CHERISH IT AS WELL
   FINISH 
REPEAT 
ERR:

COMREG(24)=FLAG
END ; !OF ARCHIVE
!
!
EXTERNALROUTINE  AWAITRESTORES(STRING (255) S)
INTEGER  FLAG
IF  UINFI(2)#2 THENRETURN ; !not a batch job- ignore call
FLAG=DRESTORE(UINFS(1),"","",UINFI(1),0); !volume will send a reply when all restores for this user completed
END ; !of awaitrestores
!
!
IF  FUNDSON#0 THEN  START 
EXTERNALROUTINE  DONATEFUNDS(STRING (255) S)
INTEGER  FLAG,PENCE,POUNDS
STRING (31) MONEY,TOUSER,SPOUNDS,SPENCE
STRING (11) TEMPLATE
TEMPLATE="POUNDS,TO"
UCTRANSLATE(ADDR(S)+1,LENGTH(S))
FILPS(TEMPLATE,S)
IF  PARMAP#3 THENSTART ; ! WRONG NUMBER OF PARAMS
   FLAG=263
   ->ERR
FINISH 
MONEY=SPAR(1)
UNLESS  MONEY->SPOUNDS.(".").SPENCE THENSTART ; ! NO PENCE SPECIFIED
   SPENCE="0"
   SPOUNDS=MONEY
FINISH 
IF  SPOUNDS="" THEN  SPOUNDS="0"
POUNDS=PSTOI(SPOUNDS)
IF  SPENCE="" THEN  SPENCE="0"
PENCE=PSTOI(SPENCE)
IF  POUNDS<0 OR  PENCE<0 THENSTART ; ! INVALID PARAMETER
   SETFNAME(MONEY)
   FLAG=202
   ->ERR
FINISH 
TOUSER=SPAR(2)
IF  LENGTH(TOUSER)#6 THENSTART ; ! INVALID PARAMETER
   SETFNAME(TOUSER)
   FLAG=202
   ->ERR
FINISH 
PENCE=100*POUNDS+PENCE
IF  UINFS(9)#"" THENSTART ; ! GROUP MEMBERS CANNOT DONATE
   FLAG=333
   ->ERR
FINISH 
IF  PENCE>UINFI(20) THENSTART ; ! INSUFFICIENT FUNDS
   FLAG=334
   ->ERR
FINISH 
FLAG=DDONATE(TOUSER,-1,PENCE*100)
FLAG=DIRTOSS(FLAG)
IF  FLAG#0 THEN  SETFNAME(TOUSER)
ERR:
COMREG(24)=FLAG
IF  FLAG#0 THEN  PSYSMES(101,FLAG)
END ; !OF DONATEFUNDS
!
!
EXTERNALROUTINE  FUNDS(STRING (255) S)
CONSTRECORD (COMF)NAME  COM = X'80C00000'
INTEGER  PENCE, NPENCE, SESSION
STRING (6) HOLDER
HOLDER=UINFS(9)
PENCE=UINFI(20)
PRINTSTRING("Funds=")
PRINTSTRING(ITOS(PENCE//100).".")
NPENCE=PENCE-100*(PENCE//100)
IF  NPENCE<10 THEN  PRINTSTRING("0")
PRINTSTRING(ITOS(NPENCE))
IF  HOLDER#"" THEN  PRINTSTRING(" held by ".HOLDER)
PRINTSTRING(", users=")
PRINTSTRING(ITOS(USERNO-SYSPROCS))
SESSION=UINFI(2)
IF  SESSION=1 THEN  START 
   PRINT STRING (", scarcity/pre-emption at ")
   PRINTSTRING(ITOS(COM_RATION>>24))
   PRINTSTRING("/")
   PRINTSTRING(ITOS((COM_RATION>>16)&X'000000FF'))
   PRINTSTRING(".")
   NEWLINE
FINISH 
IF  SCARCEWORD&x'FF'>=SCARCEWORD>>24 THENSTART 
 ! INTERACTIVE USERS > SCARCITY LIMIT
   SSOWN_SCARCITYFOUND=1
   PRINTSTRING("**Resources are Scarce.")
   IF  UINFI(20)=0 THEN  PRINTSTRING("  You are liable to pre-emption.")
   NEWLINE
FINISH 
END ; !OF FUNDS
FINISH 

!
!
EXTERNALROUTINE  LIST(STRING (255) S)
!***********************************************************************
!*                                                                     *
!* LIST accepts concatenated filenames of type CHARACTER or DATA. It   *
!* is necessary to call JOINFILes and JOIN if the output is directed   *
!* to other than .OUT or if the file is a DATA file.                   *
!*                                                                     *
!***********************************************************************
CONSTINTEGER  BANNERLENGTH=2048; !room for banner
CONSTINTEGER  MFNL=11; ! Max. length of name acceptable to SPOOLER.
 ! (**** should it be 31? ****)
INTEGER  FLAG,FIRST,LAST,NJ,JMODE,COPIES,FORMS,PRINTER,GAP
STRING (11) OUTPUT
RECORD (RF) RR
STRING (255) FILENAMES,HEADER
STRING (39) TEMPLATE
STRING (11) NAME; ! Should be (MFNL).
STRING (8) SCOPIES,SFORMS,FE
STRING (15) DEVICE,REST
RECORD (JTABF) ARRAY  TAB(0:18); !allow room for extra space for banners

TEMPLATE="FILES,DEVICE=.OUT,COPIES=,SPFORMS=,FE="
NJ=0; ! JOIN not needed.
UCTRANSLATE(ADDR(S)+1,LENGTH(S))
FILPS(TEMPLATE,S)
IF  PARMAP&1=0 OR  PARMAP>31 THENSTART 
   FLAG=263
   ->ERR
FINISH 
FILENAMES=SPAR(1)
FLAG=LENGTH(FILENAMES)
IF  FLAG<=MFNL THEN  NAME<-FILENAMES ELSESTART 
   NAME<-SUBSTRING(FILENAMES,FLAG-MFNL+1,FLAG)
   FIRST=1
   LAST=CHARNO(NAME,1)
   WHILE  FIRST<=MFNL AND  LAST#'+' AND  LAST#'.' AND  LAST#'_' CYCLE 
      FIRST=FIRST+1
      LAST=CHARNO(NAME,FIRST)
   REPEAT 
   IF  1<FIRST<=MFNL THENSTART 
      IF  FIRST>2 THEN  NAME<-SUBSTRING(NAME,FIRST-1,MFNL)
      CHARNO(NAME,1)='#'
   FINISH 
FINISH 
IF  FILENAMES->HEADER.("+").HEADER THEN  NJ=1; ! Needs JOIN.
DEVICE=SPAR(2)
IF  DEVICE="" THEN  DEVICE=".OUT"
SCOPIES=SPAR(3); !NO OF COPIES
IF  SCOPIES#"" THENSTART 
   COPIES=PSTOI(SCOPIES)
 ! COPIES MUST BE AN INTEGER IN RANGE 1-15
   UNLESS  1<=COPIES<=15 THENSTART 
      SETFNAME(SCOPIES)
      FLAG=202
      ->ERR
   FINISH 
FINISHELSE  COPIES=0; !DEFAULT - MEANS 1 COPY OF COURSE!
SFORMS=SPAR(4); !FORMS IN RANGE 0-255
IF  SFORMS#"" START 
   FORMS=PSTOI(SFORMS)
 ! FORMS MUST BE INTEGER IN RANGE 0 - 255
   UNLESS  0<=FORMS<=255 THENSTART 
      SETFNAME(SFORMS)
      FLAG=202
      ->ERR
   FINISH 
FINISHELSE  FORMS=0; !DEFAULT
FE=SPAR(5); !FORMAT EFFECTORS IN FILE
IF  FE="FE" THEN  JMODE=2 ELSE  JMODE=0; !SET BIT IN MODE
IF  (DEVICE->REST.(".GP") OR  DEVICE->REST.(".SGP") OR  C 
   DEVICE->REST.(".B")) AND  REST="" THENSTART 
   NJ=1; ! Needs JOIN.
   JMODE=JMODE!1
FINISH 
IF  DEVICE=".OUT" AND  NJ=0 THENSTART 
   CONNECT(FILENAMES,0,0,0,RR,FLAG); !{SEQ}
   ->ERR IF  FLAG#0
   IF  RR_FILETYPE#SSCHARFILETYPE OR  FE="FE" THEN  ->JOINUP
   OUTOUT(RR_CONAD+RR_DATASTART,RR_DATAEND-RR_DATASTART)
   IF  NEWCONNECT#0 THEN  SETUSE (FILENAMES, -1, 0)
   ->ERR
FINISH 
IF  CHARNO(DEVICE,1)#'.' THENSTART ; ! SIMPLE CHECK ON DEVICE CODE
   FLAG=264
   SETFNAME(DEVICE)
   ->ERR
FINISH 
JOINUP:
IF  LENGTH(DEVICE)>=3 AND  SUBSTRING(DEVICE,2,3)="LP" THEN  PRINTER=1 ELSE  C 
   PRINTER=0
OUTPUT="T#LIST".NEXTTEMP
FIRST=1; 
LAST=17; !MAXIMUM OF 16 FILES
JOINFILES(FILENAMES,TAB,JMODE,FIRST,LAST,FLAG)
->ERR IF  FLAG#0
IF  PRINTER=0 THEN  GAP=0 ELSE  GAP=BANNERLENGTH
JOIN2(TAB,FIRST,LAST,OUTPUT,JMODE&2,GAP,FLAG)
->ERR IF  FLAG#0
IF  DEVICE=".OUT" THENSTART 
   CONNECT(OUTPUT,0,0,0,RR,FLAG); !{SEQ}
   ->ERR IF  FLAG#0
   OUTOUT(RR_CONAD+RR_DATASTART,RR_DATAEND-RR_DATASTART)
   IF  NEWCONNECT#0 THEN  SETUSE (OUTPUT, -1, 0)
   DESTROY(OUTPUT,FLAG)
   ->ERR
FINISH 
SENDFILE(OUTPUT,DEVICE,NAME,COPIES,FORMS,FLAG)
ERR:

COMREG(24)=FLAG
IF  FLAG#0 THEN  PSYSMES(29,FLAG)
END ; !OF LIST
!
!
!
!
EXTERNALROUTINE  RESTORE(STRING (255) S)
RECORD (FRF) FR
INTEGER  FLAG,FSYS
STRING (31) FILE,DATE,OWNER
STRING (11) TEMPLATE
TEMPLATE="FILE,DATE="
UCTRANSLATE(ADDR(S)+1,LENGTH(S))
FILPS(TEMPLATE,S)
 ! FIRST PARAMETER IS OBLIGATORY, SECOND OPTIONAL
IF  1#PARMAP#3 THENSTART 
   FLAG=263
   ->ERR
FINISH 
FILE=SPAR(1)
UNLESS  FILE->OWNER.(".").FILE THEN  OWNER=UINFS(1)
FINFO(OWNER.".".FILE,0,FR,FLAG)
IF  FLAG=0 THEN  FLAG=219; !FILE EXISTS - SHOULD NOT
!this test is not perfect - the file may be crated before the file
!gets back from ARCHIVE. Or may exist but not be permitted.
IF  FLAG#218 THEN  ->ERR; !SOME FAULT OTHER THAN DOES NOT EXIST
DATE=SPAR(2)
IF  OWNER=UINFS(1) THEN  FSYS=UINFI(1) ELSE  FSYS=-1; !my FSYS or don't know
FLAG=DRESTORE(OWNER,FILE,DATE,FSYS,0)
IF  FLAG=102 THEN  FLAG=306 ELSE  FLAG=DIRTOSS(FLAG)
IF  DATE#"" THEN  SETFNAME(FILE." dated ".DATE) ELSE  SETFNAME(FILE)
 !SPECIAL CASE FOR DUPLICATE REQUEST
ERR:

COMREG(24)=FLAG
IF  FLAG#0 THEN  PSYSMES(65,FLAG)
END ; !OF RESTORE
!
!
EXTERNALROUTINE  TELL(STRING (255) S)
CONSTINTEGER  MAXMSIZE=2000; ! Max length of message
RECORD (FRF) FR
RECORD (RF) RR
STRING (31) FILE,USER
BYTEINTEGERARRAY  IN(1:MAXMSIZE)
INTEGER  FLAG,LEN,START,CH,NLSW,FSYS
STRING (11) TEMPLATE
TEMPLATE="USER,FILE="
UCTRANSLATE(ADDR(S)+1,LENGTH(S))
FILPS(TEMPLATE,S)
IF  1#PARMAP#3 THENSTART 
   FLAG=263
   ->ERR
FINISH 
USER=SPAR(1); ! Destination user
IF  LENGTH(USER)#6 THEN  FLAG=201 ELSESTART 
   FSYS=-1
   FLAG=DIRTOSS(DFSYS(USER,FSYS)); ! See if user exists
FINISH 
IF  FLAG=201 THENSTART ; ! Invalid user name, or does not exist.
   SETFNAME(USER)
   ->ERR
FINISH 
FLAG=0
IF  PARMAP=1 START ; ! Read from terminal
   NLSW=1
   PROMPT("Text:")
   FOR  LEN=1,1,MAXMSIZE CYCLE 
      READCH(CH)
      IF  NLSW=1 AND  CH='*' AND  NEXTCH=NL THENSTART 
         SKIPSYMBOL
         EXIT 
      FINISH 
      IF  CH=25 THENSTART ; ! End of file typed
         FLAG=IOCP(12,0); ! Reset end of file from terminal
         EXIT 
      FINISH 
      IN(LEN)=CH
      IF  CH=NL THEN  NLSW=1 ELSE  NLSW=0
   REPEAT 
   LEN=LEN-1
   START=ADDR(IN(1))
   FLAG=0
FINISHELSESTART ; ! Read message from file
   FILE=SPAR(2)
   CONNECT(FILE,0,0,0,RR,FLAG); !{SEQ}
   ->ERR IF  FLAG#0
   IF  NEWCONNECT#0 THEN  SETUSE (LASTFN, -1, 0)
   IF  RR_FILETYPE#SSCHARFILETYPE THENSTART 
      FLAG=267
      SETFNAME(FILE)
      ->ERR
   FINISH 
   LEN=RR_DATAEND-RR_DATASTART
   IF  LEN>MAXMSIZE THEN  LEN=MAXMSIZE
   START=RR_CONAD+RR_DATASTART
FINISH 
->ERR IF  LEN=0; ! Ignore null message
FLAG=DMESSAGE2(USER,LEN,1,0,FSYS,START); ! Forward message
IF  0#FLAG#61 THENSTART ; ! Some sort of failure
   FLAG=DIRTOSS(FLAG)
   ->ERR
FINISH 
IF  FLAG=0 THEN  PRINTSTRING("Message sent to ".USER) ELSESTART 
   PRINTSTRING("Message stored for ".USER)
   FLAG=0
FINISH 
NEWLINE
ERR:

COMREG(24)=FLAG
IF  FLAG#0 THEN  PSYSMES(2,FLAG)
END ; !OF TELL
!
!
ROUTINE  JOIN2(RECORD (JTABF) ARRAYNAME  TAB, INTEGER  FIRSTCELL,LASTCELL,
    STRING (31) OUT, INTEGER  FE,GAP, INTEGERNAME  FLAG)
INTEGER  OUTCONAD,OUTP,I,OUTLEN,FEF,HFL
FLAG=0; !DEFAULT REPLY
IF  LASTCELL>=FIRSTCELL THENSTART ; ! (Do nothing if there are no files.)
 ! CALCULATE LENGTH OF OUT
   OUTLEN=32+GAP<<1; ! HEADER LENGTH
   FOR  I=FIRSTCELL,1,LASTCELL CYCLE 
      OUTLEN=OUTLEN+TAB(I)_LENGTH
   REPEAT 
   OUTFILE(OUT,OUTLEN,0,0,OUTCONAD,FLAG); !{SEQ} - CREATE THE OUTPUT FILE.
   HFL = FLAG
   IF  FLAG=0 THENSTART 
      INTEGER(OUTCONAD)=OUTLEN-GAP; ! Logical dataend
      INTEGER(OUTCONAD+12)=3; !DEFAULT - CHARACTER FILE
      INTEGER(OUTCONAD+4)=32+GAP;  ! Logical datastart
      OUTP=OUTCONAD+32+GAP
   FINISH 
   FOR  I=FIRSTCELL,1,LASTCELL CYCLE 
      IF  FLAG=0 THEN  START 
         IF  TAB(I)_TYPE=SSCHARFILETYPE THEN  FEF=0 ELSE  FEF=1
         IF  FEF=0=FE THEN  MOVE(TAB(I)_LENGTH,TAB(I)_START,OUTP) C 
                      ELSE  FCONV(FE!FEF,TAB(I)_START,OUTP,0,FLAG)
         OUTP=OUTP+TAB(I)_LENGTH; !UPDATE OUT POINTER
      FINISH 
      IF  NEWCONNECT#0 THEN  SETUSE (CONFILE(TAB(I)_START), -1, 0)
   REPEAT 
   IF  NEWCONNECT#0 AND  HFL=0 THEN  DISCONNECT (OUT,HFL)
FINISH 
END ; !OF JOIN
!
!
!
SYSTEMROUTINE  JOIN(RECORD (JTABF) ARRAYNAME  TAB, INTEGER  FIRSTCELL,
   LASTCELL, STRING (31) OUT, INTEGER  FE, INTEGERNAME  FLAG)
JOIN2(TAB,FIRSTCELL,LASTCELL,OUT,FE,32,FLAG)
RETURN 
END ; ! OF JOIN
!
!
!
SYSTEMROUTINE  JOINFILES(STRING (255) FILENAMES,
    RECORD (JTABF) ARRAYNAME  TAB, INTEGER  MODE,FIRSTCELL,
    INTEGERNAME  LASTCELL,FLAG)
!***********************************************************************
!*                                                                     *
!* This routine takes as input a string of the form A+B+C and builds   *
!* an array for routine JOIN. The parameter FIRSTCELL enables us to    *
!* leave room for additional information - for example heading for     *
!* line printer listings. It is called from COMPILE,DEFINE,LIST etc.   *
!*                                                                     *
!***********************************************************************
INTEGER  P,FE,NP,I
RECORD (RF) RR
STRING (31) FILE
FE=MODE&2; !FORMAT EFFECTOR
P=FIRSTCELL
NP = P
CYCLE 
   IF  P>LASTCELL THENSTART ; ! TOO MANY FILES
      FLAG=277
      ->ERR
   FINISH 
   UNLESS  FILENAMES->FILE.("+").FILENAMES THENSTART 
      FILE=FILENAMES
      FILENAMES=""
   FINISH 
   CONNECT(FILE,0,0,0,RR,FLAG); !{SEQ}
   IF  FLAG#0 THEN  ->ERR; !FAIL TO CONNECT
   NP = P + 1
   IF  RR_FILETYPE=SSCHARFILETYPE OR  MODE&1=1 START 
 !TRULY CHARACTER OR BINARY TO BINARY DEVICE
 !TEMP    ****MUST SORT THIS OUT BETTER
      IF  FE#0 THENSTART 
         TAB(P)_START=RR_CONAD
         TAB(P)_LENGTH=FLC(FE,RR_CONAD,0,FLAG) {file length}
         ->ERR IF  FLAG#0
      FINISHELSESTART 
         TAB(P)_START=RR_CONAD+RR_DATASTART
         TAB(P)_LENGTH=RR_DATAEND-RR_DATASTART
      FINISH 
      TAB(P)_TYPE=SSCHARFILETYPE
   FINISHELSESTART 
      IF  RR_FILETYPE#SSDATAFILETYPE THENSTART ; ! INVALID FILETYPE
         FLAG=267
         ->ERR
      FINISH 
      TAB(P)_START=RR_CONAD
      TAB(P)_LENGTH=FLC(FE!1,RR_CONAD,0,FLAG) {file length}
      ->ERR IF  FLAG#0
      TAB(P)_TYPE=SSDATAFILETYPE
   FINISH 
   P=NP
REPEATUNTIL  FILENAMES=""
LASTCELL=P-1
IF  NEWCONNECT#0 THEN  -> ERRX
ERR:
IF  NEWCONNECT#0 AND  NP>FIRSTCELL THEN  START 
   FOR  I=FIRSTCELL,1,NP-1 CYCLE 
      SETUSE (CONFILE(TAB(P)_START), -1, 0)
   REPEAT 
FINISH 
ERRX:
UNLESS  267#FLAG#311 THEN  SETFNAME(FILE); !IDENTIFY CORRUPT FILE
END ; !OF JOINFILES
!
!
SYSTEMROUTINE  COMPILE2(STRING (255) S, STRING (31) ENTRY, INTEGERNAME  FLAG, C 
INTEGER  LOADTYPE)
!{SEQ} - which files should be sequential-connected for compilation?
! LOADTYPE should be set to 0 for the compiler to be permanently loaded,
! Anything else for temporary loading. Only affects new loader.
STRING (255) SOURCE,HOLDSOURCE
RECORD (JTABF) ARRAY  TAB(1:16)
CONSTSTRING (6) SRCE="T#SRCE"
CONSTINTEGER  CNUM=5;! no of compilers not requiring history info
OWNSTRING (15)ARRAY  CNAMES(1:CNUM)="ICL9CEZIBMIMP","S#PERQIMP", C 
                                    "ICL9CEZPNXIMP","S#ACCIMP","ICL9CEZDRSIMP"
STRING (1) DUMMY
RECORD (FDF) NAME  F
INTEGER  ARRAY  FORMAT  LDATAAF (0:15)
INTEGER  ARRAY  NAME  LDATAA
INTEGER  LDA,P,OBJCONAD,L,TYPE
INTEGER  DR0,DR1; !DR0 AND DR1 STAY TOGETHER
LONGINTEGERNAME  DESC
RECORD (RF) RR
STRING (31) OBJECT,LISTING,ERRSTRM
INTEGER  AWORK,REMOVEOK,AFD,CURIN,CUROUT,TOP,LOCLL,PRINTDATE,HISTAD
INTEGER  FINDCOM,CHECKCOM; ! required by smh for history part
CONSTSTRING (32) TM0="SOURCE,OBJECT,LIST=T#LIST,ERROR="
STRING (43) TEMPLATE
DESC==LONGINTEGER(ADDR(DR0))
TEMPLATE=TM0.UINFS(8)
UCTRANSLATE(ADDR(S)+1,LENGTH(S))
FILPS(TEMPLATE,S)
REMOVEOK=1; !BY DEFAULT DON'T DO INSERT
CURIN=INSTREAM
CUROUT=OUTSTREAM
IF  PARMAP&3#3 OR  PARMAP>=16 THENSTART ; ! WRONG NO OF PARAMS
   FLAG=263
   ->ERR
FINISH 
COMREG(24)=16; !FAILURE BY DEFAULT
COMREG(47)=0; !NO OF STATEMENTS OR FAULTS
SOURCE=SPAR(1)
IF  SOURCE="*" OR  SOURCE=".IN" THEN  PRINTDATE = 0 ELSE   START 
   PRINTDATE = -1
   IF    (LENGTH(SOURCE)<8 OR  CHARNO(SOURCE,7)#'.') C 
   THEN  SOURCE=UINFS(1).".".SOURCE
FINISH 
HOLDSOURCE=SOURCE; !FOR LISTING AND OBJINFO
OBJECT=SPAR(2)
LISTING=SPAR(3)
ERRSTRM=SPAR(4); !COMPILER ERROR STREAM
IF  SOURCE->S.("+").S THEN  START ; !CONCATENATED  INPUT
   PRINTDATE = 0
   TOP=16; !MAXIMUM VALUE FOR TOP
   JOINFILES(SOURCE,TAB,0,1,TOP,FLAG)
   ->ERR IF  FLAG#0
   SOURCE=SRCE
   JOIN(TAB,1,TOP,SOURCE,0,FLAG)
   ->ERR IF  FLAG#0
FINISH 
SETINPUT(SOURCE,FLAG)
->ERR IF  FLAG#0
IF  COMREG(28)&x'00000100'#0 THEN  AWORK=SSMAXWORKSIZE ELSE  AWORK=x'40000'
 !MAX WORK SIZE IF PARM(MAXDICT) SELECTED
SETWORK(AWORK,FLAG)
IF  FLAG#0 THEN  ->ERR
COMREG(52)=ADDR(OBJECT)
IF  OBJECT#".NULL" START 
   OUTFILE(OBJECT,-4096,0,0,OBJCONAD,FLAG); !CHECK THAT WE CAN CONNECT IN WRITE MODE ETC
   IF  FLAG#0 THENSTART 
      IF  CHARNO(OBJECT,1)='.' THEN  FLAG=220; !INVALID FILENAME
      ->ERR
   FINISH 
   MODDIRFILE(6,SSOWN_AVD,"",OBJECT,0,0,0,REMOVEOK)
   IF  NEWCONNECT#0 THEN  SETUSE (OBJECT, -1, 0)
 !ATTEMPT TO REMOVE INFO FROM
 ! SS#DIR
FINISH 
!  %IF ERRSTRM="" %AND UINFS(8)#"" %THEN ERRSTRM = UINFS(8)
IF  ERRSTRM=".NULL" THEN  ERRSTRM=""
IF  ERRSTRM#"" START 
   DEFINE(87,ERRSTRM,AFD,FLAG)
   ->ERR IF  FLAG#0
   COMREG(27)=COMREG(27)!x'200000'; !TEMPORARY INDICATOR
 !SET BIT FOR COMPILER
   COMREG(40)=87
   SELECTOUTPUT(87)
   SELECTOUTPUT(0)
FINISHELSESTART ; !NO ERROR STREAM
   COMREG(27)=COMREG(27)&x'FFDFFFFF'
 !TEMP - CLEAR ERRSTRM  BIT
   COMREG(40)=-1; !INDICATES NO ERROR STREAM
FINISH 
!  %IF LISTING = "" %THEN LISTING = "T#LIST"
IF  NEWLOADER=0 THENSTART 
   LOAD(ENTRY,0,FLAG); !LOAD COMPILER
   ->ERR IF  FLAG#0
   FINDENTRY(ENTRY,0,0,DUMMY,DR0,DR1,FLAG)
FINISHELSESTART 
   TYPE=CODE
   IF  LOADTYPE#0 THEN  LOCLL=CURRENTLL ELSE  LOCLL=0
   DESC=LOADEP(ENTRY,TYPE,FLAG,LOCLL); ! Load compiler
   IF  FLAG#0 THEN  UNLOAD2(1,1); !unload all if compiler fails to load
FINISH 
->ERR IF  FLAG#0
!  %IF LISTING # "" %START
DEFINE(82,LISTING,AFD,FLAG)
->ERR IF  FLAG#0
F==RECORD(AFD)
F_MAXSIZE=CLISTSIZE; !MAXIMUM LISTING FILE SIZE
SELECTOUTPUT(82)
!  %FINISH
 !NOW PRINT HEADING FOR LISTING
PRINTSTRING("Source: ")
IF  PRINTDATE=0 OR  COMREG(46)=0 THEN  START 
   PRINTSTRING (HOLDSOURCE)
   SPACES (9)
FINISH  ELSE  START 
   PRINTDATE = INTEGER(COMREG(46)+20)
   HOLDSOURCE = HOLDSOURCE." last altered ". C 
      UNPACKDATE(PRINTDATE)." ".UNPACKTIME(PRINTDATE)
   PRINTSTRING (HOLDSOURCE)
   NEWLINE
FINISH 
PRINTSTRING("Compiled: ".DATE."   ".TIME)
NEWLINE
PRINTSTRING("Object: ".OBJECT)
NEWLINES(2)
PRINTSTRING("Parms set: ")
PRINTSTRING(PRINTPARMS(LONGINTEGER(ADDR(COMREG(27)))))
NEWLINE
ENTER(1,DR0,DR1,""); !ENTER COMPILER - NO PARAMETER
SELECTOUTPUT(0)
IF  COMREG(24)=0 START 
   IF  COMREG(47)#0 START 
      WRITE(COMREG(47),1)
      PRINTSTRING(" Statements compiled")
   FINISHELSE  PRINTSTRING("Compilation successful")
   NEWLINE
   IF  OBJECT#".NULL" START 
      IF  REMOVEOK=0 START 
         !Certain compilers do not need object file inserted into active directory
         FOR  FINDCOM=CNUM,-1,1 CYCLE 
            IF  CNAMES(FINDCOM)=ENTRY THEN  CHECKCOM=1 AND  EXIT 
            CHECKCOM=0
         REPEAT 
         !Checkcom of 0 means compiler is not one of the special cases
         IF  CHECKCOM=0 THEN  MODDIRFILE(3,SSOWN_AVD,"",OBJECT,0,0,0,REMOVEOK)
         !This flag not worth checking
      FINISH 
      CONNECT(OBJECT,3,0,0,RR,FLAG)
      IF  FLAG=0 START 
         LDA=RR_CONAD+INTEGER(RR_CONAD+24); !Start of loaddata
         LDATAA == ARRAY (LDA,LDATAAF)
         HISTAD = LDATAA (12); ! Offset of start of history records.
         IF  HISTAD#0 THEN  START 
            ! There is some history already, planted by LPUT.
            ! Scan the history records and find where they end.
            CYCLE 
               P = BYTE INTEGER (RR_CONAD+HISTAD)
            EXIT  IF  P=0
               HISTAD = HISTAD + 2 + BYTEINTEGER(RR_CONAD+HISTAD+1)
            REPEAT 
            IF    HISTAD+1#INTEGER(RR_CONAD) C 
            THEN  HISTAD = -1 C 
               {That checks whether the existing history records are the}
               {last things in the file.  If they are, then we can tag on some}
               {more history, but if they are not then we would have to put}
               {our history records somewhere separate from the existing ones,}
               {and since there is only one pointer to the history either one}
               {lot of history or the other would be unfindable.}
            ELSE  INTEGER(RR_CONAD) = HISTAD
               {Throw away the zero byte which}
               {is the last thing in the file and which marks the end}
               {of the history.}
         FINISH 
         ! HISTAD = 0  :  Plant history AND plant a pointer to it.
         ! HISTAD = -1 :  Plant no history.
         ! Other value :  Plant history at RR_CONAD+HISTAD but plant no pointer.
         IF  HISTAD#-1 THEN  START 
            L=INTEGER(RR_CONAD)
            IF  L&4095<13+LENGTH(HOLDSOURCE) THENSTART 
               IF  NEWCONNECT#0 THEN  START 
                  SETUSE (OBJECT, -1, 0)
                  CHANGEFILESIZE (OBJECT, L+45, FLAG)
               FINISH  ELSE  START 
                  CHANGEFILESIZE(OBJECT,L+45,FLAG); !NEED MORE ROOM FOR HISTORY
                  IF  FLAG=261 THENSTART ; !VM HOLE TOO SMALL
                     DISCONNECT(OBJECT,FLAG)
                     CHANGEFILESIZE(OBJECT,L+45,FLAG)
                  FINISH 
               FINISH 
               IF  FLAG=0 THEN  CONNECT(OBJECT,3,0,0,RR,FLAG)
   ! RECONNECT
               IF  FLAG#0 THEN  ->ERR
            FINISH 
            IF  HISTAD=0 THEN  LDATAA(12)=INTEGER(RR_CONAD); !SET POINTER TO END OF FILE
            P=RR_CONAD+INTEGER(RR_CONAD)
            BYTEINTEGER(P)=1; !TYPE=SOURCE
            STRING(P+1)=HOLDSOURCE
            P=P+LENGTH(HOLDSOURCE)+2
            BYTEINTEGER(P)=2; !TYPE = PARM
            BYTEINTEGER(P+1)=8; !LENGTH OF FIELD
            MOVE(8,ADDR(COMREG(27)),P+2); !PARMS NOW IN COMREG(27) AND COMREG(28)
            P=P+10
            BYTEINTEGER(P)=0; !END OF LIST
            INTEGER(RR_CONAD)=P-RR_CONAD+1; ! SET LENGTH
         FINISH 
         IF  NEWCONNECT#0 THEN  SETUSE (OBJECT, -1, 0)
      FINISH 
   FINISH 
FINISHELSESTART 
   IF  COMREG(47)#0 START 
      WRITE(COMREG(47),1)
      PRINTSTRING(" Fault")
      IF  COMREG(47)>1 THEN  PRINTSYMBOL('s')
 !FOR THE PURISTS !
      PRINTSTRING(" in compilation")
   FINISHELSE  PRINTSTRING("Compilation faulty")
   NEWLINE
   IF  OBJECT#".NULL" START ; !SET TYPE OF OBJECT FILE TO CORRUPT OBJECT FILE
      CONNECT(OBJECT,3,0,0,RR,FLAG)
      IF  FLAG=0 THEN  INTEGER(RR_CONAD+12)=SSCORRUPTOBJFILETYPE
      IF  NEWCONNECT#0 THEN  DISCONNECT (OBJECT,L)
   FINISH 
FINISH 
IF  NEWCONNECT=0 THEN  DISCONNECT(OBJECT,L); !IGNORE FLAG
ERR:
CLOSEST(81); !SOURCE FILE
CLOSEST(82); !LISTING FILE
CLOSEST(87); !FAULT LIST
IF  CURIN#INSTREAM THEN  SELECTINPUT(CURIN)
IF  CUROUT#OUTSTREAM THEN  SELECTOUTPUT(CUROUT)
IF  FLAG#0 THEN  COMREG(24)=FLAG; !PUT FLAG INTO RETURNCODE
END ; !OF COMPILE2
!
!
SYSTEMROUTINE  COMPILE(STRING (255) S, STRING (31) ENTRY, INTEGERNAME  FLAG)
! Permanently loads the compiler
COMPILE2(S,ENTRY,FLAG,0)
RETURN 
END ;  ! OF COMPILE
!
!
EXTERNALROUTINE  ASSEMBLE(STRING (255) S)
INTEGER  FLAG
COMPILE(S,"S#ASSEMBLE",FLAG)
IF  FLAG#0 THEN  PSYSMES(4,FLAG)
END ; !OF ASSEMBLE
!
!
EXTERNALROUTINE  NEWFORT77(STRING (255) S)
INTEGER  FLAG
COMPILE(S,"ICL9CEF77T",FLAG)
IF  FLAG#0 THEN  PSYSMES(102,FLAG)
END ; !OF NEW FORT77
!
!
EXTERNALROUTINE  FORT77(STRING (255) S)
INTEGER  FLAG
COMPILE(S,"ICL9CEF77",FLAG)
IF  FLAG#0 THEN  PSYSMES(102,FLAG)
END ; !OF FORT77
!
!
EXTERNALROUTINE  FORTE(STRING (255) S)
INTEGER  HOLDPARM; !TEMP
INTEGER  FLAG
HOLDPARM=COMREG(27); !TEMP
COMREG(27)=COMREG(27)&x'FFFFFBFF'; !TEMP AND OUT 'ZERO' BIT
COMPILE(S,"ICL9CEZFORTRAN",FLAG)
COMREG(27)=HOLDPARM; !TEMP - RESTORE PARM
IF  FLAG#0 THEN  PSYSMES(21,FLAG)
END ; !OF FORTE
!
!
EXTERNALROUTINE  IMP(STRING (255) S)
INTEGER  FLAG
COMPILE(S,"ICL9CEZIMP",FLAG)
IF  FLAG#0 THEN  PSYSMES(23,FLAG)
END ; !OF IMP
!
!
EXTERNALROUTINE  IMP80(STRING (255) S)
INTEGER  FLAG
COMPILE(S,"ICL9CEZIMP80",FLAG)
IF  FLAG#0 THEN  PSYSMES(103,FLAG)
END ; !OF IMP80
!
!
EXTERNALROUTINE  IBMIMP(STRING (255) S)
INTEGER  FLAG
COMPILE(S,"ICL9CEZIBMIMP",FLAG)
IF  FLAG#0 THEN  PSYSMES(104,FLAG)
END ; !OF IBMIMP
!
!
EXTERNALROUTINE  IOPT(STRING (255) S)
INTEGER  FLAG
COMPILE(S,"ICL9CEZIOPT",FLAG)
IF  FLAG#0 THEN  PSYSMES(110,FLAG)
END ; !OF IOPT
!
!
EXTERNALROUTINE  REPORTON(INTEGER  CHAN)
!This routine is used to re-route output on stream 0 to a nominated stream (chan)
!It is intended for re-routeing messages from e.g.COPY, and DIAGNOSTICS after
!program failure
STRING (31) FILE
INTEGER  FLAG
IF  CHAN=0 THEN  DFDFOUT("",0,FLAG); !return to normal
IF  1<=CHAN<=80 START 
 !This next statement is needed to obtain the filename or device required for output.
   DEFINFO(CHAN,FILE,FLAG); !ignore flag
   DFDFOUT(FILE,CHAN,FLAG); !tell the subsystem
FINISH 
END ; !of reporton
!
!
EXTERNALROUTINE  SUPPRESS RECALL
!switches of recall  until we are back at command: level
JOURNALOFF
END ; !of suppress recall
!
EXTERNALROUTINE  SVSN(STRING (255) S)
PRINTSTRING(SEPVSN)
RETURN 
END ;  ! OF SVSN
!
ENDOFFILE