summary refs log blame commit diff stats
path: root/nim/llstream.pas
blob: 30d9c02872a86ad233fab033198b03685ffb1d2f (plain) (tree)
1
2
3
4

                                
                                          


















                                                                       
                                                                               
                   
                                      


















                                                                                    
                                                            

















































                                                                                    














                                                                       
            






                                                         
                                          
                          
                                                   






                                                                     
                                              
                              
                                                       











                                                        
                                       
                     
                                                       
                 
                                          
                    
                                                
             
         








                                           
                                             







                                                                    
                                                                 
                                 





                                                            






                                                            
                                                        












                                                                           
                                                       













                                                      

                                               














                                                                    
//
//
//           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.