! Filestore Module

option  "-low-nocheck-nodiag-noline-nostack"
include  "moose:mouse.inc"
Include  "sys:ether.inc"
Include  "fsconsts.inc"

recordformat  fsreqfm(record (messagefm) msg,
                      Integerarray  i(1:4))

systemintegerfnspec  stoi (String (*) s)

RecordFormat  ownerfm (Integer  uno, Record (ownerfm)name  next)

constinteger  buffersize = 512

Ownrecord (ownerfm)name  owner list

ownrecord (fsreqfm)name  rep   ;! Belong to FS Process
ownrecord (mailboxfm)name  ombox ;!   "     "      "

ownrecord (fsreqfm)   req
ownrecord (mailboxfm)   imbox
Ownrecord (semaphorefm) sem

Ownstring (255) errmess=""

owninteger  initialised = 0

Routine  Transact
   Integer  i

   req_i(2) = addr(errmess)
   send message (req, ombox, imbox)
   rep == receive message (imbox)
   i = rep_i(1)
   Signal  3,i,0,errmess If  i # fs success
End 

integerfn  Translate Addr (String (*)name  s)
   integer  lives = 9

   on  4 start 
      Signal  3,0,0,"Bad filestore name"
   Finish 
         
   Cycle 
      lives = lives - 1
   Repeatuntil  not  translatelogicalname (s) or  lives = 0
   Signal  3,0,0,"Translation looping" if  lives = 0
   result  = stoi (s)
End 

Routine  Split Filename (String (*)name  infile, outfile, fsaddr,
                         Integername  fsrdte)
   unless  split(infile,nil,outfile) Start ; Finish 
   Unless  split(outfile,nil,outfile) start ; finish 
   fsaddr = "FS_DEFAULT" unless  outfile -> fsaddr.("::").outfile
   fsrdte = translate addr (fsaddr)
End 
   
routine  initialise
   Integer  bytes,i,t

   return  unless  initialised = 0
   setup semaphore (sem)
   setup mailbox (imbox, sem)
   setup message (req, sizeof(req))

   t = Find Entry ("FS_REQUESTS", poa_logdict)
   Signal  3,0,0,"Failed to find FS_REQUESTS" if  t =0 
   ombox == record(integer(t))

   ownerlist==nil
   initialised = 1
End 

integerfn  Determine Uno (integer  rdte)
   record (ownerfm)name  own

   own == ownerlist
   while  own ## NIL cycle 
!      putstring("=>");putlong(own_uno)
      Result  = own_uno if  own_uno>>8 = rdte
      own == own_next
   repeat 
   Result  = rdte<<8
End 

ExternalRoutine  Logon To Filestore (String (127) fsaddr,user,password)
   Integer  rdte
   Record (ownerfm)name  own,p==NIL,no
   Record (passfm) pass=0

   signal  3,4,0,"Invalid username" If  user=""
   fsaddr="FS_DEFAULT" if  fsaddr=""
   rdte = translate addr (fsaddr)

   own == owner list
   While  own ## NIL cycle 
      Signal  3,4,0,"Still logged onto filestore" If  own_uno>>8=rdte
      p==own; own==own_next
   Repeat 

   pass_owner=user; pass_password=password
   req_i(1) = fs logon
   req_i(3) = rdte
   req_i(4) = addr(pass)
   transact
   no == new(no) ; no=0
   no_next == NIL
   no_uno = rep_i(2)
   if  owner list == NIL start   
      owner list == no
   Else 
      p_next == no
   Finish 
End 

Routine  Access File (Integer  uno, String (255) s, integer  mode,
                      integername  token, size)

   !putstring("*AF*")
   if  mode = input mode start 
      !putstring("Access file")
      req_i(1) = fs open file
      req_i(3) = uno
      req_i(4) = addr(s)
      transact
      !putstring("Fs spoke");
      token = rep_i(2)
      size  = rep_i(3)
      !putstring("File opened. Token = ");putlong(rep_i(2));putsym(10)
   Else 
!      putstring("Create file")
      size = 0
      req_i(1) = fs create file
      req_i(3) = uno
      req_i(4) = addr(s)
      transact
      token = rep_i(2)
   Finish 
End  

Routine  Deaccessfile (integer  token)
   req_i(1) = fs close file
   req_i(3) = token
   transact
   !! putstring("File deaccessed");putsym(10)
End 

Integerfn  Read Block (integer  token, position, amount, bytename  buf)
   Record (blockfm) bl
      
   bl_token  = token
   bl_amount = amount
   bl_buffer = addr(buf)
   bl_position = position

   req_i(1) = fs read file
   req_i(3) = addr(bl)
   transact
   !!Putstring("Read Block completed");putsym(10)
   Result  = rep_i(2)
End 

Integerfn  Write Block (Integer  token, position, amount, bytename  buf)
   Record (blockfm) bl

   bl_token  = token
   bl_position = position
   bl_amount = amount
   bl_buffer = addr(buf)

   req_i(1) = fs write file
   req_i(3) = addr(bl)
   transact
   result  = rep_i(2)
End 

externalrecord (scb fm)map  xopen alias  "r_open" -
  (integer  mode, string (255)file)
record (scb fm)name  scb
integer  x,fsrdte,uno
string (127) fsaddr

  routine  refresh(record (scb fm)name  scb)
  integer  amount,diff{,offset,pos}
    signal  9,,,"End of file" if  scb_p>=scb_fl
{   offset = rem(scb_p-scb_fs,scb_bl-scb_bs)}
{   pos = scb_p-offset; dif = scb_bs-pos}
    diff = scb_bs-scb_p+rem(scb_p-scb_fs,scb_bl-scb_bs)
    scb_fs = scb_fs+diff
    scb_fl = scb_fl+diff
    scb_p = scb_p+diff
    amount = scb_fl-scb_bs                    {rest of file}
    amount = scb_bl-scb_bs if  scb_fl>scb_bl  {if it fits}
    scb_l = scb_p+readblock(scb_b,scb_p-scb_fs,amount,byteinteger(scb_p))
  end 

  routine  flush(record (scb fm)name  scb,integer  sym)
  integer  dump
    scb_fl = scb_p if  scb_p>scb_fl
    scb_p = scb_bl if  scb_p<scb_fl
    dump = writeblock(scb_b,scb_bs-scb_fs,scb_p-scb_bs,byteinteger(scb_bs))
    if  scb_p=scb_bl start 
      scb_fs = scb_fs-buffersize; scb_fl = scb_fl-buffersize
    finish 
    scb_p = scb_bs; scb_l = scb_bl
    byteinteger(scb_p) = sym and  scb_p = scb_p+1 unless  sym<0
  end 

  routine  closin(record (scb fm)name  scb)
  integer  x
    x = scb_b; scb_b = 0
    heapput(scb_a) unless  scb_a=0
    deaccessfile(x)
    heapput(scb_bs); scb_bs = 0
    !!putstring("File closed");putsym(10)
  end 

  routine  closout(record (scb fm)name  scb,integer  mode)
  integer  x
    flush(scb,-1)
    x = scb_b; scb_b = 0
    deaccessfile(x) ;!%if mode=0 {??}
    heapput(scb_bs); scb_bs = 0
  end 

  routine  setin(record (scb fm)name  scb,integer  pos)
    scb_p = scb_fs+pos
    scb_l = scb_p unless  scb_bs<=scb_p<=scb_l
  end 

  routine  setout(record (scb fm)name  scb,integer  pos)
    flush(scb,-1) unless  scb_p=scb_bs
    signal  2,,,"writing off end of file" if  scb_fs+pos-scb_fl>0
    scb_p = scb_fs+pos
    refresh(scb)
    scb_p = scb_fs+pos
    scb_l = scb_bl
  end 

  routine  service(record (scb fm)name  scb,integer  op,parm)
  switch  sw(0:7)
    returnif  scb_b=0
    ->sw(op&7)
sw(serclosin):  closin(scb);      return 
sw(serclosout): closout(scb,0);   return 
sw(serprompt):                    return 
sw(serdropout): closout(scb,1);   return 
sw(sersetin):   setin(scb,parm);  return 
sw(sersetout):  setout(scb,parm); return 
sw(serrefresh): refresh(scb);     return 
sw(serflush):   flush(scb,parm)
  end 

   !!putstring("Filename=");putstring(file);putsym(10)
   !!putstring ("FS Open file, gla = ");putlong(a4);putsym(10)
   initialise if  initialised = 0
   scb == new scb(file)
   unless  split(scb_filename,nil,file) start ; finish 
   unless  split(file,nil,file) start ; finish 
   fsaddr = "FS_DEFAULT" unless  file -> fsaddr.("::").file
   fs rdte = translate addr (fsaddr)
   uno = determine uno (fs rdte)

   scb_mode = mode
   scb_gla = a4
   *lea service,a0; *move.l a0,x
   scb_serpc = x
   if  mode=inputmode start 
      *lea refresh,a0; *move.l a0,x
      scb_fastpc = x
      accessfile(uno,file,inputmode,scb_b,scb_fl)
   else 
      *lea flush,a0; *move.l a0,x
      scb_fastpc = x
      accessfile(uno,file,outputmode,scb_b,scb_fl)
      scb_fl = 0
   finish 
   scb_bs = heapget(buffersize)
   scb_bl = scb_bs+buffersize
   scb_fs = scb_bs
   scb_fl = scb_bs+scb_fl
   scb_p = scb_bs
   scb_l = scb_bl
   scb_l = scb_bs if  mode=inputmode
   result  == scb
end