unit streams; {$M+} interface uses classes; // Ring Buffer. type // not seekable. TRingBufferFullException = class end; TRingBufferStream = class(TStream) private fBuffer : array[0..9] of Char; fReadPosition : Cardinal; fWritePosition : Cardinal; fPosition : Cardinal; // virtual position, TODO. published function ReadByte : Byte; procedure WriteByte(aValue : Byte); function Read(var Buffer; Count : LongInt) : LongInt; override; function Write(const Buffer; Count : LongInt) : LongInt; override; procedure Drain; end; TTerminalInputStream = class(TStream) private fFD : Integer; published constructor Create(aFD : Integer); published function ReadByte : Byte; procedure WriteByte(aValue : Byte); function Read(var Buffer; Count : LongInt) : LongInt; override; function Write(const Buffer; Count : LongInt) : LongInt; override; end; implementation {$IFNDEF WIN32} uses baseunix; {$ENDIF} function TRingBufferStream.ReadByte : Byte; begin if fReadPosition <> fWritePosition then begin Result := Ord(fBuffer[fReadPosition]); Inc(fReadPosition); if fReadPosition >= Length(fBuffer) then fReadPosition := 0; end else raise EReadError.Create('EOF'); end; procedure TRingBufferStream.WriteByte(aValue : Byte); var availableRightSide : Cardinal; availableLeftSide : Cardinal; begin if fWritePosition < fReadPosition then begin // B [Dw rDDD] E availableRightSide := fReadPosition - fWritePosition; availableLeftSide := 0; end else if fWritePosition >= fReadPosition then begin // B [ rDDDw ] E availableRightSide := Length(fBuffer) - fWritePosition; availableLeftSide := fReadPosition; end; if availableRightSide + availableLeftSide = 0 then raise TRingBufferFullException.Create; //Count := 0; // TODO fill state check? fBuffer[fWritePosition] := Chr(aValue); Inc(fWritePosition); if fWritePosition >= Length(fBuffer) then fWritePosition := 0; end; procedure Move1(source : PChar; destination : PChar; Count : Cardinal); inline; begin while Count > 0 do begin destination^ := source^; Inc(destination); Inc(source); Dec(Count); end; end; function TRingBufferStream.Read(var Buffer; Count : LongInt) : LongInt; var availableRightSide : Cardinal; availableLeftSide : Cardinal; rightStart : PChar; begin availableRightSide := 0; availableLeftSide := 0; Result := 0; rightStart := @fBuffer[fReadPosition]; if fWritePosition < fReadPosition then begin // B [Dw rD] E availableRightSide := Length(fBuffer) - fReadPosition; availableLeftSide := fWritePosition; end else if fWritePosition > fReadPosition then begin // B [ rDDDw ] E availableRightSide := fWritePosition - fReadPosition; availableLeftSide := 0; end; if Count > availableRightSide + availableLeftSide then Count := availableRightSide + availableLeftSide; if Count > 0 then if Count > availableRightSide then begin Move1(rightStart, @Buffer, availableRightSide); Move1(@fBuffer[0], PChar(@Buffer) + availableRightSide, Count - availableRightSide); end else begin Move1(rightStart, @Buffer, Count); end; fReadPosition := (fReadPosition + Count) mod Length(fBuffer); Result := Count; end; function TRingBufferStream.Write(const Buffer; Count : LongInt) : LongInt; var availableRightSide : Cardinal; availableLeftSide : Cardinal; rightStart : PChar; begin // TODO throw expection on overrun. rightStart := @fBuffer[fWritePosition]; if fWritePosition < fReadPosition then begin // B [Dw rDDD] E availableRightSide := fReadPosition - fWritePosition; availableLeftSide := 0; end else if fWritePosition >= fReadPosition then begin // B [ rDDDw ] E availableRightSide := Length(fBuffer) - fWritePosition; availableLeftSide := fReadPosition; end; if (Count > availableLeftSide + availableRightSide) then raise TRingBufferFullException.Create; //Count := availableLeftSide + availableRightSide; // TODO throw exception. if Count > 0 then begin if Count > availableRightSide then begin Move1(@Buffer, rightStart, availableRightSide); Move1(PChar(@Buffer) + availableRightSide, @fBuffer[0], Count - availableRightSide); end else begin Move1(@Buffer, rightStart, Count); end; end; fWritePosition := (fWritePosition + Count) mod Length(fBuffer); Result := Count; end; procedure TRingBufferStream.Drain; begin fReadPosition := 0; fWritePosition := 0; end; { TTerminalInputStream } constructor TTerminalInputStream.Create(aFD : Integer); begin inherited Create; fFD := aFD; {function sysKeyPressed: boolean; var fdsin : tfdSet; begin if (InCnt>0) then sysKeyPressed:=true else begin fpFD_ZERO(fdsin); fpFD_SET(TTYin,fdsin); sysKeypressed:=(fpSelect(TTYIn+1,@fdsin,nil,nil,0)>0); end; end;} end; function TTerminalInputStream.ReadByte : Byte; var buffer : Byte; begin if Read(buffer, 1) >= 1 then Result := buffer else raise EReadError.Create('EOF'); end; procedure TTerminalInputStream.WriteByte(aValue : Byte); begin // ??? end; function TTerminalInputStream.Read(var Buffer; Count : LongInt) : LongInt; begin {$IFDEF WIN32} Result := 0; {$ELSE} Result := fpRead(fFD, @Buffer, 1); {$ENDIF} // Move1(rightStart, @Buffer, Count); // TODO use select() and buffer that many. end; function TTerminalInputStream.Write(const Buffer; Count : LongInt) : LongInt; begin Result := 0; // ??? end; end.