{ $Id$ This file is part of the Free Pascal Run time library. Copyright (c) 1993,97 by the Free Pascal development team See the file COPYING.FPC, included in this distribution, for details about the copyright. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. **********************************************************************} { Possible Defines: EXTENDED_EOF Use extended EOF checking for textfile, necessary for Pipes and Sockets under Linux EOF_CTRLZ Is Ctrl-Z (#26) a EOF mark for textfiles SHORT_LINEBREAK Use short Linebreaks #10 instead of #10#13 Both EXTENDED_EOF and SHORT_LINEBREAK are defined in the Linux system unit (syslinux.pp) } {**************************************************************************** subroutines For TextFile handling ****************************************************************************} Procedure FileCloseFunc(Var t:TextRec); Begin Do_Close(t.Handle); t.Handle:=UnusedHandle; End; Procedure FileInOutFunc(var t:TextRec); Begin Case t.mode Of fmoutput : Do_Write(t.Handle,Longint(t.Bufptr),t.BufPos); fminput : t.BufEnd:=Do_Read(t.Handle,Longint(t.Bufptr),t.BufSize); else RunError(102); End; t.BufPos:=0; End; Procedure FileOpenFunc(var t:TextRec); var Flags : Longint; Begin t.InOutFunc:=@FileInOutFunc; t.FlushFunc:=@FileInOutFunc; t.CloseFunc:=@FileCloseFunc; Case t.mode Of fmInput : Flags:=$1000; fmOutput : Flags:=$1101; fmAppend : Flags:=$1011; End; Do_Open(t,PChar(@TextRec(t).Name),Flags); End; Procedure assign(var t:Text;const s:String); Begin FillChar(t,SizEof(TextRec),0); TextRec(t).Handle:=UnusedHandle; TextRec(t).mode:=fmClosed; TextRec(t).BufSize:=128; TextRec(t).Bufpos:=0; TextRec(T).Bufend:=0; TextRec(t).Bufptr:=@TextRec(t).Buffer; TextRec(t).OpenFunc:=@FileOpenFunc; Move(s[1],TextRec(t).Name,Length(s)); End; Procedure Close(var t : Text);[Public,Alias: 'CLOSE_TEXT',IOCheck]; Begin If (TextRec(t).mode<>fmClosed) Then Begin FileFunc(TextRec(t).FlushFunc)(TextRec(t)); TextRec(t).mode:=fmClosed; { Only close functions not connected to stdout.} If ((TextRec(t).Handle<>StdInputHandle) or (TextRec(t).Handle<>StdOutputHandle) or (TextRec(t).Handle<>StdErrorHandle)) Then FileFunc(TextRec(t).CloseFunc)(TextRec(t)); End; End; Procedure OpenText(var t : Text;mode,defHdl:Longint); Begin Case TextRec(t).mode Of {This gives the fastest code} fmInput,fmOutput,fmInOut : Close(t); fmClosed : ; else Begin InOutRes:=102; exit; End; End; TextRec(t).mode:=mode; If TextRec(t).Name[0]<>#0 Then FileFunc(TextRec(t).OpenFunc)(TextRec(t)) else Begin TextRec(t).Handle:=defHdl; TextRec(t).InOutFunc:=@FileInOutFunc; TextRec(t).FlushFunc:=@FileInOutFunc; TextRec(t).CloseFunc:=@FileCloseFunc; End; End; Procedure Rewrite(var t : Text);[IOCheck]; Begin OpenText(t,fmOutput,1); End; Procedure Reset(var t : Text);[IOCheck]; Begin OpenText(t,fmInput,0); End; Procedure Append(var t : Text);[IOCheck]; Begin OpenText(t,fmAppend,1); End; Procedure Flush(var t : Text);[IOCheck]; Begin If TextRec(t).mode<>fmOutput Then exit; FileFunc(TextRec(t).FlushFunc)(TextRec(t)); End; Procedure Erase(var t:Text);[IOCheck]; Begin If TextRec(t).mode=fmClosed Then Do_Erase(PChar(@TextRec(t).Name)); End; Procedure Rename(var t:Text;const s:String);[IOCheck]; var p : array[0..255] Of Char; Begin If TextRec(t).mode=fmClosed Then Begin Move(s[1],p,Length(s)); p[Length(s)]:=#0; Do_Rename(PChar(@TextRec(t).Name),PChar(@p)); Move(p,TextRec(t).Name,Length(s)+1); End; End; Function Eof(Var t: Text): Boolean;[IOCheck]; Begin {$IFNDEF EXTENDED_EOF} {$IFDEF EOF_CTRLZ} Eof:=TextRec(t).Buffer[TextRec(t).BufPos]=#26; If Eof Then Exit; {$ENDIF EOL_CTRLZ} Eof:=(Do_FileSize(TextRec(t).Handle)<=Do_FilePos(TextRec(t).Handle)); If Eof Then Eof:=TextRec(t).BufEnd <= TextRec(t).BufPos; {$ELSE EXTENDED_EOF} { The previous method will NOT work on stdin and pipes or sockets. So how to do it ? 1) Check if characters in buffer - Yes ? Eof=false; 2) Read buffer full. If 0 Chars Read : Eof ! Michael.} If TextRec(T).mode=fmClosed Then { Sanity Check } Begin Eof:=True; Exit; End; If (TextRec(T).BufPos < TextRec(T).BufEnd) Then Begin Eof:=False; Exit End; TextRec(T).BufPos:=0; TextRec(T).BufEnd:=Do_Read(TextRec(T).Handle,Longint(TextRec(T).BufPtr),TextRec(T).BufSize); If TextRec(T).BufEnd<0 Then TextRec(T).BufEnd:=0; Eof:=(TextRec(T).BufEnd=0); {$ENDIF EXTENDED_EOF} End; Function Eof:Boolean; Begin Eof:=Eof(Input); End; Function SeekEof (Var F : Text) : Boolean; Var TR : ^TextRec; Temp : Longint; Begin TR:=@TextRec(f); If TR^.mode<>fmInput Then exit (true); SeekEof:=True; {No data in buffer ? Fill it } If TR^.BufPos>=TR^.BufEnd Then FileFunc(TR^.InOutFunc)(TR^); Temp:=TR^.BufPos; while (TR^.BufPos=TR^.BufEnd Then Begin FileFunc(TR^.InOutFunc)(TR^); Temp:=TR^.BufPos+1; End; End; End; Function SeekEof : Boolean; Begin SeekEof:=SeekEof(Input); End; Function Eoln(var t:Text) : Boolean; Begin { maybe we need new data } If TextRec(t).BufPos>=TextRec(t).BufEnd Then FileFunc(TextRec(t).InOutFunc)(TextRec(t)); Eoln:=Eof(t) or (TextRec(t).Bufptr^[TextRec(t).BufPos] In [#10,#13]); End; Function Eoln : Boolean; Begin Eoln:=Eoln(Input); End; Function SeekEoln (Var F : Text) : Boolean; Var TR : ^TextRec; Temp : Longint; Begin TR:=@TextRec(f); If TR^.mode<>fmInput Then exit (true); SeekEoln:=True; {No data in buffer ? Fill it } If TR^.BufPos>=TR^.BufEnd Then FileFunc(TR^.InOutFunc)(TR^); Temp:=TR^.BufPos; while (TR^.BufPos=TR^.BufEnd Then Begin FileFunc(TR^.InOutFunc)(TR^); Temp:=TR^.BufPos+1; End; End; End; Function SeekEoln : Boolean; Begin SeekEoln:=SeekEoln(Input); End; Procedure SetTextBuf(Var F : Text; Var Buf);[INTERNPROC: In_settextbuf_file_x]; Procedure SetTextBuf(Var F : Text; Var Buf; Size : Word); Begin TextRec(f).BufPtr:=@Buf; TextRec(f).BufSize:=Size; TextRec(f).BufPos:=0; TextRec(f).BufEnd:=0; End; {***************************************************************************** Write(Ln) *****************************************************************************} Procedure w(Len : Longint;var f : TextRec;var s : String);[Public,Alias: 'WRITE_TEXT_STRING']; var hbytes,Pos,copybytes : Longint; hs : String; Begin If f.mode<>fmOutput Then exit; copybytes:=Length(s); If Len>copybytes Then Begin hs:=Space(Len-copybytes); w(0,f,hs); End; Pos:=1; hbytes:=f.BufSize-f.BufPos; { If no room in Buffer, do a flush. } If hbytes=0 Then FileFunc(f.FlushFunc)(f); while copybytes>hbytes Do Begin Move(s[Pos],f.Bufptr^[f.BufPos],hbytes); f.BufPos:=f.BufPos+hbytes; dec(copybytes,hbytes); Inc(Pos,hbytes); FileFunc(f.InOutFunc)(f); hbytes:=f.BufSize-f.BufPos; End; Move(s[Pos],f.Bufptr^[f.BufPos],copybytes); f.BufPos:=f.BufPos+copybytes; End; Procedure w(var t : TextRec);[Public,Alias: 'WRITELN_TEXT']; var hs : String; Begin {$IFDEF SHORT_LINEBREAK} hs:=#10; {$ELSE} hs:=#13#10; {$ENDIF} w(0,t,hs); End; Type array00 = array[0..0] Of Char; Procedure w(Len : Longint;var f : TextRec;const p : array00);[Public,Alias: 'WRITE_TEXT_PCHAR_AS_ARRAY']; var hbytes,Pos,copybytes : Longint; hs : String; Begin If f.mode<>fmOutput Then exit; copybytes:=StrLen(p); If Len>copybytes Then Begin hs:=Space(Len-copybytes); w(0,f,hs); End; Pos:=0; hbytes:=f.BufSize-f.BufPos; { If no room in buffer , do a flush. } If hbytes=0 Then FileFunc(f.FlushFunc)(f); while copybytes>hbytes Do Begin Move(p[Pos],f.Bufptr^[f.BufPos],hbytes); f.BufPos:=f.BufPos+hbytes; dec(copybytes,hbytes); Inc(Pos,hbytes); FileFunc(f.InOutFunc)(f); hbytes:=f.BufSize-f.BufPos; End; Move(p[Pos],f.Bufptr^[f.BufPos],copybytes); f.BufPos:=f.BufPos+copybytes; End; Procedure wa(Len : Longint;var f : TextRec;p : PChar);[Public,Alias: 'WRITE_TEXT_PCHAR_AS_POINTER']; Begin w(Len,f,p); End; Procedure w(Len : Longint;var t : TextRec;l : Longint);[Public,Alias: 'WRITE_TEXT_LONGINT']; var s : String; Begin Str(l,s); w(Len,t,s); End; {$ifdef i386} Procedure w(fixkomma,Len : Longint;var t : TextRec;r : real);[Public,Alias: 'WRITE_TEXT_REAL']; var s : String; Begin Str_real(Len,fixkomma,r,rt_s64real,s); w(Len,t,s); End; {$else} Procedure w(fixkomma,Len : Longint;var t : TextRec;r : real);[Public,Alias: 'WRITE_TEXT_REAL']; var s : String; Begin Str_real(Len,fixkomma,r,rt_s32real,s); w(Len,t,s); End; {$endif} {$IFDEF VER_ABOVE0_9_7} { Older versions of the compiler convert all floats to real } Procedure w(Len : Longint;var t : TextRec;l : cardinal);[Public,Alias: 'WRITE_TEXT_CARDINAL']; var s : String; Begin Str(L,s); w(Len,t,s); End; {$ifdef ieee_support} Procedure w(fixkomma,Len : Longint;var t : TextRec;r : single);[Public,Alias: 'WRITE_TEXT_SINGLE']; var s : String; Begin Str_real(Len,fixkomma,r,rt_s32real,s); w(Len,t,s); End; Procedure w(fixkomma,Len : Longint;var t : TextRec;r : extended);[Public,Alias: 'WRITE_TEXT_EXTENDED']; var s : String; Begin Str_real(Len,fixkomma,r,rt_s80real,s); w(Len,t,s); End; {$endif ieee_support} {$ifdef comp_support} Procedure w(fixkomma,Len : Longint;var t : TextRec;r : comp);[Public,Alias: 'WRITE_TEXT_COMP']; var s : String; L : longint; Begin Str_real(Len,fixkomma,r,rt_s64bit,s); w(Len,t,s); End; {$endif comp_support} Procedure w(fixkomma,Len : Longint;var t : TextRec;r : fixed);[Public,Alias: 'WRITE_TEXT_FIXED']; var s : String; Begin Str_real(Len,fixkomma,r,rt_f32bit,s); w(Len,t,s); End; {$ENDIF VER_ABOVE0_9_7 } { Is called wc to avoid recursive calling. } Procedure wc(Len : Longint;var t : TextRec;b : Boolean);[Public,Alias: 'WRITE_TEXT_BOOLEAN']; const BoolString:array[0..1] Of String[5]=('False','True'); Begin w(Len,t,String(BoolString[byte(b)])); End; Procedure wc(Len : Longint;var t : TextRec;c : Char);[Public,Alias: 'WRITE_TEXT_CHAR']; var hs : String; Begin If t.mode<>fmOutput Then exit; If Len>1 Then Begin hs:=Space(Len-1); w(0,t,hs); End; If t.BufPos+1>=t.BufSize Then FileFunc(t.FlushFunc)(t); t.Bufptr^[t.BufPos]:=c; Inc(t.BufPos); End; {***************************************************************************** Read(Ln) *****************************************************************************} Function OpenInput(var f:TextRec):boolean; begin If f.mode=fmInput Then begin { No characters in the buffer? Load them ! } If f.BufPos>=f.BufEnd Then FileFunc(f.InOutFunc)(f); OpenInput:=true; end else OpenInput:=false; end; Function NextChar(var f:TextRec;var s:string):Boolean; begin if f.BufPos=f.BufEnd Then FileFunc(f.InOutFunc)(f); NextChar:=true; end else NextChar:=false; end; Function IgnoreSpaces(var f:TextRec):Boolean; { Removes all leading spaces,tab,eols from the input buffer, returns true if the buffer is empty } var s : string; begin s:=''; IgnoreSpaces:=false; while f.Bufptr^[f.BufPos] in [#9,#10,#13,' '] do if not NextChar(f,s) then exit; IgnoreSpaces:=true; end; Function ReadSign(var f:TextRec;var s:string):Boolean; { Read + and - sign, return true if buffer is empty } begin ReadSign:=(not (f.Bufptr^[f.BufPos] in ['-','+'])) or NextChar(f,s); end; Function ReadBase(var f:TextRec;var s:string;var Base:longint):boolean; { Read the base $ For 16 and % For 2, if buffer is empty return true } begin case f.BufPtr^[f.BufPos] of '$' : Base:=16; '%' : Base:=2; else Base:=10; end; ReadBase:=(Base=10) or NextChar(f,s); end; Function ReadNumeric(var f:TextRec;var s:string;base:longint):Boolean; { Read numeric input, if buffer is empty then return True } var c : char; begin ReadNumeric:=false; c:=f.BufPtr^[f.BufPos]; while ((base>=10) and (c in ['0'..'9'])) or ((base=16) and (c in ['A'..'F','a'..'f'])) or ((base=2) and (c in ['0'..'1'])) do begin if not NextChar(f,s) then exit; c:=f.BufPtr^[f.BufPos]; end; ReadNumeric:=true; end; Procedure r(var f : TextRec);[Public,Alias: 'READLN_TEXT']; Begin if not OpenInput(f) then exit; while (f.BufPos=f.BufEnd Then FileFunc(f.InOutFunc)(f); end; End; Procedure r(var f : TextRec;var s : String);[Public,Alias: 'READ_TEXT_STRING']; var Temp,sPos : Word; Begin { Delete the string } s:=''; if not OpenInput(f) then exit; Temp:=f.BufPos; sPos:=1; while (f.BufPos#10) Do Begin { search linefeed } while (f.Bufptr^[Temp]<>#10) and (Temp=f.BufEnd Then Begin FileFunc(f.InOutFunc)(f); Temp:=f.BufPos; End End; s[0]:=chr(sPos-1); End; Procedure r(var f : TextRec;var c : Char);[Public,Alias: 'READ_TEXT_CHAR']; Begin c:=#0; if not OpenInput(f) then exit; If f.BufPos>=f.BufEnd Then c:=#26 else c:=f.Bufptr^[f.BufPos]; Inc(f.BufPos); End; Procedure r(var f : TextRec;var s : PChar);[Public,Alias:'READ_TEXT_PCHAR_AS_POINTER']; var p : PChar; Temp : byte; Begin { Delete the string } s^:=#0; p:=s; if not OpenInput(f) then exit; Temp:=f.BufPos; while (f.BufPos#10) Do Begin { search linefeed } while (f.Bufptr^[Temp]<>#10) and (Temp=f.BufEnd Then Begin FileFunc(f.InOutFunc)(f); Temp:=f.BufPos; End End; p^:=#0; End; Procedure r(var f : TextRec;var l : Longint);[Public,Alias: 'READ_TEXT_LONGINT']; var hs : String; code : Word; base : longint; Begin l:=0; hs:=''; if not OpenInput(f) then exit; if IgnoreSpaces(f) and ReadSign(f,hs) and ReadBase(f,hs,Base) then ReadNumeric(f,hs,Base); Val(hs,l,code); If code<>0 Then RunError(106); End; Procedure r(var f : TextRec;var l : Integer);[Public,Alias: 'READ_TEXT_INTEGER']; var ll : Longint; Begin r(f,ll); l:=0; If (ll<-32768) or (ll>32767) Then RunError(106); l:=ll; End; Procedure r(var f : TextRec;var l : Word);[Public,Alias: 'READ_TEXT_WORD']; var ll : Longint; Begin r(f,ll); l:=0; If (ll<0) or (ll>$ffff) Then RunError(106); l:=ll; End; Procedure r(var f : TextRec;var l : byte);[Public,Alias: 'READ_TEXT_BYTE']; var ll : Longint; Begin r(f,ll); l:=0; If (ll<0) or (ll>255) Then RunError(106); l:=ll; End; Procedure r(var f : TextRec;var l : shortint);[Public,Alias: 'READ_TEXT_SHORTINT']; var ll : Longint; Begin r(f,ll); l:=0; If (ll<-128) or (ll>127) Then RunError(106); l:=ll; End; {$IFDEF VER_ABOVE0_9_8} Procedure r(var f : TextRec;var l : cardinal);[Public,Alias: 'READ_TEXT_CARDINAL']; var hs : String; code : Word; base : longint; Begin l:=0; hs:=''; if not OpenInput(f) then exit; if IgnoreSpaces(f) and ReadSign(f,hs) and ReadBase(f,hs,Base) then ReadNumeric(f,hs,Base); val(hs,l,code); If code<>0 Then RunError(106); End; {$ENDIF VER_ABOVE0_9_8} Procedure r(var f : TextRec;var d : Real);[Public,Alias: 'READ_TEXT_REAL']; var hs : String; code : Word; Begin d:=0.0; hs:=''; if not OpenInput(f) then exit; if IgnoreSpaces(f) and ReadSign(f,hs) and ReadNumeric(f,hs,10) then begin { First check for a . } if (f.Bufptr^[f.BufPos]='.') and (f.BufPos=f.BufEnd Then FileFunc(f.InOutFunc)(f); ReadNumeric(f,hs,10); end; { Also when a point is found check for a E } if (f.Bufptr^[f.BufPos] in ['e','E']) and (f.BufPos=f.BufEnd Then FileFunc(f.InOutFunc)(f); if ReadSign(f,hs) then ReadNumeric(f,hs,10); end; end; val(hs,d,code); If code<>0 Then RunError(106); End; {$ifdef ieee_support} Procedure r(var f : TextRec;var d : extended);[Public,Alias: 'READ_TEXT_EXTENDED']; var hs : String; code : Word; Begin d:=0.0; hs:=''; if not OpenInput(f) then exit; if IgnoreSpaces(f) and ReadSign(f,hs) and ReadNumeric(f,hs,10) then begin { First check for a . } if (f.Bufptr^[f.BufPos]='.') and (f.BufPos=f.BufEnd Then FileFunc(f.InOutFunc)(f); ReadNumeric(f,hs,10); end; { Also when a point is found check for a E } if (f.Bufptr^[f.BufPos] in ['e','E']) and (f.BufPos=f.BufEnd Then FileFunc(f.InOutFunc)(f); if ReadSign(f,hs) then ReadNumeric(f,hs,10); end; end; val(hs,d,code); If code<>0 Then RunError(106); End; {$endif ieee_support} {$ifdef comp_support} Procedure r(var f : TextRec;var d : comp);[Public,Alias: 'READ_TEXT_COMP']; var hs : String; code : Word; Begin d:=0.0; hs:=''; if not OpenInput(f) then exit; if IgnoreSpaces(f) and ReadSign(f,hs) and ReadNumeric(f,hs,10) then begin { First check for a . } if (f.Bufptr^[f.BufPos]='.') and (f.BufPos=f.BufEnd Then FileFunc(f.InOutFunc)(f); ReadNumeric(f,hs,10); end; { Also when a point is found check for a E } if (f.Bufptr^[f.BufPos] in ['e','E']) and (f.BufPos=f.BufEnd Then FileFunc(f.InOutFunc)(f); if ReadSign(f,hs) then ReadNumeric(f,hs,10); end; end; val(hs,d,code); If code<>0 Then RunError(106); End; {$endif} { $Log$ Revision 1.4 1998-04-07 22:40:46 florian * final fix of comp writing Revision 1.3 1998/04/04 17:06:17 michael * fixed initialization bug in assign. Revision 1.2 1998/03/26 14:41:22 michael + Added comp support for val and read(ln) Revision 1.1.1.1 1998/03/25 11:18:43 root * Restored version Revision 1.13 1998/03/19 12:00:42 pierre * missing write for comp fixed was just a conditionnal mistyping !! Revision 1.12 1998/03/16 23:36:37 peter * fixed read(real) for a value with a . and a E Revision 1.11 1998/02/23 14:43:23 carl * bugfix of reading reals for non-i386 processors Revision 1.10 1998/02/23 02:19:53 carl * bugfix of writing real under non-i386 processors. Revision 1.9 1998/02/12 11:05:27 michael * fixed printing of cardinals Revision 1.8 1998/02/04 09:54:22 michael * fixed bug in reading of numeric input Revision 1.7 1998/01/27 17:46:10 peter * previous commit was the wrong file :( Revision 1.6 1998/01/27 12:46:06 peter * Fixed readln() from file which was broken after previous fix Revision 1.5 1998/01/27 10:56:12 peter * Readln; works again Revision 1.4 1998/01/26 12:00:28 michael + Added log at the end revision 1.3 date: 1998/01/25 21:53:30; author: peter; state: Exp; lines: +9 -7 + Universal Handles support for StdIn/StdOut/StdErr * Updated layout of sysamiga.pas revision 1.2 date: 1998/01/12 02:32:36; author: carl; state: Exp; lines: +5 -3 + portability stuff (mainly FPU related) revision 1.1 date: 1998/01/11 02:43:10; author: michael; state: Exp; + Initial implementation of these files (by Peter Vreman). file operations are now in separate files per type of file. }