grendel-1.0.0a7/backup/
grendel-1.0.0a7/bin/
grendel-1.0.0a7/boards/
grendel-1.0.0a7/clans/
grendel-1.0.0a7/documentation/todo/
grendel-1.0.0a7/help/
grendel-1.0.0a7/logs/
grendel-1.0.0a7/players/
grendel-1.0.0a7/progs/
grendel-1.0.0a7/races/
grendel-1.0.0a7/src/contrib/
grendel-1.0.0a7/src/modules/speller/
grendel-1.0.0a7/src/modules/status/
grendel-1.0.0a7/src/tests/
grendel-1.0.0a7/src/tests/dunit/
{
  Summary:
  	Buffered filereader & writer
  
  ## $Id: fsys.pas,v 1.6 2004/04/14 19:34:36 druid Exp $
}

unit fsys;

interface


uses
	Classes,
	SysUtils;


const
	BUFSIZE = 65536 * 16;
	MAX_LINESIZE = 1024;


type
	GFileReader = class
	private
		fp : TFileStream;
		fname : string;
		fpos, fsize : integer;
		feol : boolean;
		fline : integer;
		buffer : array[0..BUFSIZE] of char;

	published
		function readChar() : char;
		function eof() : boolean;
		function eol() : boolean;
		procedure seek(pos : integer);

		function readLine() : string;
		function readInteger() : integer;
		function readCardinal() : cardinal;
		function readToken() : string;

		constructor Create(fn : string);
		destructor Destroy; override;
		
		property line : integer read fline;
		property filename : string read fname;
	end;

	GFileWriter = class
	private
		fp : TFileStream;
		fname : string;
		fpos : integer;
		buffer : array[0..BUFSIZE] of char;

	published
		procedure writeChar(c : char);
		procedure writeInteger(i : integer);
		procedure writeString(const s : string);
		procedure writeLine(const s : string);

		procedure flush();

		constructor Create(fn : string);
		destructor Destroy; override;

		property filename : string read fname;
	end;


function translateFileName(const fn : string) : string;


implementation


function translateFileName(const fn : string) : string;
begin
{$IFDEF LINUX}
  Result := StringReplace(fn, '\', '/', [rfReplaceAll]);
{$ELSE}
  Result := fn;
{$ENDIF}
end;

constructor GFileReader.Create(fn : string);
begin
  inherited Create;

  fn := translateFileName(fn);

  fp := TFileStream.Create(fn, fmOpenRead);

	fname := fn;

  fsize := fp.Read(buffer, BUFSIZE);
  
  //if (fsize = 0) then
  //  raise Exception.Create(fn + ': 0 length file');

  fpos := 0;
  fline := 1;
  feol := false;
end;

destructor GFileReader.Destroy();
begin
  fp.Free;

  inherited Destroy;
end;

function GFileReader.readChar() : char;
var c : char;
begin
  c := buffer[fpos];

  inc(fpos);

  if (fpos >= BUFSIZE) then
    begin
    fsize := fp.Read(buffer, BUFSIZE);
    fpos := 0;
    end;

  if (c = #10) then
    begin
//    if (buffer[fpos] = #13) or (buffer[fpos] = #10) then
//      readChar;
      
    inc(fline);
    feol := true;
    end
  else
    feol := false;

  readChar := c;
end;

function GFileReader.eof() : boolean;
begin
  eof := (fpos >= fsize) or (buffer[fpos] = #0);
end;

function GFileReader.eol() : boolean;
begin
  Result := feol;
end;

procedure GFileReader.seek(pos : integer);
begin
  { avoid pos+pos<0, don't want to get tangled in a bug
    *lazy coders grin* - Grimlord }

  if (fpos + pos >= 0) then
    inc(fpos,pos);
end;

function GFileReader.readLine() : string;
var
   chars : array[0..MAX_LINESIZE] of char;
   pos : integer;
   c : char;
begin
  feol := false;
  pos := 0;

  while (not eof()) do
    begin
    c := readChar();

    if (c <> #13) and (c <> #10) then
      begin
      chars[pos] := c;
      inc(pos);

      if (pos >= MAX_LINESIZE) then 
        begin
      	raise Exception.Create('max linesize exceeded in ' + fname);

        pos := MAX_LINESIZE;
        break;
        end;
      end;
      
    if (c = #10) then
      break;
    end;

  chars[pos] := #0;
   
  readLine := chars;
end;

function GFileReader.readInteger() : integer;
var c : char;
    number : integer;
    sign : boolean;
begin
  c := readChar();

  while (not (c in ['0'..'9','-','+'])) do
    begin
    if (eof) then
      begin
      Result := 0;
      exit;
      end;

    c := readChar;
    end;

  number := 0;
  sign := false;

  if (c = '+') then
    c := readChar
  else
  if (c = '-') then
    begin
    sign := true;
    c := readChar;
    end;

  if not (c in ['0'..'9']) then
    begin
    Result := 0;
    exit;
    end;

  while (true) do
    begin
    if (eof) then
      begin
      Result := number;
      exit;
      end;
      
    if (not (c in ['0'..'9'])) and (c <> #13) then
      break
    else
    if (c <> #13) then
      number := number * 10 + byte(c) - byte('0');
      
    c := readChar;
    end;

  if (sign) then
    number := 0 - number;

  if (c = '|') then
    inc(number, readInteger);

  Result := number;
end;

function GFileReader.readCardinal() : cardinal;
var c : char;
    number : cardinal;
    sign : boolean;
begin
  c := readChar();

  while (not (c in ['0'..'9','-','+'])) do
    begin
    if (eof) then
      begin
      Result := 0;
      exit;
      end;

    c := readChar;
    end;

  number := 0;
  sign := false;

  if (c = '+') then
    c := readChar
  else
  if (c = '-') then
    begin
    sign := true;
    c := readChar;
    end;

  if not (c in ['0'..'9']) then
    begin
    Result := 0;
    exit;
    end;

  while (true) do
    begin
    if (eof) then
      begin
      Result := number;
      exit;
      end;

    if (not (c in ['0'..'9'])) and (c <> #13) then
      break
    else
    if (c <> #13) then
      number := number * 10 + byte(c) - byte('0');
      
    c := readChar;
    end;

  if (sign) then
    number := 0 - number;

  if (c = '|') then
    inc(number, readCardinal);
    
  Result := number;
end;

function GFileReader.readToken() :  string;
var
  word : array[0..255] of char;
  quoted : boolean;
  pword : pchar;
  c : char;
begin
  c := readChar;

  while (c in [' ', #9, #13, #10]) do
    begin
    if (eof) then
      begin
      Result := '';
      exit;
      end;

    c := readChar;
    end;

  if (c = '''') or (c = '"') then
    begin
    quoted := true;
    pword := @word[0];
    end
  else
    begin
    quoted := false;
    word[0] := c;
    pword := @word[1];
    end;

  repeat
    if (eof) then
      begin
      pword^ := #0;
      Result := word;
      exit;
      end;

    pword^ := readChar;

    if (quoted) and (pword^ in ['''', '"', #10]) then
      begin
      pword^ := #0;
      Result := word;
      exit;
      end
    else
    if (not quoted) and (pword^ in [' ', #9, #10]) then
      begin
      pword^ := #0;
      Result := word;
      exit;
      end;

    if (pword^ <> #13) then
      inc(pword);
  until (pword > word + 255);
  
  Result := '';
end;


// GFileWriter
constructor GFileWriter.Create(fn : string);
begin
  inherited Create;

  fn := translateFileName(fn);
  fpos := 0;

  fp := TFileStream.Create(fn, fmCreate);
  fname := fn;
end;

destructor GFileWriter.Destroy();
begin
  flush();
  
  fp.Free();

  inherited Destroy;
end;

procedure GFileWriter.writeChar(c : char);
begin
  buffer[fpos] := c;

  inc(fpos);

  if (fpos >= BUFSIZE) then
    begin
    fp.Write(buffer, BUFSIZE);
    fpos := 0;
    end;
end;

procedure GFileWriter.writeInteger(i : integer);
begin
  writeString(IntToStr(i));
end;

procedure GFileWriter.writeString(const s : string);
var
  a : integer;
begin
  for a := 1 to length(s) do
    writeChar(s[a]);
end;

procedure GFileWriter.writeLine(const s : string);
var
  a : integer;
begin
  for a := 1 to length(s) do
    writeChar(s[a]);

{$IFDEF WIN32}
  writeChar(#13);
{$ENDIF}

  writeChar(#10);
end;

procedure GFileWriter.flush();
begin
  fp.Write(buffer, fpos);
  fpos := 0;
end;

end.