{ Extracted from FMACS:LIB }

{ Open Update, Close update, Flush Output  -  FDC, 12.2.85 }

{ Notes to rippers-off:                                              }
{  These routines allow a primitive form of update mode.             }
{  OPEN UPDATE opens an existing file for update, and CLOSE UPDATE   }
{  closes it again.  Both an input stream and an output stream are   }
{  associated with the file.  Use set input to position to a block   }
{  (512 byte) boundary, then read 512 bytes, change what you want,   }
{  set output back to the beginning of the block and write it back   }
{  again.  Anything else is likely to give a 'protocol error',       }
{  though if you want to replace a block entirely you don't have to  }
{  read it first, and the last block in the file does not have to be }
{  a full 512 bytes long.                                            }

@16_1108 %integerfn FCOMM(%integer cn,%string(255)s)
@16_110C %integerfn FCOMMW(%integer cn,%string(255) s,
               %bytename buffer,%integer size)
@16_1110 %integerfn FCOMMR(%integer c,%string(255)p,
                               %bytename b,%integer max)
@16_35c4 %short      USERNO
@16_372d %byte       FSPORT
@16_1100 %routine    ETHERWRITE(%integer port,%bytename buf,%integer size)
@16_1104 %integerfn  ETHERREAD(%integer port,%bytename buf,%integer max)
%recordformat sf(%integer ptr,lim,server,extra)
@16_35c6 %record(sf)%name curin
@16_35ca %record(sf)%name curout

%integerfn fromhdh(%integername pos,%integer lim)
%integer n=0,k
   %cycle
      %result = n %if pos>=lim
      pos = pos+1
      k = byteinteger(pos-1)-'0'
      %result = n %if k<0
      n = n<<4+k
   %repeat
%end

{---------- OPEN UPDATE ----------}
%external %integer %function open update(%integer stream,%string(255)file)
! Open the specified file for input and output on the specified stream.
! The file must already exist.
! The file is initially positioned at the beginning.
! Result is the size of the information in the file already.
!
! It is up to the user to read and write full (512 byte) blocks only.
! Always read a block before writing it back.
!
%string(255)s
%record(sf)%name cb
%integer pos,lim,xno,blocks,pad,size
! Open anything for output first - to get file driver addr into CB
   %begin
      %on %event 3 %start
         %signal 10, 9, 99, "Cannot create file in PUB:"
      %finish

      openoutput(stream,"pub:")
   %end
   selectoutput(stream)
   cb == curout
   xno = cb_extra
! Close it again - but don't use CLOSEOUTPUT as this will zap the driver
   cb_extra = 0
   s = "K".tostring(xno+'0').tostring(nl)
   etherwrite(fsport,charno(s,1),length(s))
   length(s) = etherread(fsport,charno(s,1),255)
! Open anything for input - to get file driver addr into CB
   openinput(stream,"directory")
   selectinput(stream)
   cb == curin
   xno = cb_extra
! Close it again - but don't use CLOSEOUTPUT as this will zap the driver
   cb_extra = 0
   s = "K".tostring(xno+'0').tostring(nl)
   etherwrite(fsport,charno(s,1),length(s))
   length(s) = etherread(fsport,charno(s,1),255)
! Now open-mod the file we want
   s = "A".tostring(userno+'0').file.tostring(nl)
   etherwrite(fsport,charno(s,1),length(s))
   length(s) = etherread(fsport,charno(s,1),255)
   %if charno(s,1)='-' %start;      !failed to open
      %signal 3,3,charno(s,2)-'0',substring(s,3,length(s)-1)
   %finish
   pos = addr(s)+1
   lim = pos+length(s)
   xno = fromhdh(pos,lim)
   blocks = fromhdh(pos,lim)
   pad = fromhdh(pos,lim)
   curin_extra = xno
   curout_extra = xno
   size = blocks<<9-pad
   reset output
   reset input
   %result = size
%end

{---------- CLOSE UPDATE ----------}
%external %routine close update
   close output
   curin_extra = 0
   close input
%end

{---------- FLUSH OUTPUT ----------}
%external %routine flush output
   %integer len

   len = curout_ptr - curout_lim + 512
   curout_ptr = curout_lim - 512
   %if len # 0 %start
      len = fcommw('Y0' + curout_extra, "", byteinteger(curout_ptr), {len}512)
{-------------- temporary hack because file store won't truncate right ---^^^}
   %finish
%end

{---------- ABANDON OUTPUT ----------}
%external %routine abandon output
   %integer junk

   junk = fcomm('H0' + curout_extra, "")
   curout_ptr = curout_lim - 512
   curout_extra = 0
%end

%endoffile
