{*******************************************************}
{                                                       }
{       WHY not a compiler? by Y [05-04-00]             }
{       Low level character stream unit                 }
{                                                       }
{       Copyright (c) 1999-2000 CROWELL, Inc.           }
{       All Rights Reserved.                            }
{                                                       }
{*******************************************************}

unit CIOStream;

{$I CDEFINES.PAS} {$IFDEF TPC} {$N+} {$ENDIF}

interface

uses Objects, CConstants;

type

  {TDoubleBufStream, a low level double buffered character stream}

  PDoubleBufStream = ^TDoubleBufStream;
  TDoubleBufStream = object(TBufStream)
    CharsRemain: Integer;
    SecondBuffer: array [1..SecondBufferSize] of char;
    LastChar: Char;
    CurrentLine, CurrentPos: Integer;
    constructor Init(FileName: FNameStr; Mode, Size: Word);
    function GetChar: Char;
    procedure PutBack(C: Char);
  end;

implementation

{TDoubleBufStream}

constructor TDoubleBufStream.Init(FileName: FNameStr; Mode, Size: Word);
begin
  inherited Init(FileName, Mode, Size);
  CurrentLine := 1;
  CurrentPos := 0;
  LastChar := #0; {any char but not CR or LF}
  CharsRemain := 0;
end; {TDoubleBufStream.Init}

function TDoubleBufStream.GetChar: Char;
var
  TempChar: Char;
begin
  if (CharsRemain > 0) then
  begin
    TempChar := SecondBuffer[CharsRemain];
    Dec(CharsRemain);
  end
  else
  begin
    {read new char}
    Read(TempChar, 1);
    if (Status = 0) then
    begin
      {update current line and position}
      Inc(CurrentPos);
      if ((TempChar = CR) and (LastChar <> LF)) or
        ((TempChar = LF) and (LastChar <> CR)) then
      begin
        CurrentPos := 0;
        Inc(CurrentLine);
      end;
      if ((TempChar = CR) and (LastChar = LF)) or
        ((TempChar = LF) and (LastChar = CR)) then
        LastChar := #0 {neither CR nor LF}
      else
        LastChar := TempChar;
    end;
  end;

  GetChar := TempChar;
end; {TDoubleBufStream.GetChar}

procedure TDoubleBufStream.PutBack(C: Char);
begin
  if (CharsRemain >= SecondBufferSize) then
    Status := stNoMorePlace
  else
  begin
    Inc(CharsRemain);
    SecondBuffer[CharsRemain] := C;
  end;
end; {TDoubleBufStream.ButBack}

end {CIOStreams}.