{EASYBUFF.PAS ----Easy buffered text output for CP/M Turbo Pascal v.2.00
 By Benjamin Ho
 Evanston, IL
 4/11/86

 Did you ever try to process a text file using this traditional,
 straightforward method of text processing ?

   while not eof(input) do begin
     read (input, ch) ;
     process (ch) ;
     write (output, ch) ;
   end ;

  If so, you've undoubtly heard your disk heads jumping madly between the
  input and output files.  This activity, which is very bad for your drives,
  is caused by Turbo's use of a pitifully small buffer (128 bytes) for
  text output.

  These routines provide a larger, user-selectable buffer for the standard
  procedures write and writeln.  Eliminate fussing with user-written buffering
  procedures which have to be tailored for each program and save your disk
  drives from excessive wear and tear by using these routines.

  Caveats : If your program uses the USR standard device, these routines
            are NOT for you.

  Useage:
    include this file at the beginning of your program.  Set the constant
    ZSIZE to a multiple of 128, and then

  1) Instead of opening your output file with

     var output: text ;
     assign (output, 'filename.ext') ;
     reset (output),

     just call initwrite ('filename.ext').

  2) When output is desired, use writeln (usr,var1,var2...) ;
  3) Instead of close(f), use endwrite.

  Make sure to use endwrite! If you don't, data will be lost!

  These routines work by re-directing USR output to a buffer
  which is automatically written to disk when full.  }

{   Date         : May 8, 1986                                           }
{   Update By    : Ken Isacson                                           }
{   Instructions : Set Max to the maximum nuumber of buffers to be       }
{                  open at one time.  When you call either InitWrite     }
{                  or EndWrite or Writeln(Usr, Var) be sure you have     }
{                  BufferNumber set to the correct buffer number.        }
{                  I.e. File number one gets BufferNumber := 1.          }
{                       File number two gets BufferNumber := 2.          }
{                       etc...                                           }
{   Reason       :  Allows you to have more than just one buffer!        }
{. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . }

const zsize = 4096 ; {default 4K buffer}
      Max   = 1    ; {Maximum number of buffers to be opened at one time}

type outfilename = string [14] ;
var zbuff        : array [1..zsize] of char ;
    zcount,zi    : integer ;
    zf           : file ;
    BufferNumber : Integer; {You need to be setting this accordingly in your
                             Program }

{----------------------------------------------------------}
procedure diskoff ;
{The disk drive motors on Kaypro machines don't always know when to stop
 spinning, so this routine is included to turn them off.}

var i : integer ;
    junk : boolean ;

begin
  for i := 1 to 256 do
    junk := keypressed ;
end ;

{----------------------------------------------------------}
procedure bwrite (ch : char) ;
{This replaces the USROUT routine called by write/ln.  Instead of going
 to the USR device, characters go into a buffer.  When the buffer is
 full, it is automatically written to disk.  Direct bdos calls are
 used to write the buffer because using Blockwrite can't be used.
 Evidently, Turbo has problems when its i/o procedures call each other.}

var i : integer ;

begin
  if zcount[BufferNumber] < zsize then begin  {put char into buffer}
    zcount[BufferNumber] := zcount[BufferNumber] + 1 ;
    zbuff [BufferNumber, zcount[BufferNumber]] := ch ;
  end
  else begin                                             {handle full buffer}
    for i := 1 to zsize div 128 do begin                 {Flush buffer      }
      bdos (26, addr(zbuff[BufferNumber,1])+128*(i-1)) ; {Set dma addr      }
      bdos (21, addr(zf[BufferNumber])+12);              {write 128 bytes   }
    end ;
    DiskOff ;
    for i := 1 to zsize do                               {re-init buffer    }
      zbuff [BufferNumber, i] := #26 ;
    zcount[BufferNumber] := 1 ;                         {reset buffer pointer}
    zbuff [BufferNumber, zcount[BufferNumber]] := ch ;
  end ;
end ;



{----------------------------------------------------------}
procedure initwrite (name: outfilename) ;
{sets up buffer, redirects USR output to buffer, opens output file}

var i :integer ;

begin {initwrite}
  zcount[BufferNumber] := 0 ;        {initialize buffer ptr}
  usroutptr := addr(bwrite) ;        {make our routine the usr routine}
  for i := 1 to zsize do             {initialize buffer}
    zbuff [BufferNumber, i] := #26 ;
  assign (zf[BufferNumber], name) ;  {connect to proper file}
  rewrite (zf[BufferNumber]) ;
end ; {initwrite}

{----------------------------------------------------------}
procedure endwrite ;
{Flushes out any remaining characters in buffer, closes file}

var even : boolean ;
    sec,i : integer ;

begin {endwrite}
  if zcount[BufferNumber] <> 0 then begin    {flush out unwritten buffer}
    even := (zcount[BufferNumber] mod 128 = 0) ;
    if even then sec := zcount[BufferNumber] div 128
      else sec := zcount[BufferNumber] div 128 + 1 ;
    for i := 1 to sec do begin               {flush buffer}
      bdos (26, addr(zbuff[BufferNumber, 1])+128*(i-1)) ;  {set dma addr}
      bdos (21, addr(zf[BufferNumber])+12)                 {write 128 bytes}
    end ;
    DiskOff ;
  end ;
  close (zf[BufferNumber]) ;
end ;   {endwrite}
