summary refs log blame commit diff stats
path: root/nim/nsystem.pas
blob: c33236189cc4e5325fe0130da61d1732096a614c (plain) (tree)










































                                                          

                                
















































                                                                



                
            























































                                                                          

                                   
                                     

                                     
                          

















                                                                            


                                                          
                                          




                                                                  




















                                                                         

                                                                    

                                                                   


              













                                                                   





























































                                                          












                                     




                                     



                                   




                          
























































































































                                                                   
                          











                                                        









                                                











































                                                                        




























                                                                    


















































                                                             



                                            
                                  
              








                                                

                                                 
        




                    


                                                            
                         
        


             
    
//
//
//           The Nimrod Compiler
//        (c) Copyright 2008 Andreas Rumpf
//
//    See the file "copying.txt", included in this
//    distribution, for details about the copyright.
//
unit nsystem;

// This module provides things that are in Nimrod's system
// module and not available in Pascal.

interface

{$include 'config.inc'}

uses
  sysutils
{$ifdef fpc}
  , math
{$endif}
  ;

type
  // Generic int like in Nimrod:
  // well, no, because of FPC's bugs...
{$ifdef cpu64}
  int = int64;
  uint = qword;
{$else}
  int = longint;
  uint = cardinal;
{$endif}

  TResult = Boolean;
  EInvalidValue = class(Exception)
  end;

{$ifndef fpc}
  EOverflow = class(Exception)
  end;
{$endif}
  EOutOfRange = class(Exception)
  end;

  float32 = single;
  float64 = double;
  PFloat32 = ^float32;
  PFloat64 = ^float64;
const
  Failure = False;
  Success = True;

  snil = '';

type
  Natural = 0..high(int);
  Positive = 1..high(int);
  NObject = object // base type for all objects, cannot use
  // TObject here, as it would overwrite System.TObject which is
  // a class in Object pascal. Anyway, pas2mor has no problems
  // to replace NObject by TObject
  end;
  PObject = ^NObject;

  int16 = smallint;
  int8 = shortint;
  int32 = longint;
  uint16 = word;
  uint32 = longword;
  uint8 = byte;

  TByteArray = array [0..1024 * 1024] of Byte;
  PByteArray = ^TByteArray;
  PByte = ^Byte;
  cstring = pchar;
  bool = boolean;
  PInt32 = ^int32;

{$ifdef bit64clean} // BUGIX: was $ifdef fpc
  BiggestUInt = QWord;
  BiggestInt = Int64; // biggest integer type available
{$else}
  BiggestUInt = Cardinal; // Delphi's Int64 is broken seriously
  BiggestInt = Integer;   // ditto
{$endif}
  BiggestFloat = Double; // biggest floating point type
{$ifdef cpu64}
  TAddress = Int64;
{$else}
  TAddress = longint;
{$endif}

var
  NaN: float;
  inf: float;
  NegInf: float;
{$ifdef fpc}
{$else}
  {$ifopt Q+}
    {$define Q_on}
    {$Q-}
  {$endif}
  {$ifopt R+}
    {$define R_on}
    {$R-}
  {$endif}
  const
    Inf = 1.0/0.0;
    NegInf = (-1.0) / 0.0;
  {$ifdef Q_on}
    {$Q+}
    {$undef Q_on}
  {$endif}
  {$ifdef R_on}
    {$R+}
    {$undef R_on}
  {$endif}
{$endif}

function toFloat(i: biggestInt): biggestFloat;
function toInt(r: biggestFloat): biggestInt;

function min(a, b: int): int; overload;
function max(a, b: int): int; overload;
{$ifndef fpc} // fpc cannot handle these overloads (bug in 64bit version?)
// the Nimrod compiler does not use them anyway, so it does not matter
function max(a, b: real): real; overload;
function min(a, b: real): real; overload;
{$endif}

procedure zeroMem(p: Pointer; size: int);
procedure copyMem(dest, source: Pointer; size: int);
procedure moveMem(dest, source: Pointer; size: int);
function equalMem(a, b: Pointer; size: int): Boolean;

function ncopy(s: string; a: int = 1): string; overload;
function ncopy(s: string; a, b: int): string; overload;
// will be replaced by "copy"

function newString(len: int): string;

procedure addChar(var s: string; c: Char);

{@ignore}
function addU(a, b: biggestInt): biggestInt;
function subU(a, b: biggestInt): biggestInt;
function mulU(a, b: biggestInt): biggestInt;
function divU(a, b: biggestInt): biggestInt;
function modU(a, b: biggestInt): biggestInt;
function shlU(a, b: biggestInt): biggestInt;
function shrU(a, b: biggestInt): biggestInt;
function ltU(a, b: biggestInt): bool;
function leU(a, b: biggestInt): bool;

function toU8(a: biggestInt): byte;
function toU16(a: biggestInt): int16;
function toU32(a: biggestInt): int32;
function ze64(a: byte): biggestInt;
function ze(a: byte): int;
{@emit}

function alloc(size: int): Pointer;
function realloc(p: Pointer; newsize: int): Pointer;
procedure dealloc(p: Pointer);

type
  TTextFile = record
    buf: PChar;
    sysFile: system.textFile;
  end;

  TBinaryFile = file;

  TFileMode = (fmRead, fmWrite, fmReadWrite, fmReadWriteExisting, fmAppend);

function OpenFile(out f: tTextFile; const filename: string;
                  mode: TFileMode = fmRead): Boolean; overload;
function endofFile(var f: tBinaryFile): boolean; overload;
function endofFile(var f: textFile): boolean; overload;

function readChar(var f: tTextFile): char;
function readLine(var f: tTextFile): string; overload;
function readLine(var f: tBinaryFile): string; overload;
function readLine(var f: textFile): string; overload;

procedure nimWrite(var f: tTextFile; const str: string); overload;
procedure nimCloseFile(var f: tTextFile); overload;

// binary file handling:
function OpenFile(var f: tBinaryFile; const filename: string;
                  mode: TFileMode = fmRead): Boolean; overload;
procedure nimCloseFile(var f: tBinaryFile); overload;

function ReadBytes(var f: tBinaryFile; out a: array of byte;
                   start, len: int): int;
function ReadChars(var f: tBinaryFile; out a: array of char;
                   start, len: int): int;

function writeBuffer(var f: TBinaryFile; buffer: pointer; len: int): int;
function readBuffer(var f: tBinaryFile; buffer: pointer; len: int): int;
overload;
function readBuffer(var f: tBinaryFile): string; overload;
function getFilePos(var f: tBinaryFile): int;
procedure setFilePos(var f: tBinaryFile; pos: int64);

function readFile(const filename: string): string;

procedure nimWrite(var f: tBinaryFile; const str: string); overload;

procedure add(var x: string; const y: string);
// Pascal version of string appending. Terminating zero is ignored.

implementation

{@ignore}
procedure add(var x: string; const y: string);
// Pascal version of string appending. Terminating zero is ignored.
var
  L: int;
begin
  L := length(y);
  if L > 0 then begin
    if y[L] = #0 then x := x + copy(y, 1, L-1)
    else x := x + y;
  end
end;
{@emit}

function alloc(size: int): Pointer;
begin
  getMem(result, size); // use standard allocator
  FillChar(result^, size, 0);
end;

function realloc(p: Pointer; newsize: int): Pointer;
begin
  reallocMem(p, newsize); // use standard allocator
  result := p;
end;

procedure dealloc(p: pointer);
begin
  freeMem(p);
end;

{@ignore}
function addU(a, b: biggestInt): biggestInt;
begin
  result := biggestInt(biggestUInt(a) + biggestUInt(b));
end;

function subU(a, b: biggestInt): biggestInt;
begin
  result := biggestInt(biggestUInt(a) - biggestUInt(b));
end;

function mulU(a, b: biggestInt): biggestInt;
begin
  result := biggestInt(biggestUInt(a) * biggestUInt(b));
end;

function divU(a, b: biggestInt): biggestInt;
begin
  result := biggestInt(biggestUInt(a) div biggestUInt(b));
end;

function modU(a, b: biggestInt): biggestInt;
begin
  result := biggestInt(biggestUInt(a) mod biggestUInt(b));
end;

function shlU(a, b: biggestInt): biggestInt;
begin
  result := biggestInt(biggestUInt(a) shl biggestUInt(b));
end;

function shrU(a, b: biggestInt): biggestInt;
begin
  result := biggestInt(biggestUInt(a) shr biggestUInt(b));
end;

function ltU(a, b: biggestInt): bool;
begin
  result := biggestUInt(a) < biggestUInt(b);
end;

function leU(a, b: biggestInt): bool;
begin
  result := biggestUInt(a) < biggestUInt(b);
end;

function toU8(a: biggestInt): byte;
begin
  assert(a >= 0);
  assert(a <= 255);
  result := a;
end;

function toU32(a: biggestInt): int32;
begin
  result := int32(a and $ffffffff);
end;

function toU16(a: biggestInt): int16;
begin
  result := int16(a and $ffff);  
end;

function ze64(a: byte): biggestInt;
begin
  result := a
end;

function ze(a: byte): int;
begin
  result := a
end;
{@emit}

procedure addChar(var s: string; c: Char);
{@ignore}
// delphi produces suboptimal code for "s := s + c"
{$ifndef fpc}
var
  len: int;
{$endif}
{@emit}
begin
{@ignore}
{$ifdef fpc}
  s := s + c
{$else}
  {$ifopt H+}
  len := length(s);
  setLength(s, len + 1);
  PChar(Pointer(s))[len] := c
  {$else}
  s := s + c
  {$endif}
{$endif}
{@emit
  s &= c
}
end;

function newString(len: int): string;
begin
  setLength(result, len);
  if len > 0 then begin
  {@ignore}
    fillChar(result[1], length(result), 0);
  {@emit}
  end
end;

function toFloat(i: BiggestInt): BiggestFloat;
begin
  result := i // conversion automatically in Pascal
end;

function toInt(r: BiggestFloat): BiggestInt;
begin
  result := round(r);
end;

procedure zeroMem(p: Pointer; size: int);
begin
  fillChar(p^, size, 0);
end;

procedure copyMem(dest, source: Pointer; size: int);
begin
  if size > 0 then
    move(source^, dest^, size);
end;

procedure moveMem(dest, source: Pointer; size: int);
begin
  if size > 0 then
    move(source^, dest^, size); // move handles overlapping regions
end;

function equalMem(a, b: Pointer; size: int): Boolean;
begin
  result := compareMem(a, b, size);
end;

{$ifndef fpc}
function min(a, b: real): real; overload;
begin
  if a < b then result := a else result := b
end;

function max(a, b: real): real; overload;
begin
  if a > b then result := a else result := b
end;
{$endif}

function min(a, b: int): int; overload;
begin
  if a < b then result := a else result := b
end;

function max(a, b: int): int; overload;
begin
  if a > b then result := a else result := b
end;

function ncopy(s: string; a, b: int): string;
begin
  result := copy(s, a, b-a+1);
end;

function ncopy(s: string; a: int = 1): string;
begin
  result := copy(s, a, length(s))
end;


{$ifopt I+} {$define I_on} {$I-} {$endif}
function OpenFile(out f: tTextFile; const filename: string;
                  mode: TFileMode = fmRead): Boolean; overload;
begin
  AssignFile(f.sysFile, filename);
  f.buf := alloc(4096);
  SetTextBuf(f.sysFile, f.buf^, 4096);
  case mode of
    fmRead: Reset(f.sysFile);
    fmWrite: Rewrite(f.sysFile);
    fmReadWrite: Reset(f.sysFile);
    fmAppend: Append(f.sysFile);
  end;
  result := (IOResult = 0);
end;

function readChar(var f: tTextFile): char;
begin
  Read(f.sysFile, result);
end;

procedure nimWrite(var f: tTextFile; const str: string);
begin
  system.write(f.sysFile, str)
end;

function readLine(var f: tTextFile): string;
begin
  Readln(f.sysFile, result);
end;

function endofFile(var f: tBinaryFile): boolean;
begin
  result := eof(f)
end;

function endofFile(var f: textFile): boolean;
begin
  result := eof(f)
end;

procedure nimCloseFile(var f: tTextFile);
begin
  closeFile(f.sysFile);
  dealloc(f.buf)
end;

procedure nimCloseFile(var f: tBinaryFile);
begin
  closeFile(f);
end;

function OpenFile(var f: TBinaryFile; const filename: string;
                  mode: TFileMode = fmRead): Boolean;
begin
  AssignFile(f, filename);
  case mode of
    fmRead: Reset(f, 1);
    fmWrite: Rewrite(f, 1);
    fmReadWrite: Reset(f, 1);
    fmAppend: assert(false);
  end;
  result := (IOResult = 0);
end;

function ReadBytes(var f: tBinaryFile; out a: array of byte;
                   start, len: int): int;
begin
  result := 0;
  BlockRead(f, a[0], len, result)
end;

function ReadChars(var f: tBinaryFile; out a: array of char;
                   start, len: int): int;
begin
  result := 0;
  BlockRead(f, a[0], len, result)
end;

function readBuffer(var f: tBinaryFile; buffer: pointer; len: int): int;
begin
  result := 0;
  BlockRead(f, buffer^, len, result)
end;

procedure nimWrite(var f: tBinaryFile; const str: string); overload;
begin
  writeBuffer(f, addr(str[1]), length(str));
end;

function readLine(var f: tBinaryFile): string; overload;
var
  c: char;
begin
  result := '';
  while readBuffer(f, addr(c), 1) = 1 do begin
    case c of
      #13: begin
        readBuffer(f, addr(c), 1); // skip #10
        break;
      end;
      #10: break;
      else begin end
    end;
    addChar(result, c);
  end
end;

function readLine(var f: textFile): string; overload;
begin
  result := '';
  readln(f, result);
end;

function readBuffer(var f: tBinaryFile): string; overload;
const
  bufSize = 4096;
var
  bytesRead, len, cap: int;
begin
  // read the file in 4K chunks
  result := newString(bufSize);
  cap := bufSize;
  len := 0;
  while true do begin
    bytesRead := readBuffer(f, addr(result[len+1]), bufSize);
    inc(len, bytesRead);
    if bytesRead <> bufSize then break;
    inc(cap, bufSize);
    setLength(result, cap);
  end;
  setLength(result, len);
end;

function readFile(const filename: string): string;
var
  f: tBinaryFile;
begin
  if openFile(f, filename) then begin
    result := readBuffer(f);
    nimCloseFile(f)
  end
  else
    result := '';
end;

function writeBuffer(var f: TBinaryFile; buffer: pointer;
                     len: int): int;
begin
  result := 0;
  BlockWrite(f, buffer^, len, result);
end;

function getFilePos(var f: tBinaryFile): int;
begin
  result := filePos(f);
end;

procedure setFilePos(var f: tBinaryFile; pos: int64);
begin
  Seek(f, pos);
end;

{$ifdef I_on} {$undef I_on} {$I+} {$endif}

{$ifopt R+} {$R-,Q-} {$define R_on} {$endif}
var
  zero: float;
  Saved8087CW: Word;
  savedExcMask: TFPUExceptionMask;
initialization
{$ifdef cpu64}
  savedExcMask := SetExceptionMask([exInvalidOp,
	exDenormalized,
	exPrecision,
	exZeroDivide,
	exOverflow,
	exUnderflow
	]);
{$else}
  Saved8087CW := Default8087CW;
  Set8087CW($133f); // Disable all fpu exceptions
{$endif}
  zero := 0.0;
  NaN := 0.0 / zero;
  inf := 1.0 / zero;
  NegInf := -inf;
finalization
{$ifdef cpu64}
  SetExceptionMask(savedExcMask); // set back exception mask
{$else}
  Set8087CW(Saved8087CW);
{$endif}
{$ifdef R_on}
  {$R+,Q+}
{$endif}
end.