!***********************************************************************
!*
!*                     Program to read VME/B tapes
!*
!*     Copyright (C)   R.D. Eager   University of Kent   MCMLXXXIII
!*
!***********************************************************************
!
!
!***********************************************************************
!*
!*          Constants
!*
!***********************************************************************
!
constantinteger  no = 0, yes = 1
constantinteger  channel = 1
constantinteger  nullstream = 80
constantinteger  blocksize = 4116
constantinteger  ssdatafiletype = 4
constantinteger  sspdfiletype = 6
constantstring (1) snl = "
"
!
!
!***********************************************************************
!*
!*          Record formats
!*
!***********************************************************************
!
recordformat  hf(integer  dataend,datastart,filesize,filetype,
                 sum,datetime,format,records)
recordformat  rf(integer  conad,filetype,datastart,dataend)
!
!
!***********************************************************************
!*
!*          Subsystem references
!*
!***********************************************************************
!
systemroutinespec  connect(string (31) file,integer  mode,hole,
                           prot,record (rf)name  r,integername  flag)
systemroutinespec  define(integer  chan,string (31) iden,
                          integername  afd,flag)
systemroutinespec  destroy(string (31) file,integername  flag)
systemroutinespec  disconnect(string (31) file,integername  flag)
systemroutinespec  etoi(integer  ad,l)
systemstringfunctionspec  failuremessage(integer  mess)
externalstringfunctionspec  interrupt
systemstringfunctionspec  itos(integer  n)
systemroutinespec  modpdfile(integer  ep,string (31) pdfile,
                             string (11) member,string (31) infile,
                             integername  flag)
systemroutinespec  move(integer  length,from,to)
systemroutinespec  newgen(string (31) file,newfile,integername  flag)
systemstringfunctionspec  nexttemp
systemroutinespec  outfile(string (31) file,integer  size,hole,
                           prot,integername  conad,flag)
systemintegerfunctionspec  parmap
externalroutinespec  prompt(string (255) s)
systemintegerfunctionspec  pstoi(string (63) s)
systemroutinespec  rename(string (31) file,newfile,integername  flag)
systemroutinespec  setfname(string (63) s)
systemroutinespec  setpar(string (255) s)
externalroutinespec  set return code(integer  i)
systemstringfunctionspec  spar(integer  n)
externalroutinespec  ssfoff
systemroutinespec  trim(string (31) file,integername  flag)
systemroutinespec  uctranslate(integer  ad,len)
externalintegerfunctionspec  uinfi(integer  entry)
!
externalroutinespec  clear(string (255) s)
externalroutinespec  convert(string (255) s)
!
!
!***********************************************************************
!*
!*          References to magnetic tape interface routines
!*
!***********************************************************************
!
externalroutinespec  askmag(integer  channel,string (7) vol,
                            integername  flag)
externalroutinespec  readmag(integer  channel,ad,integername  len,flag)
externalroutinespec  skipmag(integer  channel,n)
externalroutinespec  skiptmmag(integer  channel,n)
externalroutinespec  rewindmag(integer  channel)
externalroutinespec  unloadmag(integer  channel)
!
!
!***********************************************************************
!*
!*          Service routines
!*
!***********************************************************************
!
string (255)function  specmessage(integer  flag)
string (255) s
switch  sw(1000:1007)
!
-> sw(flag)
!
sw(1000):  s = "Catastrophic failure"; -> out
sw(1001):  s = "Failed to claim tape"; -> out
sw(1002):  s = "Tape read error"; -> out
sw(1003):  s = "No HDR1 where expected"; -> out
sw(1004):  s = "Unexpected tape mark"; -> out
sw(1005):  s = "No tape mark where expected"; -> out
sw(1006):  s = "Invalid number"; -> out
sw(1007):  s = "Invalid reply"; -> out
!
out:
result  = " ".s.snl
end ;   ! of specmessage
!
!-----------------------------------------------------------------------
!
routine  fail(integer  flag)
printstring(snl."READBTAPE fails -")
if  flag < 1000 then  start 
   printstring(failuremessage(flag))
else 
   printstring(specmessage(flag))
finish 
ssfoff
clear(itos(nullstream))
set return code(flag)
stop 
end ;   ! of fail
!
!-----------------------------------------------------------------------
!
routine  readline(stringname  s)
integer  c
!
s = ""
cycle 
   cycle 
      readsymbol(c)
      exit  if  c = nl
      s <- s.tostring(c)
   repeat 
   while  length(s) > 0 and  charno(s,length(s)) = ' ' cycle 
      length(s) = length(s) - 1
   repeat 
   exit  unless  s = ""
repeat 
uctranslate(addr(s)+1,length(s))
end ;   ! of readline
!
!-----------------------------------------------------------------------
!
routine  newpd(stringname  pdfile,integername  max)
integer  flag
string (15) s
record  (rf)rr
!
cycle 
   if  pdfile = "" then  start 
      prompt("Pdfile name: ")
      readline(pdfile)
   finish 
   !
   connect(pdfile,1,0,0,rr,flag)
   if  flag = 218 then  start ;         ! Pdfile does not exist - create it
      modpdfile(4,pdfile,"","",flag)
      if  flag = 0 then  start 
         connect(pdfile,1,0,0,rr,flag)
         printstring("Creating ".pdfile.snl)
      finish 
   finish 
   if  flag = 0 and  rr_filetype # sspdfiletype then  start 
      setfname(pdfile)
      flag = 267;                       ! Invalid filetype
   finish 
   if  flag # 0 then  start 
      if  uinfi(2) # 1 then  start ;    ! Not interactive
         fail(flag)
      finish 
      printstring(failuremessage(flag))
      pdfile = ""
   finish  else  exit 
repeat 
!
prompt("Max members? ")
cycle 
   readline(s)
   max = pstoi(s)
   if  max <= 0 then  start ;           ! Number not valid
      if  uinfi(2) # 1 then  fail(1006);! Not interactive
      printstring("Invalid number".snl)
   finish  else  exit 
repeat 
!
end ;   ! of newpd
!
!-----------------------------------------------------------------------
!
integerfunction  checkstop
string (15) s
!
s = interrupt
uctranslate(addr(s)+1,length(s))
if  s # "STOP" then  result  = no
printstring("Stop requested".snl)
result  = yes
end ;   ! of checkstop
!
!
!***********************************************************************
!*
!*          R E A D B T A P E
!*
!***********************************************************************
!
externalroutine  readbtape(string (255) parms)
integer  flag,ad,maxfsize,conad,i,pd,converting,searching,pdindex,ptr
integer  fileno,len,cdisp,lastdisp,rlen,max,blocks,pdmaxindex,mt claimed
integer  afd
string (6) tape
string (10) tempfile,tempfile2,searchfile,ffile
string (11) pdfile,member
string (16) tapefile
string (31) file
string (255) s
record (hf)name  r
byteintegerarray  b(0:blocksize-1)
!
s = interrupt;                          ! Clear any outstanding one
mt claimed = no
maxfsize = (uinfi(6)+1)*1024
pdfile = ""
pd = no
searching = no
converting = no
pdindex = 0
fileno = 0
!
setpar(parms)
if  parmap & 1 = 0 or  parmap > 7 then  start 
   flag = 263;                          ! Wrong number of parameters
   -> err
finish 
tape <- spar(1)
if  parmap & 2 # 0 then  start 
   searching = yes
   searchfile = spar(2)
finish 
if  parmap & 4 # 0 then  start 
   pd = yes
   pdfile = spar(3)
finish 
tempfile = "T#".nexttemp
tempfile2 = "T#".nexttemp
define(nullstream,".NULL",afd,flag)
!
askmag(channel,tape,flag)
if  flag # 0 then  start 
   flag = 1001;                         ! Failed to claim tape
   -> err
finish 
mt claimed = yes
rewindmag(channel)
skipmag(channel,1);                     ! Skip over label
!
if  pd = yes then  newpd(pdfile,pdmaxindex)
!
prompt("Source convert? ")
cycle 
   readline(s)
   i = charno(s,1)
   exit  if  i = 'Y' or  i = 'N'
   if  uinfi(2) # 1 then  start ;       ! Not interactive
      fail(1007);                       ! Invalid reply
   finish 
repeat 
if  i = 'Y' then  converting = yes else  converting = no
ad = addr(b(0))
!
cycle ;                                 ! Main loop
   len = 96
   readmag(channel,ad,len,flag);        ! The HDR1 label
   if  flag = 1 then  start 
      printstring("End of tape".snl)
      exit 
   finish 
   if  flag # 0 then  start 
      flag = 1002;                      ! Tape read error
      -> err
   finish 
   move(4,addr(b(6)),addr(i))
   if  i # c'HDR1' then  start 
      flag = 1003;                      ! No HDR1 where expected
      -> err
   finish 
   fileno = fileno + 1
   etoi(addr(b(10)),16);                ! File name
   b(9) = 16
   tapefile = string(addr(b(9)))
   while  charno(tapefile,length(tapefile)) = ' ' cycle 
      length(tapefile) = length(tapefile) - 1
   repeat 
   if  searching = no = pd then  start 
      printstring("File ".itos(fileno)." ".tapefile.snl)
   finish 
   if  searching = yes then  start 
      if  searchfile = tapefile then  start 
         printstring(snl.searchfile." found at file ".itos(fileno))
         newline
         if  pdfile # "" then  start 
            printstring(snl."Filling ".pdfile." from file ")
            printstring(itos(fileno)." onwards".snl)
            searching = no
         finish 
      else 
         skiptmmag(channel,3)
         exit  if  checkstop = yes
         continue 
      finish 
   finish 
   !
   ! Get past HDR2,UHL,TM
   !
   for  i = 1,1,3 cycle 
      readmag(channel,ad,len,flag)
      if  flag = 1 and  i < 3 then  start 
         flag = 1004;                   ! Unexpected tapemark
         -> err
      finish 
   repeat 
   if  flag # 1 then  start 
      flag = 1005;                      ! No tape mark where expected
      -> err
   finish 
   !
   len = 96
   if  pd = no then  start 
      exit  if  checkstop = yes
      prompt("EMASfilename: ")
      readline(file)
      if  file = "" then  start 
         skiptmmag(channel,2)
         continue 
      finish 
      if  file = ".END" then  start 
         printstring(snl."Stop".snl)
         exit 
      finish 
   finish 
   outfile(tempfile,maxfsize,0,0,conad,flag)
   -> err if  flag # 0
   r == record(conad)
   r_filetype = ssdatafiletype
   r_format = (4096<<16)!x'22';         ! E V4096
   r_records = 0
   ptr = r_datastart
   max = r_filesize
   !
   blocks = 0
   cycle 
      len = blocksize
      readmag(channel,ad,len,flag)
      exit  if  flag = 1
      blocks = blocks + 1
      if  flag # 0 then  start 
         flag = 1002;                   ! Tape read error
         -> err
      finish 
      lastdisp = b(6)<<8+b(7)+6
      cdisp = 8
      cycle 
         rlen = b(cdisp)<<8 + b(cdisp + 1) - 4
         exit  if  rlen < 0
         if  ptr + rlen + 2 > max then  start 
            printstring("File ".tapefile." is too large".snl)
            skiptmmag(channel,2)
            -> loop
         finish 
         i = rlen + 2
         move(2,addr(i)+2,conad+ptr)
         move(rlen,addr(b(cdisp+4)),conad+ptr+2)
         ptr = ptr + rlen + 2
         r_records = r_records + 1
         r_dataend = ptr
         cdisp = cdisp + rlen + 4
      repeat  until  cdisp > lastdisp
   repeat 
   !
   trim(tempfile,flag)
   if  converting = yes then  start 
      selectoutput(nullstream)
      convert(tempfile.",".tempfile2)
      selectoutput(0)
      ffile = tempfile2
   finish  else  ffile = tempfile
   printstring(tapefile." - ".itos(blocks)." block")
   if  blocks # 1 then  printsymbol('s')
   printstring(" read".snl.snl)
   length(tapefile) = 11 if  length(tapefile) > 11
   if  pd = yes then  start 
      modpdfile(2,pdfile,tapefile,"",flag)
                                        ! Delete any existing member
      modpdfile(1,pdfile,tapefile,ffile,flag)
                                        ! Insert member
      if  flag = 280 then  start ;      ! User individual file limit exceeded
         printstring("Pdfile ".pdfile." is full".snl)
         disconnect(pdfile,flag)
         pdfile = ""
         newpd(pdfile,pdmaxindex)
         modpdfile(2,pdfile,tapefile,"",flag)
                                        ! Delete any existing member
         modpdfile(1,pdfile,tapefile,ffile,flag)
      finish 
      -> err if  flag # 0
   else 
      if  file -> file.("_").member then  start 
         modpdfile(2,file,member,"",flag)
                                        ! Delete any existing member
         modpdfile(1,file,member,ffile,flag)
      else 
         rename(ffile,file,flag)
         if  flag = 219 then  newgen(ffile,file,flag)
      finish 
      -> err if  flag # 0
   finish 
   skiptmmag(channel,1);                ! Skip to next file
   if  pd = yes then  start 
      pdindex = pdindex + 1
      if  pdindex >= pdmaxindex then  start 
         printstring("Max number of files read into ".pdfile.snl)
         pdfile = ""
         newpd(pdfile,pdmaxindex)
         pdindex = 0
      finish 
   finish 
   !
   if  searching = yes then  start 
      printstring("File found".snl)
      exit 
   finish 
   !
   exit  if  checkstop = yes
   !
loop:
repeat 
!
unloadmag(channel)
if  pd = yes then  disconnect(pdfile,flag)
destroy(tempfile,flag)
destroy(tempfile2,flag)
ssfoff
clear(itos(nullstream))
set return code(0)
stop 
!
err:
unloadmag(channel) if  mt claimed = yes
fail(flag)
end ;   ! of readbtape
endoffile