! This version differs from the standard only in its treatment of a 'full
! tape' condition - it stops rather than reuse an old tape.
!FILE LAST CHANGED ON 11/02/83
!  *******************************************************************
!  *                                                                 *
!  *    THE JOURNAL SYSTEM:  PACKAGE A.                              *
!  *    THIS PACKAGE IS THE MANAGEMENT SECTION OF THE EMAS 2900      *
!  *    JOURNAL SYSTEM.                                              *
!  *                                                                 *
!  *    DESIGNED AND WRITTEN BY JOHN HENSHALL                        *
!  *                                                                 *
!  *    JOHN MURISON             VERSION: 015                        *
!  *                                                                 *
!  *                                                                 *
!  *******************************************************************

constinteger  kent = 0, ercc = 1
constinteger  journalsite = kent

!********** SYSTEM ROUTINE SPECS

  recordformat  rf(integer  conad, filetype, datastart, dataend)
  systemroutinespec  connect(string (31) file, integer  mode, hole,
          project, record (rf)name  r, integername  flag)
  systemroutinespec  destroy(string (31) s, integername  flag)
  systemroutinespec  disconnect( string (31) file, integername  flag)
  systemroutinespec  move(integer  l, f, t)
  systemroutinespec  outfile(string (31) s, integer  size, hole,
          protection, integername  conad, flag)
  systemroutinespec  oper(integer  operno, string (255) s)
  systemroutinespec  sdisconnect(string (31) file c 
          integer  fsys, integername  flag)

!**********EXTERNAL ROUTINE SPECS.

  externalroutinespec  cherish(string (255) s)
  externalroutinespec  copy(string (255) s)
  externalroutinespec  define(string (255) s)
  recordformat  f rep b(integer  dest, srce, byteinteger  flag,
      string (6) file, string (15) output q)
  externalroutinespec  dpoff(record (f rep b)name  p)
  recordformat  f parm(integer  dest, srce, p1, p2, p3, p4, p5, p6)
  externalintegerfnspec  exist(string (31) file)
  externalintegerfnspec  dspool(record (f parm)name  p, integer  len, adr)
  externalroutinespec  newpdfile(string (255) s)
  externalroutinespec  journal analysis(string (255) s)
  externalroutinespec  prompt(string (255) s)
  externalroutinespec  rename(string (255) s)
  externalroutinespec  readmag(integer  chnl, addr, integername  len, flag)
  externalroutinespec  write tmmag(integer  chnl, integername  flag)
  externalroutinespec  unload mag(integer  chnl)
  externalroutinespec  open mag(integer  chnl, string (7) tsn)
  externalroutinespec  write mag(integer  chnl, addr, len, integername  c 
          flag)
  externalroutinespec  skip mag(integer  chnl, blocks)
  externalroutinespec  skip tm mag(integer  chnl, marks)
  externalroutinespec  f skip tm mag(integer  chnl, marks,
          integername  flag)
  externalstringfnspec  date
  externalroutinespec  send(string (255) s)
  externalstringfnspec  time

!**********ROUTINE AND FUNCTION SPECS.

  routinespec  identify index(string (*)name  keyword, byteintegername  c 
          id char, data type, integername  entry)
  routinespec  line to atoms(integername  word count,
          stringarrayname  atom, byteintegerarrayname  buff)
  routinespec  master file failure(string (*)name  file, integer  flag)
  routinespec  journal(string (255) s)
  routinespec  new journal index(string (255) s)
  routinespec  new journal tape(string (255) s)
  externalroutinespec  journal backpass(string (255) s)
  externalroutinespec  create jfile(string (11) name, integer  cells, cellsize,
      headersize, integername  conad, flag)
  externalroutinespec  read prompt reply(string (*)name  reply)
  externalintegerfnspec  s to i(string (*)name  s)
  externalintegerfnspec  cyclic(integer  from, direction)
  externalstringfnspec  intostr(integer  value)
  systemintegerfnspec  pack date and time(string (8) date, time)
  systemintegerfnspec  dt word(integer  old form)
  externalintegerfnspec  minutes between(integer  from,to)
  systemstringfnspec  unpack date(integer  packed)
  systemstringfnspec  unpack time(integer  packed)
  systemintegerfnspec  current packed dt
  externalintegerfnspec  uinfi(integer  entry)

!**********RECORD FORMATS

  recordformat  f chapter header(string (6) tape name, user name,
          string (15) file name, string (8) date, time, type,
          byteinteger  spare0, spare1, spare2, integer  chapter, epages,
          fsys, perms)
  recordformat  f index entry(integer  file id, starting, finishing,
          chapter, string (6) tape, byteinteger  status) {24 bytes}
  recordformat  f index list(byteinteger  id char,
          data type, string (12) identity) {15 bytes}
  recordformat  f parameters(string (4) lower file, upper file,
          string (12) keyword, analysis)
  recordformat  f queue(string (15) name,
          halfintegerarray  streams(0:15),
          string (7) default user,
          string (31) default delivery,
          integer  default start, default priority, default time,
          default outlim, default forms, default mode, default copies,
          default rerun, length, head, max length, maxacr, q by, spare,
          amount)
  recordformat  f tape cycle(string (6) tsn, integer  age)

!**********CONSTANT ARRAYS.

  conststring (3) array  ocptimereq(0:16)= c 
    "600", "600", "600", "420", "300", "300", "300", "600", "600", "600", "600",
    "600", "600", "600", "600", "600", "600"
  conststring (60) array  journal status(0:4)= c 
    "Failure occurred at undefined point!!",
    "Failure occurred during file collection from Spooler",
    "Last run opted out of tape dump",
    "Failure occurred whilst dumping files to tape",
    "Next run is clear to rerun tape dump"
  conststring (9) array  system keyword(0:9)= c 
    "MAINLOG", "VOLUMS", "SPOOLR", "ACCOUNTS", "DIRECT", "BACK&ARCH",
    "UPDATES", "MAILER", "SPARE3", "SPARE4"
  !THE SYSTEM INDICES RECOGNITION KEYWORDS.

!**********CONSTANTS.

  constinteger  block = 4096
  !BYTES IN EPAGE.
  constinteger  index top = 9999
  !THE PHYSICAL TOP OF AN INDEX.
  constinteger  system indices = 9
  constinteger  used system indices = 7
  constinteger  nsys = 99
  !THE MAXIMUM NUMBER OF FILE SYSTEMS ON EMAS.
  !THE TOTAL NUMBER OF SYSTEM INDICES.
  constinteger  total indices = 99
  !MAXIMUM NUMBER OF INDICES ON THE SYSTEM.
  conststring (9) jtxt="Journal: "
  ownstring (8) control="JJMASTER"
  !THE IDENTITY OF THE SYSTEM CONTROL FILE.
  conststring (8) pdstore="JJ#PD"
  !THE JOURNAL SYSTEM STORAGE FILE.
  conststring (6) spool="SPOOLR"
  conststring (6) me = "JOURNL"
  conststring (8) prime start time="09.30.00"
  conststring (8) prime end time="17.00.00"
  !THESE PRIME TIMES DECIDE WHEN RESTRICTED TRIGGERING(TEST C)
  !OF THE JOURNAL HOUSEKEEPING IS IN FORCE.
  constinteger  yes = 1
  constinteger  no = 0
  conststring (1) snl="
"
  externalinteger  chpointer
  externalinteger  flen
  externalinteger  endflag
  !THESE LAST THREE INTEGERS ARE CONNECTED WITH THE 'ATOM'
  !READING FUNCTIONS.

!**********EXTERNAL ROUTINE LIST

!  THE FOLLOWING EXTERNAL ROUTINES EXIST IN THIS MODULE AND ARE IN
!  ALPHABETIC ORDER OF APPEARANCE:

!    ABORT JOURNAL FILES: THIS IS USED WHEN THERE HAS BEEN AN ABNORMAL NUMBER
!    OF FILES QUEUED FOR JOURNL IN SPOOLR SUCH THAT JOURNAL'S INDEX FILLS
!    WHEN IT TRIES TO TAKE THEM OFF SPOOLR. USING THIS COMMAND WE DESTROY
!    ALL THE FILES TAKEN FROM SPOOLR WAITING TO BE INDEXED IN THE JOURNAL
!    SYSTEM AND HENCE CLEARING THE JOURNL PROCESS DOWN.
!    THIS WILL MEAN THAT THE FILES WILL BE LOST FOR GOOD BUT THE FILES WILL
!    PROBABLY BE RUBBISH PRODUCED FROM MONITORING IN THE FIRST PLACE
!    AND HENCE DISCARDABLE.


!    ABORT JOURNAL TAPE: USED WHEN A TAPE HAS BEEN COMPLETELY SCREWED
!    AND WE  WANT TO USE ANOTHER AND CLEAR DOWN THE INDEX ENTRIES FOR
!    THE FILES ON THIS TAPE(SINCE THEY ARE EFFECTIVELY LOST). THIS CAN
!    BE USED FOR EITHER THE CURRENT MASTER TAPE OR FOR ANY OTHER TAPE
!    THAT MAY BE LOST? ETC.


!    CREATE JOURNAL SYSTEM: THIS ROUTINE INITIALISES THE JOURNAL SYSTEM
!    AND CAN ONLY BE RUN WHEN THE SYSTEM CONTROL FILE DOES NOT EXIST.
!    THE FILE 'JJMASTER'  IS CREATED BY THIS ROUTINE
!    TOGETHER WITH ALL THE "SYSTEM FILE" INDICES DEFINED IN THE ABOVE
!    CONSTARRAY 'SYSTEM KEYWORD'.

!    JOURNAL: THIS IS THE MAIN CONTROL  ROUTINE OF THE JOURNAL SYSTEM.
!    IT IS RUN AT LEAST ONCE EVERY 24 HOURS AND IS RESPONSIBLE FOR THE
!    COLLECTING, PARTITIONING, DUMPING TO TAPE OF ALL JOURNAL AND DONOR
!    FILES. IT ALSO PRODUCES THE AUTOMATIC ANALYSES SUCH AS THE ERROR
!    LOG COMPONENTS.
!    IF IT IS OBVIOUS THAT A FILE IS CAUSING REPEATED CRASHES
!    THEN THE SYSTEM MANAGER CAN USE THE PARAMETER "KILLFILE" WHICH
!    WILL RESULT IN THE FILE LOGGED AS BEING THE LAST FAILING FILE
!    IN THE MASTER CONTROL FILE WILL BE REMOVED FROM SPOOLER QUEUE.
!    THE SYSTEM CAN BE RUN WITHOUT THE TAPE DUMP BY GIVING THE
!    PARAMETER "TAPESKIP" AND WITHOUT AUTO ANALYSIS USING "ANALSKIP"

!    JOURNAL STATE:THIS ROUTINE WILL GIVE A SUMMARY OF THE CURRENT STATE
!    OF THE JOURNAL SYSTEM INCLUDING DETAILS OF ALL INDICES IN USE,
!    DETAILS OF THE TAPE CYCLE AND THE CURRENT MASTER TAPE ETC.

!    LIST JOURNAL INDEX: THIS ROUTINE WILL DUMP A FULL LIST OF THE
!    CONTENTS OF AN INDEX INTO THE FILE "JLIST". JLIST CAN
!    THEN BE LISTED OR VIEWED BY THE USER.

!    NEW JOURNAL INDEX: THIS ROUTINE WILL CREATE A NEW INDEX (UNLESS
!    IT ALREADY EXISTS) FOR THE KEYWORD SPECIFIED BY THE REPLY
!    TO THE GIVEN PROMPT. EACH INDEX IS 90 PAGES LONG AND CAN HOLD A
!    MAXIMUM OF 10, 000 ENTRIES.  AN ENTRY(BY ROUTINE "CREATE JOURNAL
!    SYSTEM" ONLY) WITH PARAMETER "SYSTEM" WILL CREATE ALL THE "SYSTEM"
!    INDICES AND IF IT FAILS AT ALL WILL DESTROY ALL THE SYSTEM FILES
!    ALREADY CREATED, INCLUDING JJMASTER, FOR A CLEAN RETRY.
!    THE FIRST 10 INDICES ARE RESERVED FOR SYSTEM INDICES, THE
!    REMAINDER BEING AVAILABLE TO THE INSTALLATION.

!    NEW JOURNAL TAPE: THIS IS USED WHEN A NEW TAPE IS TO BE ADDED TO
!    THE JOURNAL TAPE CYCLE. THE TAPE WILL BE REJECTED IF IT IS ALREADY
!    IN THE CYCLE OTHERWISE AN ACCEPTANCE MESSAGE WILL BE GIVEN
!    TOGETHER WITH A COUNT OF THE TAPES IN THE CYCLE.

!    REMOVE JOURNAL INDEX: THIS ROUTINE IS USED TO DESTROY AN INDEX AND
!    IN DOING SO REMOVING ALL ACCESS TO THE FILES STORED UNDER THAT
!    INDEX.



! ************************************************************************
! ************************************************************************
! ************************************************************************
  externalroutine  abort journal files(string (255) s)
  integer  flag
  destroy(pdstore, flag)
  if  flag#0 start 
    printstring(jtxt."Cannot destroy partition ".pdstore.", flag: ")
    write(flag, 3); newline
  finish  else  start 
    printstring(jtxt."All pending files destroyed")
    newline
  finish 
  newpdfile(pdstore)
  cherish(pdstore)
  end ;  !OF ABORT JOURNAL FILES
! ***************************************************************
! ***************************************************************
! ***************************************************************
  externalroutine  abort journal tape(string (255) s)
  record (f tape cycle)arrayformat  af tape cycle(1:100)
  record (f index list)arrayformat  af index list(0:total indices)
  record (f index entry)arrayformat  af index entry(0:index top)
  record  (rf)r
  integername  master entry, total chapters, total epages, tape count
  record (f tape cycle)arrayname  tape cycle
  record (f index list)arrayname  index list
  record (f index entry)arrayname  index entry
  integer  i, j, k, files lost, flag, new master, max
  string (15) ss, index
  string (6) tsn
  byteinteger  id
  connect(control, 3, 0, 0, r, flag)
  if  flag#0 then  master file failure(control, flag)
  master entry==integer(r_conad+x'708')
  total epages==integer(r_conad+x'714')
  total chapters==integer(r_conad+x'710')
  tape cycle==array(r_conad+x'720', af tape cycle)
  tape count==integer(r_conad+x'700')
  index list==array(r_conad+x'30', af index list)
  cycle 
    prompt("JOURNAL TAPE:")
    read prompt reply(ss)
    exit  if  length(ss)=6
    printstring("??"); newline
  repeat 
  for  k=1, 1, tape count cycle 
    exit  if  tape cycle(k)_tsn=ss
    if  k=tape count start 
      printstring(ss." not a Journal cycle tape!")
      newline
      return 
    finish 
  repeat 
  files lost=0;  !COUNT OF FILES ON THE BAD TAPE.
  for  i=0, 1, total indices cycle 
    if  index list(i)_identity#"" start 
     id=index list(i)_id char
      index="JJ#".intostr(id)."DEX"
      connect(index, 3, 0, 0, r, flag)
      if  flag#0 then  master file failure(index, flag)
      index entry==array(r_conad+x'40', af index entry)
      for  j=0, 1, index top cycle 
        if  index entry(j)_tape=ss start 
         if  1<=index entry(j)_status<9 then  index entry(j)_status=9 c 
          and  files lost=files lost+1
        finish 
      repeat 
      disconnect(index, flag)
    finish 
  repeat 
  printstring("There were ".intostr(files lost)." files on the tape.")
  newline
  unless  k=master entry start 
    printstring("Bad tape marked unused, please replace with")
    printstring(" a new tape with the same label.")
    newline
    tape cycle(k)_age=0
    disconnect(control, flag)
    printstring("Abort succeeds."); newline
    return 
  finish 
  !OTHERWISE WE KNOW THE TAPE WAS THE MASTER TAPE.
  new master=-1
  for  i=1, 1, tape count cycle 
    if  tape cycle(i)_age=0 then  new master=i and  exit 
  repeat 
  if  new master=-1 start 
    !WE MUST USE A FULL TAPE(THE OLDEST.)
    max=10000
    for  i=1, 1, tape count cycle 
      if  tape cycle(i)_age<max and  tape cycle(i)_age#-1 start 
        max=tape cycle(i)_age
        new master=i
      finish 
    repeat 
    tsn=tape cycle(new master)_tsn
    printstring("Reusing ".tsn." as replacement master tape")
    newline
    for  i=0, 1, total indices cycle 
      if  index list(i)_identity#"" start 
        id=index list(i)_id char
        index="JJ#".intostr(id)."DEX"
        connect(index, 3, 0, 0, r, flag)
        if  flag#0 then  master file failure(index, flag)
        index entry==array(r_conad+x'40', af index entry)
        for  j=0, 1, index top cycle 
          if  index entry(j)_tape=tsn start 
            if  index entry(j)_status>1 start 
              index entry(j)_status=9
              integer(r_conad+x'2C')=j
            finish 
          finish 
        repeat 
        disconnect(index, flag)
      finish 
    repeat 
  finish  else  start 
    printstring("New master tape ".tape cycle(new master)_tsn)
    newline
  finish 
  printstring("Bad tape marked unused, please replace with a new tape")
  newline
  printstring("with the same label."); newline
  tape cycle(k)_age=0
  tape cycle(new master)_age=-1
  master entry=newmaster
  total chapters=0
  total epages=0
  disconnect(control, flag)
  printstring("Abort succeeds."); newline
  return 
end ;  !OF ABORT JOURNAL TAPE


! *******************************************************************
! *******************************************************************
! *******************************************************************
  externalroutine  abort main analysis(string (255) s)
  record  (rf)r; integer  flag
  connect("JJ#0DEX", 3, 0, 0, r, flag)
  if  flag#0 start 
    printstring(jtxt."Problems..cannot connect Mainlog index, ")
    printstring("flag:".intostr(flag))
    newline
    return 
  finish 
  integer(r_conad+x'28')=integer(r_conad+x'20')
  printstring(jtxt."Current analysis aborted.")
  newline
  end 


! *******************************************************************
! *******************************************************************
! *******************************************************************
  externalroutine  abort volums analysis(string (255) s)
  record  (rf)r; integer  flag
  connect("JJ#1DEX", 3, 0, 0, r, flag)
  if  flag#0 start 
    printstring(jtxt."Problems..cannot connect Volums log index, ")
    printstring("flag:".intostr(flag))
    newline
    return 
  finish 
  integer(r_conad+x'28')=integer(r_conad+x'20')
  printstring(jtxt."Current analysis aborted.")
  newline
  end 


! *******************************************************************
! *******************************************************************
! *******************************************************************
  externalroutine  abort spoolr analysis(string (255) s)
  record  (rf)r; integer  flag
  connect("JJ#2DEX", 3, 0, 0, r, flag)
  if  flag#0 start 
    printstring(jtxt."Problems..cannot connect Spoolr log index, ")
    printstring("flag:".intostr(flag))
    newline
    return 
  finish 
  integer(r_conad+x'28')=integer(r_conad+x'20')
  printstring(jtxt."Current analysis aborted.")
  newline
  end 


! *******************************************************************
! *******************************************************************
! *******************************************************************
  externalroutine  abort direct analysis(string (255) s)
  record  (rf)r; integer  flag
  connect("JJ#4DEX", 3, 0, 0, r, flag)
  if  flag#0 start 
    printstring(jtxt."Problems..cannot connect Direct log index, ")
    printstring("flag:".intostr(flag))
    newline
    return 
  finish 
  integer(r_conad+x'28')=integer(r_conad+x'20')
  printstring(jtxt."Current analysis aborted.")
  newline
  end 


! ************************************************************************
! ************************************************************************
! ************************************************************************
  externalroutine  create journal system(string (255) s)
  record (f index list)arrayformat  af index list(0:total indices)
  record (f tape cycle)arrayformat  af tape cycle(1:100)
  record (f index list)arrayname  index list
  record (f tape cycle)arrayname  tape cycle
  string (7) arrayformat  af pending files(1:250)
  stringarrayname  pending files
  record  (rf)r
  integer  i, flag, conad
  connect(control, 0, 0, 0, r, flag)
  if  flag=0 start 
    printstring(jtxt.control." already exists??")
    newlines(2)
    return 
  finish 
  !WE NOW KNOW THAT JJMASTER DOES NOT EXIST AND THAT THE SYSTEM HAS
  !NOT ALREADY BEEN SET UP. PROCEED WITH SET UP.
  outfile(control, 3*4096, 0, 0, conad, flag)
  if  flag#0 start 
    printstring(jtxt."Failed to create JJMASTER, flag ")
    write(flag, 2)
    newlines(2)
    return 
  finish 
  !NOW SET THE INITIAL VALUES TO JJMASTER.
  integer(conad) = integer(conad+8); ! Set data length = physical length
  integer(conad+x'20') = current packed dt
  integer(conad+x'24')=0;  !THE JOURNAL STATE SETTING.
  integer(conad+x'28')=0;  !THE ICL ERROR ENTRY CYCLIC COUNT(LAST TWO BYTES)
  integer(conad+x'6D8')=0;  !THE FAILURE DESCRIPTOR.
  integer(conad+x'6DC')=0;  !AUTO CONTROL FLAG
  index list==array(conad+x'30', af index list)
  !NOW INITIALISE THE INDEX DESCRIPTORS.
  for  i=0, 1, total indices cycle 
    index list(i)_id char=i
    index list(i)_data type=0
    !IE 0: TEXT(TEXT DATA).  1: MAPPED DATA.
    index list(i)_identity=""
  repeat 
  !NOW CREATE THE TAPE CYCLE CONTROL.
  string(conad+x'6F2')="";  !IDENTIFIES LAST FAILING FILE.
  integer(conad+x'700')=0;  !TAPES IN CYCLE
  integer(conad+x'704')=1;  !AGE OF NEXT TAPE
  integer(conad+x'708')=-1;  !INITIAL MASTER TAPE ENTRY
  integer(conad+x'70C')=7000; !Max epages per dump tape.
  integer(conad+x'710')=0;  !TOTAL CHAPTERS ON MASTER TAPE.
  integer(conad+x'714')=0;  !TOTAL EPAGES ON MASTER TAPE.
  tape cycle==array(conad+x'720', af tape cycle)
  for  i=1, 1, 100 cycle 
    tape cycle(i)_tsn=""
    tape cycle(i)_age=-2
  repeat 
  integer(conad+x'1FFC')=0;  !COUNT OF THE FILES IN THE PENDING FILES ARRAY.
  pending files==array(conad+x'2000', af pending files)
  !THIS ARRAY POINTS TO THE FILES IN JOURNL TAKEN FROM SPOOLER TO BE PROCESSED.
  string(conad+x'6EA')="";  !THIS IS THE BAD FILE POINTER.
  string(conad+x'27D0') = ""; ! Null background password.
  journal backpass("")
  byteinteger(conad+x'27DC') = 0; ! Count for next autojob logfile.
  disconnect(control, flag)
  printstring(jtxt."JJMASTER initialised.")
  newlines(2)
  cherish(control)
  !NOW SET UP THE SYSTEM INDICES.
  new journal index("SYSTEM")
  printstring("The Journal system requires at least two tapes")
  newline
  printstring("for operation.  Add these two tapes through the ")
  newline
  printstring("following prompts. Any further tapes can be added using")
  newline
  printstring("the command 'NEW JOURNAL TAPE'.")
  newline
  new journal tape(s)
  new journal tape(s)
  printstring("The Journal system is now initialised."); newline
  printstring("The first run of the housekeeping command: JOURNAL")
  printstring(" will initiate (on its"); newline
  printstring("successful completion) the automatic housekeeping.")
  newline
  return 
  end ;  !OF CREATE JOURNAL SYSTEM.

! ********************************************************************
! ********************************************************************
! ********************************************************************
! ROUTINES THAT GIVE DIRECT CALLED ACCESS TO THE HOUSEKEEPING.

  externalroutine  journal override(string (255) s)
    journal("OVERRIDE")
  end 

  externalroutine  journal recovery(string (255) s)
  journal("")
  end 

  externalroutine  update journal(string (255) s)
  journal("TAPESKIP,ANALSKIP,EXTERNAL")
  end 

! ************************************************************************
! ************************************************************************
! ************************************************************************
  externalroutine  journal(string (255) s)
  owninteger  run tape
  ! Stops tape dump run if no files
  owninteger  tapeskip
  owninteger  analskip
  owninteger  auto call
  owninteger  decks
  owninteger  killfile
  owninteger  closetape
  owninteger  external;  !USED WHEN 'JOURNAL' CALLED BY 'FULL JOURNAL ANALYSIS'.
  owninteger  call state;  !ALSO USED IN ABOVE CASE.
  owninteger  write unit=1
  !THE TAPE CONTROL UNIT IDENTITIES.
  owninteger  abandon tape retries = 2
  !IE LEVEL OF RETRY THAT WILL RESULT IN AUTO JOURNAL JOBS BEING
  !STOPPED IF UNSUCCESSFUL.
  owninteger  on = 1
  owninteger  off = 0
  owninteger  tape retry level= -1
  !THE RETRY COUNTER.
  owninteger  override
  !THE OVERRIDE FLAG.
  recordformat  f finf(integer  nkb, rup, eep, apf, use,
          arch, fsys, conseg, cct, codes, codes2, ssbyte, string (6) offer)
  record  (f finf)finf
  recordformat  f req(integer  dest, srce, flag,
      string (6) user, file, integer   p6)
  recordformat  f rep a(integer  dest, srce, flag,
          string (6) file, string (11) output q)
  recordformat  f rep b(integer  dest, srce, byteinteger  flag,
      string (6) file, string (15) output q)
  recordformat  f file list(integer  files, integerarray  dts(1:100),
          string (7) array  names(1:100))
  record (f file list)array  file list(0:total indices)
  record (f file list)name  fli
  record (f index entry)arrayformat  af index entry(0:index top)
  record (f index list)arrayformat  af index list(0:total indices)
  record (f tape cycle)arrayformat  af tape cycle(1:100)
  record (f index entry)arrayname  index entry
  record (f index list)arrayname  index list
  record (f tape cycle)arrayname  tape cycle
  record (f chapter header)name  chapter header
  record (f parameters)name  parameters
  record (f req)req
  record (f rep a)name  repa
  record (frep b)name  repb
  record (f repb)poff rep
  record (rf)r
  record (f parm)p
  record (f queue)name  queue
  string (7) arrayformat  af pending files(1:250)
  stringarrayname  pending files
  string (11) backpass
  byteintegername  nextjjlog
  externalintegerfnspec  dpon2(string (6)  user, record (f req)name  p,
          integer  msgtype, outno)
  externalintegerfnspec  dfinfo(string (6) user, string (11) file,
          integer  fsys, addr)
  recordformat  f parm(integer  dest, srce, p1, p2, p3, p4, p5, p6)
  externalintegerfnspec  dpon3(string (6) user, record (f parm)name  p,
          integer  invoc, msgtype, outno)
  routinespec  remove failing file
  routinespec  bulk change index status(string (12) keyword,
          byteinteger  old status, new status)
  routinespec  collect journal files
  routinespec  connect control file
  routinespec  connect index(string (15) index, integer  mode,
          integername  addr)
  routinespec  date and time(integer  index slot)
  routinespec  dump to tape
  routinespec  check file(string (*)name  file, byteintegername  c 
          data type, integername  flag)
  routinespec  file list from spooler
  integerfnspec  autojob(string (15) name, string (*)name  ident)
  routinespec  respool journal(string (15) name)
  routinespec  remove queued file(string (6) file)
  routinespec  requeue file(string (6) file)
  routinespec  start up
  byteintegerarrayformat  af buff(1:10000000)
  byteintegerarrayname  buff
  switch  journal state(0:5)
  integername  relative age, master entry, p file count
  integername  system state, run date, total chapters, tape count
  integername  autoflag, fail type, total epages, max epages
  string (*)name  fail file, bad file
  string (140) array  atoms(1:68)
  string (16) index, new file name, start date, start time, identj
  string (16) finish date, finish time, poff file; poff file=""
  string (64) s1, ss
  integer  i, flag, index addr, free slot, sequence number, entry
  integer  queues, prime start, prime end
  prime start=packdateandtime(date, prime start time)
  prime end=packdateandtime(date, prime end time)
  string (255) pstring
  byteinteger  id char, datatype

!THE MAIN CONTROL CODE BEGINS HERE.

  connect control file
  !CONNECT THE CONTROL FILE.
  respool journal("MONITOR") if  autojob("MONITOR", identj)=no
  disconnect("JJINF", flag); destroy("JJINF", flag)
  destroy("JLIST", flag)
  destroy("JJANL", flag)
  destroy("JWORKFILE", flag)
  !THIS IS A GENERAL WORK FILE THAT EXISTS ONLY FOR RUNS OF CERTAIN ANALYSES.
  !DESTROY IT IF IT IS FOUND HANGING AROUND!!
  if  s#"" start 
    !THE CALL HAD A PARAMETER LIST.
    !POSSIBLE PARAMETER COMBINATIONS:-
    !
    !'OVERRIDE, EXTERNAL':
    !CALL FROM ENGINEERS(PACKAGE C) TO UPDATE
    !JEF. REQUIRES A FULL COLLECTION, NO TAPE DUMP AND AN AUTO MAINLOG
    !ANALYSIS. IT IS LEFT IN THE 'TAPE DUMP SKIPPED' STATE
    !WHICH WILL TRIGGER THE NEXT AUTO HOUSEKEEPING TO TIDY UP.
    !
    !'TAPESKIP, ANALSKIP, EXTERNAL':
    !A CALL FROM THE COMMAND 'UPDATE JOURNAL' TO UPDATE THE
    !JOURNAL SYSTEM WITH THE FILES QUEUED BY SPOOLR.. LEFT IN STATE
    !AS ABOVE.
    !
    !'AUTOCALL':
    !THIS IS THE ENTRY MADE BY THE AUTOMATIC HOUSEKEEPING HOURLY BATCH JOB.
    !IF IT DECIDES THAT A FULL RUN IS REQUIRED IT WILL DETACH
    !A SECOND BATCH JOB TO RUN AS SOON AS POSSIBLE WITH ENTRY AS BELOW.
    !
    !'AUTOCALL+DECK':
    !THIS ENTRY IS MADE BY THE ABOVE ENTRY BEING CALLED EARLIER AND
    !DECIDING THAT A FULL RUN IS REQUIRED. THIS JOB ENTRY WILL
    !REQUEST AN MTU FOR THE RUN.
    !
    !'OVERRIDE':
    !THIS IS THE CALL TO OVERRIDE THE LOCK IMPOSED ON RUNNING THE
    !HOUSEKEEPING WHEN THE AUTOMATIC HOUSEKEEPING IS IN AN UNFAILED STATE
    !OR THE OPERATORS MAY RUN THIS TO INSTITUE A RECOVERY FROM ANY
    !SUSPECTED ERRORS.
    !
    printstring("Parameter list: ".s)
    newlines(2)
    flag=0
    for  i=1, 1, 4 cycle 
      if  s->s1.(",").s start 
        if  s1="TAPESKIP" then  tapeskip=1
        if  s1="ANALSKIP" then  analskip=1
        if  s1="KILLFILE" then  killfile=1
      if  s1="EXTERNAL" then  external=1
        if  tapeskip+analskip+killfile+external#i then  flag=1 and exit 
      finish  else  exit 
    repeat 
    if  s="TAPESKIP" then  tapeskip=1
    if  s="ANALSKIP" then  analskip=1
    if  s="KILLFILE" then  killfile=1
    if  s="EXTERNAL" then  external=1
    if  s="AUTOCALL" then  autocall=1
    if  s="AUTOCALL+DECK" then  decks = on and  autocall=on
    if  s="OVERRIDE" then  override=1
    if  s="CLOSETAPE" then  closetape=1
    if  tapeskip+analskip+killfile+external+autocall+override+closetape#i c 
     then  flag=1
    if  (autocall=on) and  i#1 then  flag=1
    if  override=on start 
      if  external#on start 
        if  i#1 then  flag=1
      finish 
    finish 
    if  flag=1 start 
      printstring(jtxt."Parameter list faulty!".snl)
      return 
    finish 
    if  killfile=1 then  remove failing file
    if  closetape=1 then  max epages = 0
    ! Reset (to 7000) by next call of START NEWTAPE.
  finish 
  connect(spool.".CFILE", 9, 0, 0, r, flag)
  if  flag#0 start 
    !WE CANNOT CONNECT THE SPOOLR INFO FILE.
    printstring("Spoolr descriptor file (CFILE) connect fails:")
    write(flag, 3) and  newline
    printstring("Log off and try again.".snl)
    stop 
  finish 
  queues=integer(r_conad+x'18')
  if  queues=0 start 
    printstring("No queues defined in SPOOLR descriptor file".snl)
    stop 
  finish 
  for  i=1, 1, queues cycle 
    queue==record(r_conad+x'20'+148*(i-1))
    if  queue_name="JOURNAL" then  exit 
    if  i=queues start 
      printstring("Journal queue not in SPOOLR descriptor file".snl)
      stop 
    finish 
  repeat 
  if  autoflag=on and  autocall=off and  override=off start 
    !IE A MANUAL RUN OF JOURNAL IS NOT ALLOWED WHEN THE AUTO
    !JOURNAL SYSTEM IS IN AN UNFAILED STATE.
    unless  external=on start 
      printstring(jtxt."Manual run not permitted whilst auto".snl)
      printstring("          Journal is in unfailed state.".snl)
      stop 
      finish 
      !ALTHOUGH ALLOW CALL FROM UPDATE JOURNAL.
  finish 
  if  override=on and  external=off start 
    !We have a manual run interrupting the auto run sequence.
    autoflag=off
    fail type=0
  finish 
  if  override=on and  external=on start 
    !IE A CALL FROM THE ENGINEERS COMMAND 'UPDATE JEF'.
    if  autoflag=off or  (system state#0 and  system state#2) c 
      start 
      printstring("Journal system in failed state, please log")
      printstring(" off and inform ops."); newline
      return 
    finish 
    autoflag=off; tapeskip=on
    printstring("Updating JEF")
    newline
  finish 
  start up;  !FIND OUT HOW TO START UP THIS RUN OF JOURNAL HOUSEKEEPING
  !NOW CLOSE THE CURRENT MAINLOG.
  p=0
  p_dest=x'FFFF0000'!27
  i=dpon3("DIRECT", p, 0, 1, 7)
  -> journal state(system state)

journal state(0):
  !IF THE SET TESTS ARE POSITIVE (IE THE PD IS FILLING UP) THEN
  !DESTROY THE PARTITION AMENDING THE STATUS SETTINGS IN THE
  !INDICES FROM "ON PD AND TAPE" TO "ON TAPE ONLY". THEN CREATE
  !A NEW 24 HOUR PARTITION.
  i=dfinfo(me, "JJ#PD", -1, addr(finf))
  if  i#0 start 
    printstring("Journal DFINFO fails, max assumed".snl)
    finf_nkb=3001
  finish 
  if  (finf_nkb>1000 and  (finf_nkb*1024+queue_amount)>1024*3500) c 
    or  (finf_nkb*1024+queue_amount)>1024*4000 start 
    bulk change index status("ALL", 1, 2)
    !ALL STATUS AMENDMENTS MADE.
    destroy(pdstore, flag)
    newpdfile(pdstore)
    cherish(pdstore)
  finish 

journal state(2):
journal state(3):
  !RESTART WITH EXISTING PD FILE OR DROP THROUGH FROM ABOVE.
  !STATE 3 CAN ONLY BE REACHED BY EXTERNAL CALL FROM 'UPDATE
  !JOURNAL' WHEN A TAPE DUMP HAS PREVIOUSLY FAILED AND
  !WE WISH TO ALLOW A FILE COLLECTION TO TAKE PLACE WHILST
  !RETAINING THE TAPE DUMP FAILURE CONTINGENCY( THE CALL WILL
  !BE ACCOMPANIED BY 'TAPESKIP' AND 'ANALSKIP')
  if  system state=3 then  call state=3
  !IE REMOTE CALL OF JOURNAL AFTER A PREVIOUS TAPE CONTINGENCY.
  system state=1
  !SETTING THE SYSTEM STATUS TO DEFAULT COLLECTION FAILURE.
  collect journal files

journal state(4):
  !FORCED DUMP TO TAPE OR FALL THROUGH FROM ABOVE.
  if  tape skip=0 start 
    cycle 
      system state = 3; ! Default state during tape dump.
      dump to tape
      exit  if  system state=0; ! Tape dump successful.
      tape retry level=tape retry level+1
      if  tape retry level=abandon tape retries start 
        printstring("Multiple tape failure, auto Journal runs suspended.".snl)
        printstring("See Journal documentation, failure no: 1.".snl)
        auto flag=off
        ss=" JOURNAL SYSTEM FAILS   FAILURE NO: 1."
        byteinteger(addr(ss)+1)=17
        !MAKE THE OPER MESSAGE FLASH.
        fail type=1
        oper(0, ss)
        return 
        !I.e. we have failed in the tape dump consistently, so stop auto runs
        !     and inform the operators of failure.  The System management will
        !     then have to sort out the tape problem (fail type 1).
      finish 
      printstring(jtxt."Dump to tape failed, retry level:")
      printstring(intostr(tape retry level).snl)
      oper(0, "JOURNAL:TRY A NEW DECK")
    repeat 
  finishelsestart 
    if  call state=3 then  system state=3 else  system state=2
    ! I.e. if remote call from 'UPDATE JOURNAL' then any tape
    !contingency is retained through the call, else assign 'SKIP' state.
    printstring(jtxt."Tape dump omitted as requested.".snl)
  finish 
  if  analskip=1 start 
    printstring(jtxt."Ended without auto analyses as requested".snl)
    if  autoflag=off then  autoflag=on
    !WE CAN ALLOW AUTO SYSTEM TO RUN SINCE COLLECTION IS OK.
    disconnect(control, flag)
    return 
  finish 
  autoflag=off; fail type=4
  !SET THE FAIL TYPE FOR AUTO ANALYSIS FAILURE.

  !NOW PERFORM THE MAIN LOG ANALYSIS FOR ''TODAY''
  parameters==record(addr(pstring)+1)
  parameters_keyword="MAINLOG"
  parameters_analysis="AUTOMATIC"
  index="MAINLOG"
  identify index(index, id char, data type, entry)
  index="JJ#".intostr(id char)."DEX"
  connect index(index, 3, index addr)
  parameters_lower file<-intostr(integer(index addr+x'28'))
  if  integer(index addr+x'28')=integer(index addr+x'20') start 
    printstring(jtxt."No files for automatic analysis (MAINLOG)".snl)
  finish  else  start 
    parameters_upper file<-intostr(cyclic(integer(index addr+x'20'), -1))
    byteinteger(addr(pstring))=x'30'
    printstring(jtxt."Running automatic analysis (MAINLOG)".snl)
    journal analysis(pstring)
    !THE ANALYSIS HAS NOW BEEN DEFINED AND RUN.
    !NOW RESET THE RUNNING PARAMETERS IN THE INDEX.
    integer(index addr+x'28')=integer(index addr+x'20')
  finish 
  disconnect(index, flag)
  !AUTO MAINLOG ANALYSIS NOW COMPLETED AND POINTERS RESET.
  if  override=on and  external=on start 
    printstring("JEF updated.")
    autoflag=on; failtype=0
    return 
  finish 

  !NOW PERFORM THE SPOOLR ANALYSIS FOR ''TODAY''
  fail type=5;  !SET FAIL TYPE FOR SPOOLR ANALYSIS.
  parameters==record(addr(pstring)+1)
  parameters_keyword="SPOOLR"
  parameters_analysis="AUTOMATIC"
  index="SPOOLR"
  identify index(index, id char, data type, entry)
  index="JJ#".intostr(id char)."DEX"
  connect index(index, 3, index addr)
  parameters_lower file<-intostr(integer(index addr+x'28'))
  if  integer(index addr+x'28')=integer(index addr+x'20') start 
    printstring(jtxt."No files for automatic analysis (SPOOLR)".snl)
  finish  else  start 
    parameters_upper file<-intostr(cyclic(integer(index addr+x'20'), -1))
    byteinteger(addr(pstring))=x'30'
    printstring(jtxt."Running automatic analysis (SPOOLR)".snl)
    journal analysis(pstring)
    !THE ANALYSIS HAS NOW BEEN DEFINED AND RUN.
    !NOW RESET THE RUNNING PARAMETERS IN THE INDEX.
    integer(index addr+x'28')=integer(index addr+x'20')
  finish 
  disconnect(index, flag)
  !AUTO SPOOLR ANALYSIS NOW COMPLETED AND POINTERS RESET.

  !NOW PERFORM THE VOLUMS ANALYSIS FOR 'TODAY'
  fail type=6;  !SET FAIL TYPE FOR VOLUMS ANALYSIS.
  parameters==record(addr(pstring)+1)
  parameters_keyword="VOLUMS"
  parameters_analysis="AUTOMATIC"
  index="VOLUMS"
  identify index(index, id char, data type, entry)
  index="JJ#".intostr(id char)."DEX"
  connect index(index, 3, index addr)
  parameters_lower file<-intostr(integer(index addr+x'28'))
  if  integer(index addr+x'28')=integer(index addr+x'20') start 
    printstring(jtxt."No files for automatic analysis (VOLUMS)".snl)
  finish  else  start 
    parameters_upper file<-intostr(cyclic(integer(index addr+x'20'), -1))
    byteinteger(addr(pstring))=x'30'
    printstring(jtxt."Running automatic analysis (VOLUMS)".snl)
    journal analysis(pstring)
    !THE ANALYSIS HAS NOW BEEN DEFINED AND RUN.
    !NOW RESET THE RUNNING PARAMETERS IN THE INDEX.
    integer(index addr+x'28')=integer(index addr+x'20')
  finish 
  disconnect(index, flag)
  !AUTO VOLUMS ANALYSIS NOW COMPLETED AND POINTERS RESET.

  !NOW PERFORM THE DIRECT ANALYSIS FOR 'TODAY'
  fail type=7;  !SET FAIL TYPE FOR DIRECT ANALYSIS.
  parameters==record(addr(pstring)+1)
  parameters_keyword="DIRECT"
  parameters_analysis="AUTOMATIC"
  index="DIRECT"
  identify index(index, id char, data type, entry)
  index="JJ#".intostr(id char)."DEX"
  connect index(index, 3, index addr)
  parameters_lower file<-intostr(integer(index addr+x'28'))
  if  integer(index addr+x'28')=integer(index addr+x'20') start 
    printstring(jtxt."No files for automatic analysis (DIRECT)".snl)
  finish  else  start 
    parameters_upper file<-intostr(cyclic(integer(index addr+x'20'), -1))
    byteinteger(addr(pstring))=x'30'
    printstring(jtxt."Running automatic analysis (DIRECT)".snl)
    journal analysis(pstring)
    !THE ANALYSIS HAS NOW BEEN DEFINED AND RUN.
    !NOW RESET THE RUNNING PARAMETERS IN THE INDEX.
    integer(index addr+x'28')=integer(index addr+x'20')
  finish 
  disconnect(index, flag)
  !Auto Direct analysis now completed and pointers reset.
  printstring(jtxt."Requested run of Journal completed.".snl)
  fail type=0; autoflag=on
  disconnect(control, flag)
  return 


  routine  remove failing file
    !HERE WE REMOVE THE QUEUED FILE  THAT IS CAUSING REPEATED FAILURES
    integer  i
    string (16) s, ns1
    if  fail file="" start 
      printstring(jtxt."No record of a failing file!".snl)
      stop 
    finish 
    if  fail file->ns1.(spool.".").s and  ns1="" start 
      printstring(jtxt."Marking ".fail file." for deletion.".snl)
      bad file=s
      disconnect(control, flag)
      stop 
    finish  else  start 
     for  i=1, 1, p file count cycle 
        if  pending files(i)=fail file then  pending files(i)=""
      repeat 
      destroy(fail file, flag)
      printstring(jtxt."File ".fail file." destroyed.".snl)
      fail file=""
      disconnect(control, flag)
      stop 
    finish 
  end ;  !OF REMOVE FAILING FILE.

  routine  bulk change index status(string (12) keyword,
          byteinteger  old, new)
  !THIS ROUTINE WILL CONNECT THE DEFINED INDEX (ALL INDICES IF KEYWORD
  != "ALL" ) AND WILL CHANGE ALL STATUS VALUES THAT ARE AT PRESENT "OLD"
  !TO "NEW"
  !JJMASTER MUST BE CONNECTED AND INDEX LIST MAPPED ON ENTRY TO THIS
  !ROUTINE.
  byteinteger  status
  integer  i, k, top file
  for  i=0, 1, total indices cycle 
    !LOOK UP THE LIST OF INDICES.
    if  (keyword="ALL" or  keyword=index list(i)_identity) and  c 
      index list(i)_identity#"" start 
      index="JJ#".intostr(index list(i)_id char)."DEX"
      connect index(index, 3, index addr)
      top file=integer(index addr+x'20');  !THE TOP FILE(+1)OF THE INDEX
      if  integer(index addr+x'24')#0 start 
        !THERE ARE FILES ON THE INDEX.
        k = top file
        cycle 
          k = cyclic(k,-1)
          ! Backwards to save cpu.
          status=index entry(k)_status
          exit  if  status=2 or  status=8
          !IE IF FILES ON TAPE ARE FOUND OR ENTRY UNUSED, THEN WE HAVE
          ! Gone far enough back through the index.
          if  status=old then  index entry(k)_status=new
        repeat  until  k=top file
      finish 
      disconnect(index, flag)
    finish 
  repeat 
  end ;  !OF BULK CHANGE INDEX STATUS.

  routine  collect journal files
  !THIS ROUTINE TAKES ALL THE FILES OFF THE INPUT QUEUE AND PUTS THEM
  !ON THE 24 HOUR PARTITION AT THE SAME TIME MAKING AN ENTRY FOR EACH
  !FILE IN THE RELEVANT INDEX.  THE CONTROL OF THE SYSTEM IS MAINTAINED
  !BY UPDATING THE CONTROL AREAS OF THE CONTROL FILE AND INDICES.

  integer  flag, i, ind, fls
  byteinteger  data type
  !DATA TYPE: DEFINES THE FILE INFORMATION TYPE IE TEXT(TEXT DATA) OR MAPPED DATA.
  string (31) file, seq

  file list from spooler
  for  ind=0, 1, total indices cycle 
    fli == file list(ind)
    continue  unless  fli_files>0
    data type=index list(ind)_data type
    ! There are files to be taken of this type.
    !ID CHAR IS DEFINED BY IND.
    index="JJ#".intostr(ind)."DEX"
    connect index(index, 3, index addr)
    for  fls=1, 1, fli_files cycle 
      file=fli_names(fls)
      check file(file, data type, flag)
      continue  unless  flag=0
      free slot=integer(index addr+x'20')
      sequence number=integer(index addr+x'24')
      seq=intostr(sequence number);  !THE STRING VERSION OF THE SEQUENCE
      !WE NOW HAVE THE INDEX POSITION AND NEW IDENTITY NUMBER OF
      !THE NEW FILE.
      new file name="J".intostr(ind)."I".seq
      !THE NEW FILE NAME.
      index entry(free slot)_file id = sequence number
      rename(pdstore."_".file.",".pdstore."_".newfilename)
      connect(pdstore."_".newfilename, 0, 0, 0, r, flag)
      monitor  and  stop  if  flag#0;  !SHOULD NOT HAPPEN.
      date and time(free slot)
      index entry(freeslot)_status=0
      integer(index addr+x'20') = cyclic(freeslot, 1)
      integer(index addr+x'24') = cyclic(sequence number, 1)
      for  i=1, 1, p file count cycle 
        if  pending files(i)=file then  pending files(i)="" c 
        and  exit 
      repeat 
      run tape=1
    repeat 
    disconnect(index, flag)
  repeat 
  p file count=0
  !IE THERE ARE NO FILES ON THE PENDING FILE LIST NOW(ALL
  !ENTRIES SHOULD BE "")
  printstring(jtxt."File collection completed.".snl)
  end ;  !OF COLLECT JOURNAL FILES.

  routine  connect control file
  !THIS ROUTINE WILL CONNECT THE MASTER CONTROL FILE JJMASTER AND
  !ALL THE NAMES LINKED TO IT .
  integer  flag
  connect(control, 3, 0, 0, r, flag)
  if  flag#0 then  master file failure(control, flag)
  system state==integer(r_conad+x'24')
  run date==integer(r_conad+x'20')
  master entry==integer(r_conad+x'708')
  !THE POINTER FOR THE ENTRY TO THE CURRENT MASTER TAPE.
  max epages==integer(r_conad+x'70C')
  total epages==integer(r_conad+x'714')
  total chapters==integer(r_conad+x'710')
  tape cycle==array(r_conad+x'720', af tape cycle)
  tape count==integer(r_conad+x'700')
  relative age==integer(r_conad+x'704')
  fail type==integer(r_conad+x'6D8')
  autoflag==integer(r_conad+x'6DC')
  !THE AUTO RUN PERMISSION FLAG.
  fail file==string(r_conad+x'6F2')
  index list==array(r_conad+x'30', af index list)
  p file count==integer(r_conad+x'1FFC')
  pending files==array(r_conad+x'2000', af pending files)
  bad file==string(r_conad+x'6EA')
  back pass <- string(r_conad+x'27D0')
  nextjjlog == byteinteger(r_conad+x'27DC')
  end ;  !OF CONNECT CONTROL FILE.

  routine  connect index(string (15) index, integer  mode,
          integername  addr)
  !THIS ROUTINE WILL CONNECT THE REQUIRED INDEX IN THE MODE
  !DEFINED AND WILL MAP THE "INDEX ENTRY" ARRAY ONTO IT. THE
  !CONNECT ADDRESS IS PASSED BACK IN ADDR.
  integer  flag
  connect(index, mode, 0, 0, r, flag)
  if  flag#0 then  master file failure(index, flag)
  addr=r_conad
  index entry==array(r_conad+x'40', af index entry)
  end ;  !OF CONNECT INDEX.

  routine  date and time(integer  index slot)
  !THIS ROUTINE IS USED TO ENTER THE RELEVANT DATES AND TIMES
  !FOR THE FILE IN THE INDEX CONNECTED. THIS WILL BE THE
  !MEANS OF SEARCH IDENTITY FOR ANY RETRIEVAL FROM THE SYSTEM.
  if  start date#"*" start 
    if  start date="" start 
      !IE NO DATES FOUND.
      if  index entry(cyclic(index slot, -1))_status#8 start 
        !IE NOT THE FIRST INDEX ENTRY.
        index entry(index slot)_starting c 
         =index entry(cyclic(index slot, -1))_finishing
        index entry(index slot)_finish ing c 
         =index entry(index slot)_starting
      finish 
      ! Leave index creation date in.  This should not happen often.
    finishelsestart 
      index entry(index slot)_starting c 
       =packdateandtime(start date, start time)
      index entry(index slot)_finishing c 
       = packdateandtime(finish date, finish time)
    finish 
  finish  else  start 
    !IN THIS CASE
    !MAINTAIN A CONTINUOUS DATE INDEX WE USE THIS AS THE FINISHING
    !DATE FOR THE FILE AND THE STARTING DATE AS THE FINISHING DATE
    !OF THE LAST FILE ON THE INDEX.
    index entry(index slot)_finishing= c 
      pack date and time(finish date, finish time)
    if  index entry(cyclic(index slot, -1))_status#8 start 
      !IE THIS IS NOT THE FIRST ENTRY IN THE INDEX
      index entry(index slot)_starting= c 
      index entry(cyclic(index slot, -1))_finishing
    finish  else  index entry(index slot)_starting= c 
      index entry(index slot)_finishing
  finish 
  end ;  !OF DATE AND TIME.

  routine  dump to tape
  !THIS ROUTINE WILL DUMP ALL THE INDEXED FILES FROM THE PD FILE
  !TO MAGNETIC TAPE CONTROLLED BY THE TAPE CYCLE INFORMATION IN
  !THE CONTROL FILE JJMASTER.
  integer  epages, chapters, file epages, displ, wkaddr
  integer  i, j, k, curraddr, len, file length, existing chapters
  integer  last bytes, count
  integer  tape change;  tape change=0
  byteintegerarray  buffer(0:4095)
  !THE TAPE IO BUFFER
  string (6)  write tape, full tape
  string (31) file name
  connect control file

  routine  tape error(string (64) s)
    !THIS ROUTINE DEALS WITH MOST OF THE 'EVERYDAY' TYPE OF TAPE ERRORS
    !OCCURING DURING THE RUN OF THE TAPE DUMP.
    printstring(jtxt."Tape error detected.".snl)
    printstring(s.snl)
    return 
  end ;  !OF TAPE ERROR.

  routine  read verify(integername  flag)
    !THIS ROUTINE READS THROUGH THE THE LAST WRITE TAPE
    !TO ENSURE THAT THERE ARE NO PROBLEMS
    integer  pages, j
    printstring(jtxt."Verifying ".write tape.snl)
    len=block
    skip tm mag(write unit, 1);  !GET BEYOND THE LABEL.
    if  chapters>0 start 
      printstring(jtxt."Verify:  skipping ".intostr(chapters-1))
      printstring(" chapters.".snl)
      flag=0
      f skip tm mag(write unit, chapters-1, flag) if  chapters>1
      !SKIP TO LAST CHAPTER
      if  flag#0 start 
        printstring(jtxt."Verify:  skip fails flag: ".intostr(flag).snl)
        flag=1
        return 
      finish 
      len=block
      read mag(write unit, wkaddr, len, flag)
      if  flag=1 start 
        printstring(jtxt."Verify: tape mark where header should be!!".snl)
        flag=1; return 
      finish 
      if  flag>1 start 
        printstring(jtxt."Verify:  failure on header read , flag: ")
        write(flag, 3); printstring("Chapter: ")
        write(chapters, 4) and  newline
        flag=1; return 
      finish 
      if  chapter header_type#"JOURNAL" or  c 
        chapter header_tape name#write tape or  c 
        chapter header_chapter#chapters start 
        printstring(jtxt."Verify:  chapter header failure: ".snl)
        printstring("            should be: ")
        printstring("Journal ".write tape." ")
        write(chapters, 4) and  newline
        printstring("            actual: ")
        printstring(chapter header_type." ".chapter header_tapename)
        write(chapter header_chapter, 5) and  newline
        flag=1; return 
      finish 
      pages=chapter header_epages
      for  j=1, 1, pages cycle 
        len=block
        read mag(write unit, wkaddr, len, flag)
        if  flag=1 start 
          printstring(jtxt."Verify:  tape mark in middle of file.".snl)
          printstring("            chapter: ")
          write(chapters, 4) and  newline
          flag=1; return 
        finish 
        if  flag>1 start 
          printstring(jtxt."Verify:  failure reading tape, flag: ")
          write(flag, 3) and  newline
          printstring("         chapter: "); write(chapters, 4) and  newline
          flag=1; return 
        finish 
      repeat 
      read mag(write unit, wkaddr, len, flag)
      if  flag#1 start 
          printstring(jtxt."Verify:  no tape mark, chapter: ")
        write(chapters, 4) and  newline
         flag=1; return 
       finish 
    finish 
    printstring(jtxt."Verify:  last existing chapter verified.".snl)
    flag=0
    return 
  end 

  routine  verify new chapters(integer  existing chapters, chapters,
          integername  flag)
    !THIS ROUTINE JUST READ VERIFIES THE NEW CHAPTERS ON THE MASTER TAPE.
    integer  pages, i, j, ch count
    ch count=0
    printstring(jtxt."Verifying ".write tape.snl)
    if  chapters-existing chapters>0 start 
      f skip tm mag(write unit, -(chapters-existing chapters+2), flag)
      if  flag#0 start 
        printstring(jtxt."Verify:  skip fails flag: ".intostr(flag).snl)
        return 
      finish 
      !NOW SHOULD BE BEFORE TM OF LAST OLD CHAPTER.
      skip tm mag(write unit, 1)
      ch count=0
      !NOW AT THE HEADER OF THE FIRST NEW CHAPTER(I HOPE)
      for  i=existing chapters+1, 1, chapters cycle 
        len=block
        read mag(write unit, wkaddr, len, flag)
        if  flag=1 start 
          printstring(jtxt."Verify: tape mark where header should be!!".snl)
          flag=1; return 
        finish 
        if  flag>1 start 
          printstring(jtxt."Verify:  failure on header read , flag: ")
          write(flag, 3); printstring("Chapter: ")
          write(i, 4) and  newline
          flag=1; return 
        finish 
        if  chapter header_type#"JOURNAL" or  c 
          chapter header_tape name#write tape or  c 
          chapter header_chapter#i start 
          printstring(jtxt."Verify:  chapter header failure: ".snl)
          printstring("            should be: ")
          printstring("Journal ".write tape." ")
          write(i, 4) and  newline
          printstring("            actual: ")
          printstring(chapter header_type." ".chapter header_tapename)
          write(chapter header_chapter, 5) and  newline
          if  i-chapter header_chapter=1 and  c 
            i=existing chapters+1 start 
            !WE HAVE THE SITUATION WHERE THE TAPE MARK OF THE FINAL EXISTING
            !CHAPTER HAS BEEN OVERWRITTEN BY THE NEW CHAPTERS, WE MUST
            !RESTORE THE DOUBLE TM AT THE END OF THIS CHPTER BEFORE FAILING.
            printstring(jtxt."Verify:  special last chapter recovery ")
            printstring("proceeding".snl)
            pages=chapter header_epages
            for  j=1, 1, pages cycle 
              len=block
              read mag(write unit, wkaddr, len, flag)
              if  flag=1 then  c 
               printstring("         Fails with TM.".snl) and  return 
              if  flag>1 start 
                printstring("         Fails, flag: ")
                write(flag, 1) and  newline
                flag=1
                return 
              finish 
            repeat 
            !OK WE ARE AT THE END OF THE LAST EXISTING CHAPTER, WRITE TWO TMS.
            write tmmag(write unit, flag)
            write tmmag(write unit, flag)
            printstring("         Recovery OK.".snl)
          finish 
          flag=1; return 
        finish 
        pages=chapter header_epages
        ch count=ch count+1
        for  j=1, 1, pages cycle 
        len=block
          read mag(write unit, wkaddr, len, flag)
          if  flag=1 start 
            printstring(jtxt."Verify:  tape mark in middle of file.".snl)
            printstring("            chapter: ")
            write(i, 4) and  newline
            flag=1; return 
          finish 
          if  flag>1 start 
            printstring(jtxt."Verify:  failure reading tape, flag: ")
            write(flag, 3) and  newline
            printstring("            chapter: "); write(i, 4) and  newline
            flag=1; return 
          finish 
        repeat 
        read mag(write unit, wkaddr, len, flag)
        if  flag#1 start 
          printstring(jtxt."Verify:  no tape mark, chapter: ")
          write(i, 4) and  newline
          flag=1; return 
        finish 
      repeat 
    finish 
    printstring(jtxt.intostr(chcount)." new chapters verified.".snl)
    flag=0
    return 
  end 

  routine  start new tape(integername  flag)
    !THIS ROUTINE IS CALLED WHEN THE CURRENT MASTER TAPE
    !IS FULL AND NEEDS TO BE REPLACED  WITH A FRESH TAPE FROM THE CYCLE.
    integer  i, max
    record (rf) r
    max epages = 7000; ! Could have been set to 0 (by JOURNAL(CLOSETAPE) ).
    printstring(jtxt."Tape dump:  ".write tape." full, starting new tape".snl)
    write tmmag(write unit, flag)
    if  flag#0 start 
      printstring(jtxt."Tape dump:  failed to write tape mark.".snl)
      flag=1; return 
    finish 
    verify new chapters(existing chapters, chapters, flag)
    if  flag=1 then  return 
    !IE VERIFY FAILED.
    unload mag(write unit)
    full tape=write tape
    write tape=""
    for  i=1, 1, tape count cycle 
      if  tape cycle(i)_age=0 then  c 
        write tape=tape cycle(i)_tsn and  exit 
    repeat 
    if  write tape="" start 
      connect("JENGPD_JENGHD",0,0,0,r,flag)
      if  flag=0 and  integer(r_conad+x'100')=5 start 
         ! 2972 - temp frig.
         oper(0,"LOG INTO JOURNL AND CALL")
         oper(0,"COMMAND 'NEW JOURNAL TAPE'")
         stop 
      finish 
      !WE WILL HAVE TO REUSE THE OLDEST TAPE
      max=10000
      for  i=1, 1, tape count cycle 
        if  tape cycle(i)_age<max and  tape cycle(i)_age#-1 start 
          max=tape cycle(i)_age
          write tape=tape cycle(i)_tsn
        finish 
      repeat 
      printstring("            reusing ".write tape.snl)
    finish 
    epages=0
    chapters=0
    existing chapters=0
    !ZEROISE THE CHAPTER COUNT.
    printstring(jtxt."Tape dump:  new write tape: ".write tape.snl)
    open mag(write unit, write tape."*")
    skip mag(write unit, 1);  !GET BEYOND THE LABEL.
    write tm mag(write unit, flag)
    flag=0
    len=block
    return 
  end ;  !OF START NEW TAPE.

  if  run tape=0 start 
    printstring(jtxt."No files to dump to tape.".snl)
    system state=0
    return 
  finish 
  wkaddr=addr(buffer(0))
  for  i=0, 1, block-1 cycle 
    buffer(i)=0
  repeat 
  !IE CLEAR DOWN THE IO BUFFER
  if  tape count<2 start 
    printstring(jtxt."Tape dump:  only "); write(tape count, 1)
    printstring(" tapes in the cycle, there must be at least 2.".snl)
    return 
  finish 
  !WE KNOW THAT THERE ARE SUFFICIENT TAPES IN THE CYCLE.
  if  master entry=-1 start 
    !THIS MUST BE THE FIRST RUN OF THE SYSTEM!
    master entry=1
    tape cycle(1)_age=-1
  finish 
  write tape=tape cycle(master entry)_tsn
  chapter header==record(wkaddr)
  !MAP THE CHAPTER HEADER RECORD ONTO THE I/O AREA.
  chapters = total chapters;  !THE NUMBER OF CHAPTERS ALREADY ON THE MASTER TAPE.
  epages = total epages;  !THE COUNT OF THE EPAGES ON THIS TAPE.
  existing chapters=total chapters
  printstring(jtxt."Tape dump:  requesting tape ".writetape." for dumping files.".snl)
  open mag(write unit, write tape."*")
  if  chapters>0 start 
    !THERE ARE FILES ALREADY ON THE TAPE, AS A CHECK READ VERIFY
    !THE TAPE UP TO THE END
    read verify(flag)
    if  flag=1 start 
      printstring("Verify:  fails!".snl)
      ->unload
    finish 
  finish  else  start 
    !OTHERWISE WE ARE STARTING A NEW TAPE.
    skip mag(write unit, 1);  !GET BEYOND THE LABEL
    write tm mag(write unit, flag)
  finish 
  !WE ARE NOW POSITIONED READY TO WRITE THE NEW FILES.
  len = block
  for  i=0, 1, block-1 cycle 
    buffer(i)=0
  repeat 
  for  i=0, 1, total indices cycle 
    continue  if  index list(i)_identity=""
    !THIS IS A 'USED' INDEX.
    id char=index list(i)_id char
    index="JJ#".intostr(id char)."DEX"
    connect index(index, 3, index addr)
    for  j=0, 1, index top cycle 
      if  index entry(j)_status=8 then  disconnect(index, flag) c 
      and  exit 
      !REACHED THE CURRENT TOP OF THE INDEX
      continue  if  index entry(j)_status#0
      !THE FILE NEEDS TO BE WRITTEN OUT TO TAPE.
      filename="J".intostr(id char)."I" c 
        .intostr(indexentry(j)_file id)
      connect(pdstore."_".file name, 0, 0, 0, r, flag)
      if  flag#0 start 
        printstring("Tape dump:  ".filename." lost!!".snl)
        index entry(j)_status=9
        !MARK THE FILE AS LOST.
      finish  else  start 
        if  epages>max epages start 
          start new tape(flag)
          ->unload if  flag=1
          tape change=1
        finish 
        !THE MASTER TAPE IS FULL START NEW TAPE(OR OLD FULL ONE.)
        file length=integer(r_conad)
        file epages=file length>>12
        if  file epages<<12 # file length start 
          last bytes=file length-file epages<<12
        file epages=file epages+1
        finish  else  last bytes=0
        displ=0
        chapters=chapters+1
        chapter header_tape name<-write tape
        chapter header_username="JOURNL"
        chapter header_file name<-filename
        chapter header_date=date
        chapter header_time=time
        chapter header_type="JOURNAL"
        chapter header_chapter=chapters
        chapter header_epages=file epages
        chapter header_fsys=-1
        chapter header_perms=0
        write mag(write unit, wkaddr, len, flag)
        if  flag#0 then  c 
          tape error("On writing file header in new chapter ".c 
          intostr(chapters)." Fails:".intostr(flag)) c 
          and  ->unload
        !THE HEADER FOR THE FILE IS NOW WRITTEN.
        printstring(chapter header_tapename)
        printstring(" ".chapter header_file name)
        spaces(1); write(chapter header_chapter, 3)
        write(chapter header_epages, 4)
        newline
        epages=epages+1
        !INCREMENT THE TOTAL EPAGE COUNT.
        for  k=1, 1, file epages cycle 
          if  k=file epages and  lastbytes>0 then  c 
          count=last bytes else  count=block
          !NOW COPY OVER EACH PAGE OF THE FILE
          curraddr=r_conad+displ
          move(count, curraddr, wkaddr)
          write mag(write unit, wkaddr, len, flag)
          !ONE PAGE FROM THE FILE.
          displ = displ+block
          if  flag#0 then  tape error("On writing page ". c 
          intostr(k)." of new chapter ".intostr(chapters). c 
          " Fails:".intostr(flag)) and  ->unload

          epages = epages+1
        repeat 
        write tmmag(write unit, flag)
        if  flag#0 start 
          printstring("Tape dump:  failed to write tape mark at ")
          printstring("End of new chapter ")
          write(chapters, 4) and  newline
          ->unload
        finish 
        !FILE IS NOW ON THE TAPE OK, FILL IN INDEX FOR TAPE POSN.
        index entry(j)_tape<-write tape
        index entry(j)_chapter=chapters
      finish 
    repeat 
    disconnect(index, flag)
  repeat 
  write tmmag(write unit, flag)
  if  flag#0 start 
    printstring("Tape dump:  failed to write double tape mark.".snl)
    ->unload
  finish 
  verify new chapters(existing chapters, chapters, flag)
  if  flag=1 then  ->unload
  !IE THE READ VERIFICATION FAILED.
unload:
  unload mag(write unit)
  return  if  flag#0; ! Error at some stage in tape handling.
  !WE HAVE NOW CHECKED THAT THE NEW TAPE INFO CAN BE READ ALL THE WAY THROUGH.
  !UPDATE THE INDICES TO  IDENTIFY THE POSITION OF THE FILE
  for  i=0, 1, total indices cycle 
    if  index list(i)_identity#"" start 
      id char=index list(i)_id char
      index="JJ#".intostr(id char)."DEX"
      connect index(index, 3, index addr)
      for  j=0, 1, index top cycle 
        if  index entry(j)_status=0 then  index entry(j)_status=1
        !THE FILE IS NOW ON TAPE
        if  tape change=1 start 
          !THERE HAS BEEN AN ADDITION OF A NEW TAPE DURING THIS DUMP.
          if  index entry(j)_tape=write tape and  c 
            index entry(j)_status>1 then  index entry(j)_status=9 c 
            and  integer(index addr+x'2C')=cyclic(j, 1)
          !THE FILE WAS ON THE REUSED TAPE SO IT IS NOW LOST. ALSO
          !THE OLDEST FILE POINTER IS UPDATED.

        finish 
        exit  if  index entry(j)_status=8
      repeat 
      disconnect(index, flag)
    finish 
  repeat 
  total epages=epages
  total chapters = chapters
  !AND AMEND THE CHAPTER COUNT AND PAGE COUNT.
  if  tape change = 1 start 
    !THERE WAS A CHANGE OF TAPE IN THIS DUMP.
    for  i=1, 1, tape count cycle 
      if  tape cycle(i)_tsn=write tape then  tape cycle(i)_age=-1 c 
      and  master entry=i
      if  tape cycle(i)_tsn=full tape c 
        then  tape cycle(i)_age=relative age +1
    repeat 
    relative age=relative age+1
    !INCREMENT THE BASE AGE COUNTER FOR TAPES.
  finish 
  !WE HAVE COMPLETED THE TAPE DUMP SUCCESSFULLY
  system state=0;  !IE TAPE DUMP COMPLETED OK.
  end ;  !OF DUMP TO TAPE.

  routine  file list from spooler
   integer  id, dt, count, fsys
    string (16) name, s
    integer  ld, hd, i, j, k, flag, dat, min, low, pass, pfcount
    ld=pack date and time("06/01/70", "01.01.01")
    hd=pack date and time("01/01/99", "01.01.01")
    string (16) file, spoolr file
    for  count=0, 1, total indices cycle 
      file list(count)_files=0
    repeat 

    !FIRST COLLECT ALL THE FILES FROM SPOOLER AND THROW OUT ANY
    !UNRECOGNISED FILES OR A MARKED BAD FILE.
    pf count=0
    pass=0
    if  p file count>0 then  pass=1
    !If the last run failed then there may be files in Journal
    !that are waiting to be processed (pending files).
    !In the following section we deal with these files first followed
    !by files from Spooler (pass 1 and pass 0).
    cycle 
      if  pass=1 and  pf count=p file count then  pass=0
      !WE HAVE LOOKED AT ALL THE PENDING FILES.
      if  pass=1 start 
        pf count=pf count+1
        file=pending files(pf count)
        connect(pdstore, 3, 0, 0, r, flag)
        if  flag #0 start 
          printstring("Journal file 'JJ#PD' lost !!!")
          newline
          stop 
        finish 
        connect(pdstore."_".file, 0, 0, 0, r, flag)
        if  flag#0 start 
          printstring(jtxt."File ".file." lost!!!".snl)
          pending files(pf count)=""
          ->next
        finish 
      finish  else  start 
        req_dest=x'FFFF003C'
        req_flag=1
        req_user="JOURNL"
        i=dpon2(spool, req, 1, 7)
        if  poff file#"" start 
          poff rep=0
          dpoff(poff rep)
          if  poff rep_flag#0 start 
            printstring(jtxt."Warning, ".poff file)
            printstring(" still on queue, flag:")
            write(poff rep_flag, 3) and  newline
          finish 
          poff file=""
        finish 
        if  i#0 start 
          printstring(jtxt."DPON2(3C) error..SPOOLR missing??".snl)
          stop 
        finish 
        repa==req; repb==req
        flag=0
        if  rep b_flag#0 then  flag=rep b_flag else  start 
          if  length(repb_file)=6 then  spoolr file=rep b_file c 
        else  start 
            flag=rep a_flag
            spoolr file=rep a_file if  flag=0
          finish 
        finish 
        file=spoolr file if  flag=0
        exit  if  flag=207
        if  flag#0 start 
          printstring(jtxt."Failed,  Spooler flag: ")
          write(flag, 3) and  newline
          printstring("          whilst accessing JOURNL queue.".snl)
          stop 
        finish 
        fail file=spool.".".file
        if  file=bad file start 
          !THIS FILE HAS BEEN MARKED AS BAD AND IS TO BE IGNORED AND REMOVED.
          disconnect(spool.".".file, flag)
          remove queued file(file)
          printstring(jtxt."File ".bad file." removed!".snl)
          bad file=""
          ->next
        finish 
        !FIND THE FILE SYSTEM FOR THIS SPOOLR.
        s=file; length(s)=2
        fsys = s to i(s)
        unless  0<=fsys<=nsys start 
          printstring(jtxt."Invalid fsys for file: ".fail file)
          printstring(" , removing queue entry".snl)
          remove queued file(file)
          ->next
        finish 
        i=(fsys<<8)!x'80'
        connect(spool.".".file, 0, 0, i, r, flag)
        if  flag#0 start 
          printstring(jtxt."Cannot connect ".fail file." flag")
          write(flag, 3) and  newline
          remove queued file(file)
          ->next
        finish 
        if  integer(r_conad+8)&x'0FFF'#0 or  integer(r_conad) c 
          >x'100000' start 
          printstring(jtxt."File SPOOLR.".file." has a corrupt")
          printstring(" Header or is too big(>1024k), file discarded.".snl)
          sdisconnect(spool.".".file, fsys, flag)
          remove queued file(file)
          ->next
        finish 
        if  r_datastart=r_dataend or  r_dataend>integer(r_conad+8) c 
          or  r_dataend<r_datastart start 
          !THE FILE IS EMPTY OR HAS A BAD HEADER.
          sdisconnect(spool.".".file, fsys, flag)
          remove queued file(file)
          printstring(jtxt."Throwing out empty/bad file ".file.snl)
          ->next
        finish 
        flen=r_dataend
        !IT IS WORTH NOTING HERE THAT THE PD FILE CAN HOLD UP TO
        !4 MEG. SINCE SPOOLER ONLY HOLDS 100 FILES IT WILL BE UNLIKELY
        !THAT THE AVERAGE FILE SIZE WILL EXCEED 40K SO A SINGLE RUN
        !IS EXTREMELY UNLIKELY TO FILL THE PARTITION ESPECIALLY
        !SINCE RUNS WILL CATCH THE QUEUE WELL BEFORE THE UPPER FILE
        !LIMIT IS REACHED.
        printstring(jtxt."Taking ".file." from ".spool)
        newline
        file="J".file
        copy(spool.".".spoolr file.",".pdstore."_".file)
        connect(pdstore, 3, 0, 0, r, flag)
        monitor  if  flag # 0
        connect(pdstore."_".file, 0, 0, 0, r, flag)
        if  flag#0 start 
          printstring(jtxt."Fails taking file from queue.".snl)
        printstring("          see documentation, failure number 2.".snl)
          ss=" JOURNAL SYSTEM FAILS   FAILURE NO: 2."
          byteinteger(addr(ss)+1)=17
          oper(0, ss)
          autoflag=off;  fail type=2
          sdisconnect(spool.".".spoolr file, fsys, flag)
          requeue file(spoolr file)
          stop 
        finish 
        !THE FILE HAS BEEN SUCCESSFULLY COPIED INTO JOURNL.
        sdisconnect(spool.".".spoolr file, fsys, flag)
        remove queued file(spoolr file)
        fail file=""
      finish 
      id=integer(r_conad+x'18')
      dt = dtword(integer(r_conad+x'14'))
      ! Note that date in logfile header is STILL in old format (put there by Director).
        if  id&x'FF' = 0  then  integer(r_conad+4)=x'20'
        !TO GET ROUND PETES FAULT IN SUPERV.
      flag=0
      if  (id>>8)=x'FFFFFF' start 
        id=x'FF'&id
        if  0<=id<=total indices start 
          flag=1
          if  ld<=dt<=hd then  flag=2
          !IE IS THE DATE AND TIME OK FOR RANGE?
        finish 
      finish 
      if  flag=2 start 
        if  index list(id)_identity#"" start 
         !WE RECOGNISE THE FILE
          file list(id)_files=file list(id)_files+1
          count=file list(id)_files
          file list(id)_names(count)<-file
          file list(id)_dts(count)=dt
          if  pass=0 start 
            !ONLY ADD FILE TO PENDING LIST IF NEWLY OFF SPOOLER.
            p file count=p file count+1
            pending files(p file count)=file
          finish 
          if  count=100 start 
            printstring(jtxt."Filled file space, ")
            printstring("Commencing processing!!".snl)
          printstring("          Some files will be unordered!!!!".snl)
            exit 
          finish 
        finish  else  start 
          printstring(jtxt.file." not recognised !!".snl)
          printstring("           type ".intostr(id)." invalid.".snl)
        finish 
      finish  else  start 
        if  flag=0 then  c 
          printstring(jtxt.file." not a 'JOURNAL' file!!".snl)
        if  flag=1 start 
          printstring(jtxt.file." has bad date/time entry!!".snl)
          spaces(10)
          printstring(unpackdate(dt)." ".unpacktime(dt).snl)
        finish 
        newlines(2)
        send(file.",.LP");  !SEND TO PRINTER IF INVALID FILE.
      finish 
    next:
    repeat 
    !Now sort each queue of pending files into chronological order.
    for  i=0, 1, total indices cycle 
      fli == file list(i)
      count=fli_files
      continue  if  count=0
      for  j=1, 1, count-1 cycle 
        low=j; min=fli_dts(j)
        for  k=j+1, 1, count cycle 
          if  fli_dts(k)<min start 
            min=fli_dts(k)
            low=k
          finish 
        repeat 
        if  low#j start 
          name=fli_names(low)
          dat=fli_dts(low)
          fli_names(low) = fli_names(j)
          fli_dts(low)=fli_dts(j)
          fli_names(j) = name
          fli_dts(j) = dat
        finish 
      repeat 
      printstring("Index: ".intostr(i));newline
      for  j=1, 1, count cycle 
        printstring(fli_names(j)." ". c 
        unpackdate(fli_dts(j))." ". c 
        unpacktime(fli_dts(j)))
        newline
      repeat 
    repeat 
 end ;  !OF FILE LIST FROM SPOOLR.

 routine  check file(string (*)name  file, byteintegername   c 
          data type, integername  flag)
  !THE ROUTINE LOOKS FOR DATE AND TIME INFORMATION IN THE FILE
  integer  word count, i
  !
  routine  reverse line to atoms(integername  word count,
         stringarrayname  atoms, byteintegerarrayname  buff)
  !HERE WE READ A LINE OF THE FILE INTO AN ARRAY OF "ATOMS" PASSING
  !BACK THE RESULTING WORDS(WORD COUNT  DEFINING THE NUMBER OF WORDS)
  !IN THE ARRAY ATOM.
  integer  adn
  byteinteger  ch, i
  word count=0; endflag=0; i=0
  cycle 
    chpointer=chpointer-1
    if  chpointer<flen then  endflag=1 and  return 
    ch=buff(chpointer)
    exit  if  ch>32
  repeat 
  cycle 
    if  ch=32 or  ch=10 start 
      if  i>0 then  byteinteger(adn)=i and  i=0
      return  if  ch=10
    finish  else  start 
      if  32<ch<128 start 
        if  i=0 start 
          word count=word count+1 unless  word count=68
          adn=addr(atoms(word count))
        finish 
        i=i&x'7F'+1
        !LENGTH OF ATOM SHOULD NOT EXCEED 127, SET TO 1 IF OCCURS!!
        byteinteger(adn+i)=ch
      finish 
    finish 
    chpointer=chpointer-1
    if  chpointer<flen then  endflag=1 and  ch=10 c 
    else  ch=buff(chpointer)
  repeat 
  end ;  !OF REVERSE LINE TO ATOMS.

  start date=""
  fail file=file
  connect(pdstore."_".file, 0, 0, 0, r, flag)
  if  flag#0 start 
    printstring(jtxt."Cannot connect ".file." for date search!".snl)
    stop 
  finish 
  if  datatype=1 or  integer(r_conad+x'18')&x'FF'=5 start 
    !IE WITH A MAPPED DATE FILE OR BACKUP/ARCHIVE REPORT FILE WE KNOW THAT
    !THE DATE INFORMATION IS THAT CONTAINED IN WORD 6 OF THE HEADER.
    start date="*"
    finish date=unpack date(integer(r_conad+x'14'))
    finish time=unpack time(integer(r_conad+x'14'))
    disconnect(pdstore."_".file, flag)
    flag=0
    fail file=""
    return 
  finish 
  buff==array(r_conad+r_datastart, af buff)
  flen=r_dataend-r_datastart
  chpointer=0
  cycle 
    line to atoms(word count, atoms, buff)
    exit  if  endflag=1
    if  word count>=3 start 
      if  atoms(1)="DT:" start 
        start date=atoms(2)
        start time=atoms(3)
        exit 
      finish 
      if  atoms(1)="SDT:" start 
        finish date=atoms(2)
        finish time=atoms(3)
        start date="*"
        exit 
      finish 
    finish 
  repeat 
  unless  start date="*" start 
    finish date=start date
    finish time=start time
    chpointer=flen
    flen=1
    cycle 
      reverse line to atoms(word count , atoms, buff)
      exit  if  endflag=1
      if  word count>=3 and  atoms(word count)=":TD" start 
        if  length(atoms(word count-1))=length(atoms(word count-2))=8 c 
        start 
          for  i=8, -1, 1 cycle 
            byteinteger(addr(finish date)+9-i) c 
            =byteinteger(addr(atoms(word count-1))+i)
            byteinteger(addr(finish time)+9-i)= c 
            byteinteger(addr(atoms(word count-2))+i)
          repeat 
          length(finish time)=8
          length(finish date)=8
          exit 
        finish 
      finish 
    repeat 
  finish 
  disconnect(pdstore."_".file, flag)
  fail file=""
  flag=0
  end ;  !OF CHECK FILE.

  routine  remove queued file(string (6) file)
  !HERE WE TELL SPOOLER TO REMOVE THE SPECIFIED FILE, IE DELETE IT, FROM
  !ITHE JOURNAL QUEUE.
    integer  i
    req_dest=x'FFFF003D'
    req_flag=0
    req_user="JOURNL"
    req_file<-file
    i=dpon2(spool, req, 1, 6)
    if  i#0 start 
      printstring(jtxt."DPON2(3D) error..SPOOLR missing??".snl)
      stop 
    finish 
    poff file=file
  end ;  !OF REMOVE QUEUED FILE.

  routine  requeue file(string (6) file)
    !HERE WE REQUEUE A FILE AFTER A PROBLEM.
    integer  i
    req_dest=x'FFFF003D'
    req_flag=1
    req_file<-file
    req_user="JOURNL"
    i=dpon2(spool, req, 1, 7)
    if  i#0 start 
      printstring(jtxt."DPON(3D) error, SPOOLR missing??".snl)
      stop 
    finish 
    repa==req; repb==req
    flag=repb_flag
    if  flag #0 start 
      printstring(jtxt."File: ".file." cannot requeue!".snl)
    finish 
    return 
  end ;  !OF REQUEUE FILE

  integerfn  autojob(string (15) name, string (*)name  ident)
    !THIS ROUTINE INTERROGATES SPOOLR TO SEE IF THERE IS A BATCH JOB
    !'NAME' IN THE QUEUE AND PASSES BACK ITS IDENTITY.
  recordformat  fhf(integer  end, start, size, type, spare0, datetime,
          spare1, spare2)
  recordformat  infof(integer  vsn, state, string (7) ident, user,
          string (15) dest, srce, output, string (31) name)
  string (63) message
  record (infof)name  info
  record (fhf)name  fh
  record  (f parm)p
  integer  i, entries, flag
  destroy("JJINF", flag)
  message="COMMAND QUEUE BATCH,JJINF"
  p=0
  flag=dspool(p, length(message), addr(message)+1)
  if  flag#0 start 
    printstring("SPOOLR fault: no access!!".snl)
    respool journal("MONITOR")
    stop 
  finish 
  connect("JJINF", 0, 0, 0, r, flag)
  if  flag#0 start 
    printstring("Cannot connect SPOOLR info file for 'AUTOJOB'".snl)
    respool journal("MONITOR")
    stop 
  finish 
  fh==record(r_conad)
  ident=""
  entries=(fh_end-fh_start)//256
  result =no if  entries=0
  for  i=1, 1, entries cycle 
    info==record(r_conad+32+(i-1)*256)
    if  info_name=name and  info_state=1 then  ident = info_ident and  result =yes
  repeat 
  result =no
  end ;  !OF AUTOJOB.

  routine  respool journal(string (15) name)
    !This routine is used to detach the auto command file that controls
    !the Journal system in background mode. The detached files start Journal
    !automatically every hour.
    string (255) msg
    integer  flag
    string (8) tt, th, timereq; integer  hours, j, ocptype
    connect("JENGPD_JENGHD", 0, 0, 0, r, flag)
    ocptype=16
    if  flag=0 start 
      if  0<=integer(r_conad+x'100')<=15 then  c 
      ocptype=integer(r_conad+x'100')
    finish 
    if  name = "HOUSEKEEP" then  timereq=ocptimereq(ocptype) else  timereq = "10"
    define("STREAM12,JCMDFILE")
    select output(12)
    msg = "JOURNAL(AUTOCALL"
    if  name = "HOUSEKEEP" then  msg = msg."+DECK)" else  msg = msg.")"
    if  uinfi(16)=0 start ; ! NOBRACKETS option in force.
       charno(msg,8) = ' '
       length(msg) = length(msg)-1
    finish 
    printstring(msg)
    newline
    select output(0)
    close stream(12)
    disconnect("JCMDFILE", flag)
    msg="DOCUMENT DEST=BATCH,USER=JOURNL, PASS=".back pass.", "
    msg=msg."SRCE=JCMDFILE,TIME=".timereq.",PRTY=VHIGH,NAME=".name.","
    tt=time
    tt->th.(".").tt
    hours = s to i(th)
    hours=hours+1
    if  hours=24 then  tt="23.59.59" else  start 
      th=intostr(hours)
      if  length(th)=1 then  th="0".th
      tt=th.".".tt
    finish 
    if  name = "HOUSEKEEP" then  msg=msg."DECKS=1" else  c 
     msg=msg."AFTER=".date." ".tt
    msg = msg.",OUT=FILE,OUTNAME=JJLOG".tostring('0'+nextjjlog)
    msg = msg.",RERUN=NO
"
    p=0
    j=0
    j=dspool(p, length(msg), addr(msg)+1)
    if  j#0 start 
      printstring("Cannot spool auto command file(".name.") flag:")
      write(j, 3) and  newline
      ss=" JOURNAL SYSTEM FAILS   FAILURE NO: 3."
      byteinteger(addr(ss)+1)=17; ! Flashing.
      fail type=3
      autoflag=off
      oper(0, ss)
    finishelse  nextjjlog = (nextjjlog+1)&7; ! Thus 0<=nextjjlog<=7.
  end ; !OF RESPOOL JOURNAL

  routine  start up
  !The system state setting from the last run of Journal is looked at
  !and based on this a decision is made on the route for the startup of
  !this run.
  integer  i, j
  conststring (7)array  fail anal(4:7) = "MAINLOG","SPOOLR","VOLUMS","DIRECT"
  switch  sw(0:4)
  if  autocall = on and  autoflag = off start 
    !THIS IS AN AUTOMATIC CALL OF JOURNAL BUT IT CANNOT
    !PROCEED BECAUSE THE AUTO FLAG HAS BEEN SET TO INDICATE AN ERROR
    !CONDITION IS PRESENT FROM THE LAST RUN.
    ss=" JOURNAL IN FAIL STATE"
    ss=ss."  FAILURE NO: ".intostr(fail type)
    byteinteger(addr(ss)+1)=17
    oper(0, ss)
    printstring(jtxt."Fail state ".intostr(fail type))
    printstring(" recorded on oper!".snl)
    stop 
  finish 
  if  autocall=on start 
    !OK TO PROCEED WITH AUTOMATIC RUN OF JOURNAL.
    printstring("Automatic Journal run.".snl)
    j=minutes between(run date, packdateandtime(date, time))
    flag=0
    !TEST A: >=24 HRS SINCE LAST RUN AND >16K BYTES IN QUEUE.
    if  j>=24*60 and  queue_amount>16*1024 then  flag=1
    !TEST B: >=25 FILES IN QUEUE OR >0.8 MEG OF FILES IN QUEUE.
    if  queue_amount>(800*1025) or  queue_length>=25 c 
    then  flag=1
    !TEST C:(FOR PRIME TIME ONLY)>=45 FILES OR >2 MEG OF FILES
    if  queue_amount>(2000*1024) or  queue_length>=45 c 
    then  flag=2
    printstring("SPOOLR parameters:".snl)
    printstring("Files:"); write(queue_length, 3) and  newline
    printstring("Total size:"); write(queue_amount, 6) and  newline
    printstring("Minutes since last run:"); write(j, 5) and  newline
    if  prime start<packdate and time(date, time)<prime end start 
      printstring("We are in prime period.".snl); newline
      flag=0 if  flag=1
    finish 
    if  system state#0 start 
      printstring(jtxt."Last run incomplete, or failed")
      printstring(" (system crash?).".snl)
      printstring("Running again to clear problem.".snl)
      flag=1
    finish 
    if  flag>=1 start 
      !WE WANT A FULL RUN.
      if  decks = on then  printstring("**Commencing auto run**".snl) C 
       else  start 
        !DETACH THE JOB TO DO THE FULL RUN.
        respool journal("HOUSEKEEP") if  autojob("HOUSEKEEP", identj)=off
        printstring("Full run detached or already there.".snl)
        if  identj = "" then  flag = autojob("HOUSEKEEP", identj)
        !FIND OUT THE IDENTITY IF JUST QUEUED.
        flag = 0
        ss=" JOURNAL RUN REQUIRED "
        ss=ss."  RUN ".identj." SOON!"
        byteinteger(addr(ss)+1)=17
        oper(0, ss)
      finish 
    finish  else  printstring("**Full run not required**".snl)
    stop  if  flag=0
  finish 
  run date=pack date and time(date, time)
  ->sw(system state)
sw(0):
    !ALL OK IN THE LAST RUN.
    if  fail type<4 start 
    printstring(jtxt."Last run of Journal ended normally ".snl)
    finish  else  start 
    printstring(jtxt."Last run completed housekeeping but the".snl)
    printstring("auto ".fail anal(failtype)." analysis failed!!".snl)
    finish 
    return 
sw(1):
    printstring(jtxt."Restarting from Spooler unloading")
    printstring(" failure during previous run".snl)
    if  fail file#"" start 
      printstring(jtxt."File: ".fail file." error warning!".snl)
    finish  else  start 
    printstring(jtxt."No file in error, probably system crash?".snl)
    finish 
    !TRIM DOWN THE PENDING FILE LIST(IE THOSE FILES LEFT OVER FROM FAILURE
    !OF THE LAST RUN.)
    if  p file count>0 start 
      i=0
      cycle 
        i=i+1; exit  if  i=p file count+1
        if  pending files(i)="" start 
          if  i=p file count then  p file count=p file count-1 c 
          and  exit 
          for  j=i+1, 1, p file count cycle 
            pending files(j-1)=pending files(j)
          repeat 
          p file count=p file count-1
          i=i-1
        finish 
      repeat 
    finish 
    system state=2
    !ALLOW RESTART
    run tape=1
    return 
sw(2):
    printstring(jtxt."Last run skipped tape dump.".snl)
    run tape=1
    return 
sw(3):
    if  tapeskip=1 start 
      if  external=off start 
        printstring(jtxt."The tape dump failed last run.".snl)
        printstring("          Skip option not valid after failure!".snl)
        stop 
      finish  else  start 
        !IE CALL FROM 'FULL JOURNAL ANALYSIS' ALLOWED TO RUN
        !FILE COLLECTION EVEN THOUGH THERE WAS A TAPE CONTINGENCY
        !ON THE LAST RUN. THE CONTINGENCY WILL BE RETAINED(UNLESS OF
        !COURSE THE FILE COLLECTION FAILS AND THIS HIGHER PRIORITY
        !CONTINGENCY IS THEN REMEMBERED)
        printstring(jtxt."Last run failed in tape dump".snl)
      printstring("          Allowing file collection run for 'FULL")
        printstring(" Journal analysis'".snl)
        system state=3
        return 
      finish 
    finish 
    run tape=1
    printstring(jtxt."The tape dumping failed last run.".snl)
    if  autocall=on start 
    printstring("          Must have been system crash, proceeding ")
      printstring("with file collection.".snl)
      system state=2
    finish  else  start 
      printstring("          Retrying the tape dump.".snl)
      system state=4
    finish 
    return 
sw(4):
    !SHOULD NOT RETURN HERE EXCEPT IN FLUKE "SYSTEM DOWN" SITUATION.
    !SHOULD TREAT THIS AS SW(3) TYPE ASSUMING TAPE DUMP TO BE RETRIED.
    printstring(jtxt."Retrying tape dump.".snl)
    run tape=1
    return 
  end ;  !OF START UP.
  end ;  !OF JOURNAL

! ************************************************************************
! ************************************************************************
! ************************************************************************
  externalroutine  journal state(string (255) s)
  record (f queue)name  queue
  record (f tape cycle)arrayformat  af tape cycle(1:100)
  record (f tape cycle)arrayname  tape cycle
  record  (rf)r
  integer  j, i, status, flag, autoflag, fail type, queues, k, latedate
  string (8) tdate, ttime
  newpage
  printstring("Journal status report ".date." ".time)
  newline
  connect(control, 0, 0, 0, r, flag)
  if  flag#0 then  master file failure(control, flag)
  status=integer(r_conad+x'24')
  autoflag=integer(r_conad+x'6DC')
  fail type=integer(r_conad+x'6D8')
  tdate=unpack date(integer(r_conad+x'20'))
  ttime=unpack time(integer(r_conad+x'20'))
  printstring("Last run on ".tdate." at ".ttime);newline
  j = -1; latedate = 0
  for  i=0,1,7 cycle 
      connect("JJLOG".tostring('0'+i), 0, 0, 0, r, flag)
      continue  if  flag#0
      k = integer(r_conad+20)&x'7FFFFFFF'; ! Time last changed.
      j = i and  latedate=k if  k>latedate
  repeat 
  if  j=-1 then  printstring("No autojob logfiles found") else  c 
    printstring("Last autojob logfile: JJLOG".tostring('0'+j))
  newlines(2)
  printstring("Status details: ")
  if  autoflag=1 start 
    if  status=0 start 
      printstring("In automatic housekeeping mode.");newline
      printstring("Action required: none.");newlines(2)
    finish  else  start 
      printstring("Last auto housekeeping failed, recovery will ")
     newline; printstring("                be attempted automatically.")
      newline; spaces(16);printstring("[")
      printstring(journal status(status)."]");newline
      printstring("Action required: none.");newlines(2)
    finish 
  finish  else  start 
    if  fail type=0 start 
      printstring("In manual mode with an unexplained error or after")
      newline;printstring("                a System crash.");newline
      spaces(16);printstring("[")
      printstring(journal status(status)."]")
      newline
      printstring("Action required: JOURNAL OVERRIDE in JOURNL process.")
      newlines(2)
    finish  else  start 
      printstring("In manual mode due to failure, doc ref: ")
      write(failtype, 2);newline; printstring("Action required: ")
      printstring("see Journal documentation.");newlines(2)
    finish 
  finish 
  connect(spool.".CFILE", 9, 0, 0, r, flag)
  if  flag#0 start 
    !WE CANNOT CONNECT THE SPOOLR INFO FILE.
    printstring("Spoolr descriptor file (CFILE) connect fails:")
    write(flag, 3); newline
    printstring("Log off and try again.")
    newline
    stop 
  finish 
  queues=integer(r_conad+x'18')
  if  queues=0 start 
    printstring("No queues defined in SPOOLR descriptor file")
    newline
  finish 
  for  i=1, 1, queues cycle 
    queue==record(r_conad+x'20'+148*(i-1))
    if  queue_name="JOURNAL" then  exit 
    if  i=queues start 
      printstring("Journal queue not in SPOOLR descriptor file")
      newline
    finish 
  repeat 
  printstring("Current state of the 'JOURNAL' queue:");newline
  printstring("Files:"); write(queue_length, 3)
  printstring("   Total bytes:"); write(queue_amount, 6)
  newline
  connect(control, 0, 0, 0, r, flag)
  if  flag#0 then  master file failure(control, flag)
  !NOW ADD THE DETAILS FROM THE TAPE CONTROL .
  j=0
  newline
  printstring("Tape cycle: there are ");write(integer(r_conad+x'700'), 3)
  printstring(" tapes in the cycle.")
  newline
  if  integer(r_conad+x'700')>0 start 
    !THERE ARE TAPES IN THE CYCLE TO DESCRIBE.
    tape cycle==array(r_conad+x'720', af tape cycle)
    if  integer(r_conad+x'708')>0 start 
      !THERE IS AN ASSIGNED MASTER , IE. SYSTEM IN USE.
      printstring("Master tape: ")
      printstring(tape cycle(integer(r_conad+x'708'))_tsn)
      printstring(" with a total of "); write(integer(r_conad+x'710'), 4)
      printstring(" chapters, "); write(integer(r_conad+x'714'), 4)
      printstring(" epages.")
      newline
    finish 
    newline; printstring("Full tape cycle list:")
    newline
    for  i=1, 1, integer(r_conad+x'700') cycle 
      j=j+1
      printstring("TSN:".tape cycle(i)_tsn." ")
      if  tape cycle(i)_age=-1 then  printstring("master tape")
      if  tape cycle(i)_age=0 then  printstring("unused tape")
      if  tape cycle(i)_age>0 then  printstring("full tape  ")
      if  j=3 then  newline and  j=0 else  spaces(3)
    repeat 
  finish 
  newlines(2)
  printstring("End of system summary.")
  newline
  disconnect(control, flag)
  end ;  !OF JOURNAL STATE.

! ************************************************************************
! ************************************************************************

  externalroutine  list journal index(string (255) s)
  ! Parameter can be "dd/mm/yy,dd/mm/yy" (either or both optional), to
  ! specify the range of files of interest.

  record (f index entry)arrayformat  af index entry(0:index top)
  record (f index list)arrayformat  af index list(0:total indices)
  record (f index entry)arrayname  index entry
  record (f index entry)name  ie
  record (f index list)arrayname  index list
  record  (rf)r
  conststring (40) array  status description(0:9)= c 
    "ON LINE",
    "ON LINE AND ON TAPE: ",
    "            ON TAPE: ",
    "", "", "", "", "", "",
    "LOST!!!!!!!!!"
  string (8) index, tdate, ttime
  string (16) reply
  byteinteger  id, data type
  integer  i, flag, status, entry, lost flag, early, late
  connect(control, 0, 0, 0, r, flag)
  if  flag#0 then  master file failure(control, flag)
  index list==array(r_conad+x'30', af index list)
  early = pack date and time("01/01/72","00.00.00")
  late = current packed dt
  if  s#"" start ; ! Date range specified.
      if  s -> s.(",").reply start 
         if  length(reply)=8 and  charno(reply,3)='/' and  charno(reply,6)='/' c 
            then  late = pack date and time(reply,"23.59.59")
      finish 
      if  length(s)=8 and  charno(s,3)='/' and  charno(s,6)='/' then  c 
            early = pack date and time(s,"00.00.00")
  finish 
  if  early>late start 
      printstring(jtxt."Early date is after late date??")
      newline
      return 
  finish 
  cycle 
    !Find out which file is to be listed.
    prompt("INDEX KEYWORD:")
    read prompt reply(reply)
    if  reply="HELP" start 
      printstring(jtxt."Current index keywords:"); newlines(2)
      for  i=0, 1, total indices cycle 
        !LIST OUT THE INDEX KEYWORDS.
        if  index list(i)_identity#"" then  c 
          printstring(index list(i)_identity) and  newline
      repeat 
      return 
    finish 
    identify index(reply, id, data type, entry)
    !FIND THE IDENTITY CHARACTER OF THIS INDEX.
    exit  if  id#100
    printstring(jtxt."Reply help for a list of keywords")
    newline
  repeat 
  index="JJ#".intostr(id)."DEX"
  !THE INDEX FILE
  connect(index, 0, 0, 0, r, flag)
  if  flag#0 then  master file failure(index, flag)
  define("STREAM10,JLIST,1024")
  select output(10)
  printstring(jtxt."List of index ".index.".  ".date." ".time)
  newline
  printstring("===================================================")
  newlines(2)
  printstring("Date range: ".unpackdate(early)." - ".unpackdate(late))
  newlines(2)
  printstring("Index keyword: ".reply)
  newlines(3)
  lost flag = 0; ! Used to prevent repeated "file lost" output.
  index entry==array(r_conad+x'40', af index entry)
  for  i=0, 1, index top cycle 
    ie == index entry(i)
    exit  if  ie_file id=-1
    ! IE THE CURRENT TOP OF THE INDEX.

    continue  if  ie_finishing<early or  ie_starting>late; ! File not in requested range.
    if  ie_status=9 start 
       if  lost flag=1 start 
          printstring("              ..... all lost up to .....")
          newline
       finish 
       lost flag = lost flag+1
       continue  if  lost flag>1
    finish  else  lost flag = 0
    printstring("File: ")
    write(ie_file id, 5)
    tdate=unpack date(ie_starting)
    ttime=unpack time(ie_starting)
    printstring("  ".tdate." ".ttime." to ")
    tdate=unpack date(ie_finishing)
    ttime=unpack time(ie_finishing)
    printstring(tdate." ".ttime."  status: ")
    status=ie_status
    printstring(status description(status))
    if  1<=status<=2 then  printstring(ie_tape) c 
      and  printstring("(".intostr(ie_chapter).")")
    newline
  repeat 
  newlines(2)
  printstring(jtxt."End of list of index: ".index)
  newlines(3)
  select output(0)
  close stream(10)
  printstring(jtxt."List prepared in JLIST.")
  newlines(2)
  disconnect(index, flag)
  disconnect(control, flag)
  end ;  !OF LIST JOURNAL INDEX

! ************************************************************************
! ************************************************************************
! *************************************************************************
  externalroutine  new journal index(string (255) s)
  !STRING S WILL ONLY BE SET WHEN THE ROUTINE IS CALLED FROM
  !"CREATE JOURNAL SYSTEM" WITH S='SYSTEM'. IN THIS CASE ALL THE SYSTEM
  !INDICES ARE INITIALISED. ON A NORMAL CALL S IS NOT SET AND A SET
  !OF PROMPTS ARE USED TO DEFINE THE INDEX TO BE SET UP.
  record (f index list)arrayformat  af index list(0:total indices)
  record (f index entry)arrayformat  af index entry(0:index top)
  record (f index list)arrayname  index list
  record (f index entry)arrayname  index entry
  record  (rf)r
  integer  i, j, k, flag, entry, data
  string (16) reply, dtype
  byteinteger  id char, data type

  integerfn  empty slot(integer  type)
    !FIND THE NEXT EMPTY INDEX SLOT IN JJMASTER THAT WILL
    !DEFINE THE IDENTITY OF THE NEW INDEX.
    integer  i, j
    if  type=0 then  j=0 else  j=system indices+1
    for  i=j, 1, total indices cycle 
      if  index list(i)_identity="" then  result =i
    repeat 
    result =-1
  end ;  !OF EMPTY SLOT.

  routine  new index(byteinteger  id char, integername  flag)
    !CREATE AND INITIALISE A NEW INDEX DEFINED BY ID CHAR
    !FLAG=0: SUCCESS, FLAG=1: FAILURE.
    record (f index entry)name  ie0
    string (8) file
    integer  i, conad, cflag
    file="JJ#".intostr(id char)."DEX"
    flag=1;  !DEFAULT FAILURE.
    connect(file, 0, 0, 0, r, cflag)
    if  cflag=0 start 
      printstring(jtxt.file." already exists")
      newlines(2)
      return 
    finish 
    create jfile(file, index top+1 {cells}, 24 {cell size}, x'40' {header},
      conad, cflag)
    if  cflag#0 start 
      printstring(jtxt."Cannot create ".file." flag:")
      write(cflag, 3)
      newlines(2)
      return 
    finish 
    integer(conad+x'20')=0;  !NEXT FREE INDEX ENTRY, ALSO USED AS POINTER TO LAST(+1) FILE FOR AUTO ANALYSIS.
    integer(conad+x'24')=0;  !NEXT FREE SEQUENCE NO.
    integer(conad+x'28')=0;  !NEXT FILE ENTRY TO BE PROCESSED BY AUTO ANAL.
    integer(conad+x'2C')=0;  !The oldest file on the index pointer.
    index entry==array(conad+x'40', af index entry)
    ie0 == index entry(0)
    ie0_file id=-1
    ie0_starting = current packed dt
    ie0_finishing=ie0_starting
    ie0_status=8
    ie0_chapter=-1
    ie0_tape=""
    index entry(i) = ie0 for  i=1,1,index top
    disconnect(file, flag)
    cherish(file)
    printstring(jtxt."File recognition number for ".file." is: ")
    write(id char, 3)
    newline
    flag=0;  !SUCCESSFUL.
  end ;  !OF NEW INDEX

  connect(control, 3, 0, 0, r, flag)
  if  flag#0 then  master file failure(control, flag)
  index list==array(r_conad+x'30', af index list)
  !THE INDEX CONTROL LIST.
  if  s="SYSTEM" start 
    !A CALL FROM 'CREATE JOURNAL SYSTEM' TO INITIALISE SYSTEM INDICES.
    for  i=0, 1, used system indices cycle 
      !CREATE EACH OF THE SYSTEM INDICES.
      j=empty slot(0)
      !THE NEXT EMPTY INDEX SLOT.
      if  j#i start 
        !NO INDICES SHOULD ALREADY EXIST.
        printstring(jtxt."Severe warning, do not attempt ")
        printstring("to recreate system indices!!!")
        newlines(2)
        disconnect(control, flag)
        return 
      finish 
      id char=index list(j)_id char
      !THE IDENTITY CHARACTER OF THE NEW INDEX.
      new index(id char, flag)
      if  flag#0 start 
        printstring(jtxt."Failed to create system index!")
        newline
        for  k=1, 1, i cycle 
          exit  if  k=i
          destroy("JJ#".intostr(index list(k)_id char)."DEX", flag)
          !DESTROY ALL THE ALREADY CREATED SYSTEM INDICES.
          index list(k)_identity=""
        repeat 
        disconnect(control, flag)
        destroy(control, flag)
        !DESTROY JJMASTER AS WELL TO GIVE CLEAN RETRY.
        printstring(jtxt."Try running create again after checking")
        printstring(" over the process")
        newlines(3)
        stop 
      finish 
      index list(j)_identity<-system keyword(i)
      index list(i)_data type=0; !DEFAULT VALUE OF 'TEXT'.
      if  system keyword(i)="ACCOUNTS" then  index list(i)_data type=1
      !IE THIS IS A MAPPED DATA TYPE FILE.
      printstring(jtxt.system keyword(i)." index initialised")
      newlines(2)
    repeat 
    printstring(jtxt."All system indices created.")
    newlines(3)
    disconnect(control, flag)
    return 
  finish ;  !OF "SYSTEM" JOURNAL INDICES CREATION.
  !BELOW CODE WILL ADD INSTALLATIONS OWN INDEX.
  !WHICH WILL BE INDICES 10-19, OR IT WILL BE USED
  !TO ADD A NEW SYSTEM INDEX (RANGE 0-9)
  cycle 
    prompt("SYS OR OWN:")
    read prompt reply(reply)
    exit  if  reply="SYS" or  reply="OWN"
  repeat 
  if  reply="SYS" then  j=empty slot(0) else  j=empty slot(1)
  cycle 
    prompt("INDEX KEYWORD:")
    read prompt reply(reply)
    exit  if  0<length(reply)<=12
    printstring(jtxt.reply." too long??")
    newlines(2)
  repeat 
  data=-1
  cycle 
    prompt("TEXT OR MAPPED:")
    read prompt reply(dtype)
    data=0 if  dtype="TEXT"
    data=1 if  dtype="MAPPED"
    exit  if  data#-1
  repeat 
  if  j=-1 start 
    printstring(jtxt."System full, no further indices.")
    newlines(2)
    return 
  finish 
  identify index(reply, id char, data type, entry)
  if  id char<100 start 
    printstring(jtxt."Keyword already used!!")
    newlines(2)
    return 
  finish 
  id char = index list(j)_id char
  new index(id char, flag)
  !CREATE THE NEW INDEX DEFINED BY ID CHAR.
  if  flag#0 start 
    printstring(jtxt."Failed to create ".reply." index!")
    newlines(2)
    return 
  finish 
  index list(j)_identity<-reply
  index list(j)_data type<-data
  !FILL IN THE KEYWORD NOW INDEX CREATED.
  printstring(jtxt.reply." index initialised.")
  newlines(3)
  disconnect(control, flag)
  end ;  !OF NEW JOURNAL INDEX.

! ************************************************************************
! ************************************************************************
! ************************************************************************
  externalroutine  new journal tape(string (255) s)
  record (f tape cycle)arrayformat  af tape cycle(1:100)
  record (f tape cycle)arrayname  tape cycle
  record  (rf)r
  integer  i, flag
  integername  tape count
  string (16) reply
  !THE CONTROL MASTER FILE.
  connect(control, 3, 0, 0, r, flag)
  !WE WANT TO WRITE TO IT.
  if  flag#0 then  master file failure(control, flag)
  tape count==integer(r_conad+x'700')
  !THE TOTAL TAPES IN THE CYCLE.
  cycle 
    !GET THE TAPE IDENTITY TO BE ADDED TO THE CYCLE.
    prompt("JOURNAL TAPE:")
    read prompt reply(reply)
    if  length(reply)=6 then  exit 
    !CORRECT LENGTH TSN.
  repeat 
  tape cycle==array(r_conad+x'720', af tape cycle)
  if  tape count=0 start 
    !THERE ARE NO TAPES ON CYCLE AT THE MOMENT.
    tape cycle(1)_tsn<-reply
    tape cycle(1)_age=0
    tape count=1
  finish  else  start 
    !THERE ARE TAPES ALREADY IN THE CYCLE.
    for  i=1, 1, tape count cycle 
      !CHECK TAPE NOT ALREADY THERE.
      if  tape cycle(i)_tsn=reply start 
        printstring(jtxt.reply." already in cycle")
        newlines(2)
        return 
      finish 
    repeat 
    for  i=1, 1, 100 cycle 
      !NOW SLOT IN THE NEW TAPE.
      if  tape cycle (i)_tsn="" start 
        !WE HAVE FOUND EMPTY SLOT.
        tape cycle(i)_tsn<-reply
        tape cycle(i)_age=0;  !UNUSED.
        tape count=tape count+1
        exit 
      finish 
    repeat 
  finish 
  printstring(jtxt.reply." added to cycle with new total of ")
  write(tape count, 2)
  printstring(" tapes.")
  newlines(2)
  disconnect(control, flag)
  end ;  !OF NEW JOURNAL TAPE.

! ************************************************************************
! ************************************************************************
! ************************************************************************
  externalroutine  remove journal index(string (255) s)
  record (f index list)arrayformat  af index list(0:total indices)
  record (f index list)arrayname  index list
  record  (rf)r
  string (16) reply
  byteinteger  id char, data type
  integer  flag, entry
  cycle 
    !FIND THE IDENTITY OF THE INDEX TO BE REMOVED.
    prompt("INDEX KEYWORD:")
    read prompt reply(reply)
    exit  if  0<length(reply)<=12
    printstring(jtxt.reply." too long??")
    newlines(2)
  repeat 
  identify index(reply, id char, data type, entry)
  if  id char=100 start 
    printstring(jtxt.reply." not valid keyword")
    newlines(2)
    return 
  finish 
  connect(control, 3, 0, 0, r, flag)
  if  flag#0 then  master file failure(control, flag)
  index list==array(r_conad+x'30', af index list)
  index list(entry)_identity=""
  !THE INDEX ENTRY IS REMOVED.
  destroy("JJ#".intostr(id char)."DEX", flag)
  disconnect(control, flag)
  printstring(jtxt."Index removed.")
  newlines(2)
  end ;  !OF REMOVE JOURNAL INDEX

! *****************************************************************************
! *****************************************************************************
! *****************************************************************************
  externalroutine  journal backpass(string (255) s)
  externalintegerfnspec  dsetpassword(string (6) user, integer  fsys, which,
                                      string (63) old, new)
  string (63) forepass, backpass
  record  (rf) r
  integer  i, flag
  connect(control, 3, 0, 0, r, flag)
  if  flag#0 start 
     printstring("Unable to connect ".control)
     newline
     return 
  finish 
  printstring("Background password currently stored by Journal: ".c 
    string(r_conad+x'27D0'))
  newline
  printstring("If this is satisfactory, exit by replying '*' to the first prompt.")
  newlines(2)
  printstring("Give current foreground password, then new background password.")
  newline
  for  i = 1,1,3 cycle 
      prompt("Foreground:")
      read prompt reply(fore pass)
      flag = 1 and  exit  if  fore pass="*"
      prompt("New back:")
      read prompt reply(back pass)
      if  length(back pass)>11 start 
         printstring("**Warning: reduced to first 11 characters.")
         newline
         length(back pass) = 11
      finish 
      flag = dsetpassword("JOURNL",-1,1,fore pass, back pass)
      exit  if  flag=0
      printstring("Failed!!  You get 3 tries.  That was try no.")
      write(i,1); newline
  repeat 
  if  flag#0 start 
     printstring("Background password unchanged.")
  finishelsestart 
     string(r_conad+x'27D0') = back pass
     printstring("New background password now in use.")
  finish 
  newline
  end ; ! Of %external %routine journal backpass.

!**************************************************************************
!          ROUTINES AND FUNCTIONS COMMON TO THE SYSTEM.
!**************************************************************************

  routine  identify index(string (*)name  keyword, byteintegername   c 
          id char, data type, integername  entry)
  !HERE WE ARE GIVEN AN INDEX IDENTITY KEYWORD IE 'ERRORLOG' AND
  !WE SEARCH TO SEE IF IT IS VALID, IF IT IS WE PASS BACK THE
  !IDENTITY OF THE INDEX IN THE RANGE '0' TO '99' WHICH DEFINES THE
  !INDEX IE JJ'8'DEX ELSE WE PASS BACK A DEFAULT FAIL VALUE OF -1.
  record (f index list)arrayformat  af index list(0:total indices)
  record (f index list)arrayname  index list
  record  (rf)r
  string (16) file
  integer  i, flag
  file="JJMASTER"
  connect(file, 0, 0, 0, r, flag)
  if  flag#0 then  master file failure(file, flag)
  index list==array(r_conad+x'30', af index list)
  for  i=0, 1, total indices cycle 
    if  index list(i)_identity=keyword start 
      id char=index list(i)_id char
      data type=index list(i)_data type
      entry=i
      return 
    finish 
  repeat 
  id char=100;  !IE FAILED TO FIND MATCHING KEYWORD.
  end ;  !OF IDENTIFY INDEX.

  routine  line to atoms(integername  word count,
         stringarrayname  atoms, byteintegerarrayname  buff)
  !HERE WE READ A LINE OF THE FILE INTO AN ARRAY OF "ATOMS" PASSING
  !BACK THE RESULTING WORDS(WORD COUNT  DEFINING THE NUMBER OF WORDS)
  !IN THE ARRAY ATOM.
  integer  adn
  byteinteger  ch, i
  word count=0; endflag=0; i=0
  cycle 
    chpointer=chpointer+1
    if  chpointer>flen then  endflag=1 and  return 
    ch=buff(chpointer)
    exit  if  ch>32
  repeat 
  cycle 
    if  ch=32 or  ch=10 start 
      if  i>0 then  byteinteger(adn)=i and  i=0
      return  if  ch=10
    finish  else  start 
      if  32<ch<128 start 
        if  i=0 start 
          word count=word count+1 unless  word count=68
          adn=addr(atoms(word count))
        finish 
        i=i&x'7F'+1
        !LENGTH OF ATOM SHOULD NOT EXCEED 127, SET TO 1 IF OCCURS!!
        byteinteger(adn+i)=ch
      finish 
    finish 
    chpointer=chpointer+1
    if  chpointer>flen then  endflag=1 and  ch=10 c 
    else  ch=buff(chpointer)
  repeat 
  end ;  !OF LINE TO ATOMS.

routine  master file failure(string (*)name  file, integer  flag)
  !HERE WE PRINT THE WARNING OF A FAILURE(MISSING) MASTER FILE
  !AND STOP THE SYSTEM.
  printstring(jtxt.file." lost, major fault.  Flag: ")
  write(flag, 2)
  newlines(2)
  stop 
end ;  !OF JJMASTER FAILURE.
endoffile