!REGION: procedures for accessing parts (regions) of files

%include "inc:util.imp"
%include "inc:fs.imp"

%bytemap put(%integer k,%bytename b)
  b = k; %result == b[1]
%end

%byteintegermap putnum(%integer n,%bytename b)
  b == putnum(n>>4,b) %and n = n&15 %if n>=64
  %result == put(n+'0',b)
%end

%routine add(%integer x,%string(*)%name s)
  s = s.tostring(x)
%end

%routine addnum(%integer x,%string(*)%name s)
  addnum(x>>4,s) %and x = x&15 %if x>=64
  add(x+'0',s)
%end

%byteintegermap num(%bytename b,%integername x)
%integer k
  x = 0
  %cycle
    k = b-'0'; b == b[1]
    %result == b %if k<0
    x = x<<4+k
  %repeat
%end

%routine move(%integer bytes,%bytename from,to)
  *sub.l #1,d0
  *swap d0
a:*swap d0
b:*move.b (a0)+,(a1)+
  *dbra d0,b
  *swap d0
  *dbra d0,a
%end

! ACCESS FILE
! Opens the file and returns in SIZE the number of bytes in the file,
! and in REF a token (actually the filestore transaction number) which
! must be passed to DEACCESS FILE, READ REGION, and WRITE REGION.
! MODE=0: Read-only, MODE=1: Read-modify.

%externalroutine access file(%string(255)filename,%integer mode,
                             %integername ref,size)
%string(255)s=""
%integer blocks
%bytename b
  mode = 'A'-'S' %unless mode=0
  add(mode+'S',s); add(userno+'0',s); s = s.filename; add(nl,s)
  b == charno(s,1)
  etherwrite(lsap,b,length(s))
  length(s) = etherread(lsap,b,255)
  %signal 3,3,b[1]-'0',substring(s,3,length(s)-1) %if b='-'
  b == num(b,ref)
  b == num(b,blocks)
  b == num(b,size)
  size = blocks<<9-size
%end

! DEACCESS FILE
! Just closes the file

%externalroutine deaccess file(%integer ref)
%string(255)s=""
%bytename b
  add('K',s); add(ref+'0',s); add(nl,s)
  b == charno(s,1)
  etherwrite(lsap,b,length(s))
  length(s) = etherread(lsap,b,255)
%end

! READ REGION
! Reads BYTES bytes from the file specified by REF into store at BUFFER,
! starting with byte BYTE of the file (BYTE=0 means beginning of file).

%externalroutine read region(%integer ref,byte,bytes,%bytename buffer)
%string(31)s=""
%bytearray temp(1:516)
%bytename b,p
%integer lo,hi,i,count
  %returnif bytes<=0
  b == temp(1)
  lo = byte>>9; hi = (byte+bytes-1)>>9
  add('U',s); add(ref+'0',s); addnum(lo,s); add(nl,s); !Set to required block
  etherwrite(lsap,charno(s,1),length(s))
  i = etherread(lsap,b,515)
  ->shit %if b='-'
  s = ""
  add('X',s); add(ref+'0',s)
  addnum(hi-lo+1,s);   !Multi-block read!
  add(nl,s)
  etherwrite(lsap,charno(s,1),length(s))
  count = 512-byte&511
  p == b[byte&511+3]
  %cycle
    i = etherread(lsap,b,515)
    %if b='-' %start
shit: lo = b[1]-'0'; b[1] = i-3
      %signal 3,4,lo,string(addr(b)+1)
    %finish
    count = bytes %if bytes<count
    move(count,p,buffer)
    buffer == buffer[count]
    bytes = bytes-count
    count = 512; p == b[3]
    %exitunless i=515
    lo = lo+1
  %repeatuntil lo>hi
  %signal 3,4,0,"Read region: internal error" %unless lo>=hi %and bytes<=0
%end

%externalroutine write region(%integer ref,byte,bytes,%bytename buffer)
%bytearray temp(1:532)
%integer count,block,i
%bytename b,b0
  b0 == temp(1)
  count = 512; count = bytes %if bytes<count
  block = byte>>9
  b == put('W',b0)
  b == put(ref+'0',b)
  b == putnum(block,b)
  b == put(',',b)
  b == putnum(count,b)
  b == put(nl,b)
  %if byte&511#0 %start; !First block not aligned
    readregion(ref,block<<9,512,b)
    count = count-byte&511
    move(count,buffer,b[byte&511])
    bytes = bytes+byte&511
  %else
    move(count,buffer,b)
  %finish
  %cycle
    etherwrite(lsap,temp(1),addr(b)-addr(b0)+count)
    i = etherread(lsap,b0,255)
    %if b0='-' %start
      count = b0[1]-'0'; b0[1] = i-3
      %signal 3,4,count,string(addr(b0)+1)
    %finish
    buffer == buffer[count]
    bytes = bytes-count
    %exitif bytes<=0
    count = 512; count = bytes %if bytes<count
    block = block+1
    b == put('W',b0)
    b == put(ref+'0',b)
    b == putnum(block,b)
    b == put(',',b)
    b == putnum(count,b)
    b == put(nl,b)
    move(count,buffer,b)
  %repeat
%end

%end
