//
//
// The Nimrod Compiler
// (c) Copyright 2009 Andreas Rumpf
//
// See the file "copying.txt", included in this
// distribution, for details about the copyright.
//
unit llstream;
// Low-level streams for high performance.
interface
uses
nsystem, charsets, strutils;
type
TLLStreamKind = (
llsNone, // null stream: reading and writing has no effect
llsString, // stream encapsulates a string
llsFile, // stream encapsulates a file
llsStdIn); // stream encapsulates stdin
TLLStream = object(NObject)
kind: TLLStreamKind; // accessible for low-level access (lexbase uses this)
f: TBinaryFile;
s: string;
rd, wr: int; // for string streams
end;
PLLStream = ^TLLStream;
function LLStreamOpen(const data: string): PLLStream; overload;
function LLStreamOpen(var f: TBinaryFile): PLLStream; overload;
function LLStreamOpen(const filename: string; mode: TFileMode): PLLStream; overload;
function LLStreamOpen(): PLLStream; overload;
function LLStreamOpenStdIn(): PLLStream;
procedure LLStreamClose(s: PLLStream);
function LLStreamRead(s: PLLStream; buf: pointer; bufLen: int): int;
function LLStreamReadLine(s: PLLStream): string;
function LLStreamReadAll(s: PLLStream): string;
procedure LLStreamWrite(s: PLLStream; const data: string); overload;
procedure LLStreamWrite(s: PLLStream; data: Char); overload;
procedure LLStreamWrite(s: PLLStream; buf: pointer; buflen: int); overload;
procedure LLStreamWriteln(s: PLLStream; const data: string);
function LLStreamAtEnd(s: PLLStream): bool;
implementation
function LLStreamOpen(const data: string): PLLStream; overload;
begin
new(result);
{@ignore}
fillChar(result^, sizeof(result^), 0);
{@emit}
result.s := data;
result.kind := llsString;
end;
function LLStreamOpen(var f: TBinaryFile): PLLStream; overload;
begin
new(result);
{@ignore}
fillChar(result^, sizeof(result^), 0);
{@emit}
result.f := f;
result.kind := llsFile;
end;
function LLStreamOpen(const filename: string; mode: TFileMode): PLLStream; overload;
begin
new(result);
{@ignore}
fillChar(result^, sizeof(result^), 0);
{@emit}
result.kind := llsFile;
if not OpenFile(result.f, filename, mode) then result := nil;
end;
function LLStreamOpen(): PLLStream; overload;
begin
new(result);
{@ignore}
fillChar(result^, sizeof(result^), 0);
{@emit}
result.kind := llsNone;
end;
function LLStreamOpenStdIn(): PLLStream;
begin
new(result);
{@ignore}
fillChar(result^, sizeof(result^), 0);
{@emit}
result.kind := llsStdIn;
result.s := '';
end;
procedure LLStreamClose(s: PLLStream);
begin
case s.kind of
llsNone, llsString, llsStdIn: begin end;
llsFile: nimCloseFile(s.f);
end
end;
function LLreadFromStdin(s: PLLStream; buf: pointer; bufLen: int): int;
var
line: string;
L: int;
begin
s.s := '';
s.rd := 0;
while true do begin
write(output, 'Nimrod> ');
line := readLine(input);
L := length(line);
add(s.s, line);
add(s.s, nl);
if (L > 0) and (line[L-1+strStart] = '#') then break;
end;
result := min(bufLen, length(s.s)-s.rd);
if result > 0 then begin
copyMem(buf, addr(s.s[strStart+s.rd]), result);
inc(s.rd, result)
end
end;
function LLStreamRead(s: PLLStream; buf: pointer; bufLen: int): int;
begin
case s.kind of
llsNone: result := 0;
llsString: begin
result := min(bufLen, length(s.s)-s.rd);
if result > 0 then begin
copyMem(buf, addr(s.s[strStart+s.rd]), result);
inc(s.rd, result)
end
end;
llsFile: result := readBuffer(s.f, buf, bufLen);
llsStdIn: result := LLreadFromStdin(s, buf, bufLen);
end
end;
function LLStreamReadLine(s: PLLStream): string;
begin
case s.kind of
llsNone: result := '';
llsString: begin
result := '';
while s.rd < length(s.s) do begin
case s.s[s.rd+strStart] of
#13: begin
inc(s.rd);
if s.s[s.rd+strStart] = #10 then inc(s.rd);
break
end;
#10: begin inc(s.rd); break end;
else begin
addChar(result, s.s[s.rd+strStart]);
inc(s.rd);
end
end
end
end;
llsFile: result := readLine(s.f);
llsStdIn: result := readLine(input);
end
end;
function LLStreamAtEnd(s: PLLStream): bool;
begin
case s.kind of
llsNone: result := true;
llsString: result := s.rd >= length(s.s);
llsFile: result := endOfFile(s.f);
llsStdIn: result := false;
end
end;
procedure LLStreamWrite(s: PLLStream; const data: string); overload;
begin
case s.kind of
llsNone, llsStdIn: begin end;
llsString: begin add(s.s, data); inc(s.wr, length(data)) end;
llsFile: nimWrite(s.f, data);
end;
end;
procedure LLStreamWriteln(s: PLLStream; const data: string);
begin
LLStreamWrite(s, data);
LLStreamWrite(s, nl);
end;
procedure LLStreamWrite(s: PLLStream; data: Char); overload;
var
c: char;
begin
case s.kind of
llsNone, llsStdIn: begin end;
llsString: begin addChar(s.s, data); inc(s.wr); end;
llsFile: begin
c := data;
{@discard} writeBuffer(s.f, addr(c), sizeof(c));
end
end
end;
procedure LLStreamWrite(s: PLLStream; buf: pointer; buflen: int); overload;
begin
case s.kind of
llsNone, llsStdIn: begin end;
llsString: begin
if bufLen > 0 then begin
setLength(s.s, length(s.s) + bufLen);
copyMem(addr(s.s[strStart+s.wr]), buf, bufLen);
inc(s.wr, bufLen);
end
end;
llsFile: {@discard} writeBuffer(s.f, buf, bufLen);
end
end;
function LLStreamReadAll(s: PLLStream): string;
const
bufSize = 2048;
var
bytes, i: int;
begin
case s.kind of
llsNone, llsStdIn: result := '';
llsString: begin
if s.rd = 0 then result := s.s
else result := ncopy(s.s, s.rd+strStart);
s.rd := length(s.s);
end;
llsFile: begin
result := newString(bufSize);
bytes := readBuffer(s.f, addr(result[strStart]), bufSize);
i := bytes;
while bytes = bufSize do begin
setLength(result, i+bufSize);
bytes := readBuffer(s.f, addr(result[i+strStart]), bufSize);
inc(i, bytes);
end;
setLength(result, i);
end
end
end;
end.