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