{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}