| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870 |
- IMPLEMENTATION MODULE FileIO;
- (* ISO (GPM) version by Pat Terry. Sat 04-25-98 p.terry@ru.ac.za *)
- (* This module attempts to provide several potentially non-portable
- facilities for Coco/R.
- (a) A general file input/output module, with all routines required for
- Coco/R itself, as well as several other that would be useful in
- Coco-generated applications.
- (b) Definition of the "LONGINT" type needed by Coco.
- (c) Some conversion functions to handle this long type.
- (d) Some "long" and other constant literals that may be problematic
- on some implementations.
- (e) Some string handling primitives needed to interface to a variety
- of known implementations.
- The intention is that the rest of the code of Coco and its generated
- parsers should be as portable as possible. Provided the definition
- module given, and the associated implementation, satisfy the
- specification given here, this should be almost 100% possible.
- FileIO is based on code by MB 1990/11/25; heavily modified and extended
- by PDT and others between 1992/1/6 and the present day. *)
- IMPORT SYSTEM, Strings, SysClock, ProgramArgs, TextIO, RawIO, WholeIO,
- IOChan, IOResult, RndFile, TermFile, StdChans, ChanConsts,Environment, FIO, FileSystem;
- FROM Storage IMPORT ALLOCATE, DEALLOCATE;
- CONST
- MaxFiles = BitSetSize;
- NameLength = 256;
- TYPE
- File = POINTER TO FileRec;
- FileRec = RECORD
- ref: IOChan.ChanId;
- self: File;
- handle: CARDINAL;
- savedCh: CHAR;
- textOK, eof, eol, noOutput, noInput, haveCh: BOOLEAN;
- name: ARRAY [0 .. NameLength] OF CHAR;
- END;
- VAR
- Handles: BITSET;
- Opened: ARRAY [0 .. MaxFiles-1] OF File;
- FromKeyboard, ToScreen: BOOLEAN;
- res: ChanConsts.OpenResults;
- PROCEDURE NotRead (f: File): BOOLEAN;
- BEGIN
- RETURN (f = NIL) OR (f^.self # f) OR (f^.noInput);
- END NotRead;
- PROCEDURE NotWrite (f: File): BOOLEAN;
- BEGIN
- RETURN (f = NIL) OR (f^.self # f) OR (f^.noOutput);
- END NotWrite;
- PROCEDURE NotFile (f: File): BOOLEAN;
- BEGIN
- RETURN (f = NIL) OR (f^.self # f) OR (f = con) OR (f = err)
- OR (f = StdIn) & FromKeyboard
- OR (f = StdOut) & ToScreen
- END NotFile;
- PROCEDURE CheckRedirection;
- BEGIN
- FromKeyboard := TRUE; ToScreen := TRUE; (* ISO fail safe *)
- (* Ideally we would like
- FromKeyboard := NOT (StdIn has been redirected )
- ToScreen := NOT (StdOut has been redirected )
- *)
- END CheckRedirection;
- PROCEDURE ASCIIZ (VAR s1, s2: ARRAY OF CHAR);
- (* Convert s2 to a nul terminated string in s1 *)
- VAR
- i: CARDINAL;
- BEGIN
- i := 0;
- WHILE (i <= HIGH(s2)) & (s2[i] # 0C) DO
- s1[i] := s2[i]; INC(i)
- END;
- s1[i] := 0C
- END ASCIIZ;
- PROCEDURE NextParameter (VAR s: ARRAY OF CHAR);
- BEGIN
- IF ProgramArgs.IsArgPresent()
- THEN
- TextIO.ReadToken(ProgramArgs.ArgChan(), s);
- ProgramArgs.NextArg()
- ELSE s[0] := 0C
- END
- END NextParameter;
- PROCEDURE GetEnv (envVar: ARRAY OF CHAR; VAR s: ARRAY OF CHAR);
- VAR
- result : BOOLEAN;
- BEGIN
- result := Environment.GetEnvironment(envVar, s);
- END GetEnv;
- PROCEDURE Open (VAR f: File; fileName: ARRAY OF CHAR; newFile: BOOLEAN);
- VAR
- i: CARDINAL;
- name: ARRAY [0 .. NameLength] OF CHAR;
- BEGIN
- ExtractFileName(fileName, name);
- FOR i := 0 TO NameLength - 1 DO name[i] := CAP(name[i]) END;
- IF (name[0] = 0C) OR (Compare(name, "CON") = 0) THEN
- (* con already opened, but reset it *)
- Okay := TRUE; f := con;
- f^.savedCh := 0C; f^.haveCh := FALSE;
- f^.eof := FALSE; f^.eol := FALSE; f^.name := "CON";
- RETURN
- ELSIF Compare(name, "ERR") = 0 THEN
- Okay := TRUE; f := err; RETURN
- ELSE
- ALLOCATE(f, SYSTEM.TSIZE(FileRec));
- (* Flags below may have to be altered according to implementation *)
- IF newFile
- THEN RndFile.OpenClean(f^.ref, fileName,
- RndFile.old (* + RndFile.text *) + RndFile.raw, res)
- ELSE RndFile.OpenOld(f^.ref, fileName,
- RndFile.read (* + RnfDile.text *) +RndFile.raw, res)
- END;
- Okay := res = RndFile.opened;
- IF ~ Okay
- THEN
- DEALLOCATE(f, SYSTEM.TSIZE(FileRec)); f := NIL
- ELSE
- (* textOK below may have to be altered according to implementation *)
- f^.savedCh := 0C; f^.haveCh := FALSE; f^.textOK := FALSE;
- f^.eof := newFile; f^.eol := newFile; f^.self := f;
- f^.noInput := newFile; f^.noOutput := ~ newFile;
- ASCIIZ(f^.name, fileName);
- i := 0 (* find next available filehandle *);
- WHILE (i IN Handles) & (i < MaxFiles) DO INC(i) END;
- IF i < MaxFiles
- THEN f^.handle := i; INCL(Handles, i); Opened[i] := f
- ELSE WriteString(err, "Too many files"); Okay := FALSE
- END;
- END
- END
- END Open;
- PROCEDURE Close (VAR f: File);
- BEGIN
- Okay := TRUE;
- IF NotFile(f) OR (f = StdIn) OR (f = StdOut)
- THEN Okay := FALSE
- ELSE
- EXCL(Handles, f^.handle);
- RndFile.Close(f^.ref);
- IF Okay THEN DEALLOCATE(f, SYSTEM.TSIZE(FileRec)) END;
- f := NIL
- END;
- (*
- EXCEPT (* For ISO compilers *)
- Okay := FALSE; f := NIL; RETURN
- *)
- END Close;
- PROCEDURE Delete (VAR f: File);
- (*
- FileSystem
- PROCEDURE Delete (name: ARRAY OF CHAR; VAR f: File) ;
- *)
- VAR
- fname : ARRAY [0 .. NameLength] OF CHAR;
-
- BEGIN
- IF NotFile(f) OR (f = StdIn) OR (f = StdOut)
- THEN Okay := FALSE
- ELSE
- Assign(f^.name, fname);
- Close(f);
- FileSystem.Delete(fname,f);
- (*Okay := f^. *)
- END
- END Delete;
- PROCEDURE SearchFile (VAR f: File; envVar, fileName: ARRAY OF CHAR;
- newFile: BOOLEAN);
- VAR
- i, j: INTEGER;
- k: CARDINAL;
- c: CHAR;
- fname: ARRAY [0 .. NameLength] OF CHAR;
- path: ARRAY [0 .. NameLength] OF CHAR;
- BEGIN
- FOR k := 0 TO HIGH(envVar) DO envVar[k] := CAP(envVar[k]) END;
- GetEnv(envVar, path);
- i := 0;
- REPEAT
- j := 0;
- REPEAT
- c := path[i]; fname[j] := c; INC(i); INC(j)
- UNTIL (c = PathSep) OR (c = 0C);
- IF (j > 1) & (fname[j-2] = DirSep) THEN DEC(j) ELSE fname[j-1] := DirSep END;
- fname[j] := 0C; Concat(fname, fileName, fname);
- Open(f, fname, newFile);
- UNTIL (c = 0C) OR Okay
- END SearchFile;
- PROCEDURE ExtractDirectory (fullName: ARRAY OF CHAR;
- VAR directory: ARRAY OF CHAR);
- VAR
- i, start: CARDINAL;
- BEGIN
- start := 0; i := 0;
- WHILE (i <= HIGH(fullName)) & (fullName[i] # 0C) DO
- IF i <= HIGH(directory) THEN
- directory[i] := fullName[i];
- END;
- IF (fullName[i] = ":") OR (fullName[i] = DirSep) THEN start := i + 1 END;
- INC(i)
- END;
- IF start <= HIGH(directory) THEN directory[start] := 0C END
- END ExtractDirectory;
- PROCEDURE ExtractFileName (fullName: ARRAY OF CHAR;
- VAR fileName: ARRAY OF CHAR);
- VAR
- i, l, start: CARDINAL;
- BEGIN
- start := 0; l := 0;
- WHILE (l <= HIGH(fullName)) & (fullName[l] # 0C) DO
- IF (fullName[l] = ":") OR (fullName[l] = DirSep) THEN start := l + 1 END;
- INC(l)
- END;
- i := 0;
- WHILE (start < l) & (i <= HIGH(fileName)) DO
- fileName[i] := fullName[start]; INC(start); INC(i)
- END;
- IF i <= HIGH(fileName) THEN fileName[i] := 0C END
- END ExtractFileName;
- PROCEDURE AppendExtension (oldName, ext: ARRAY OF CHAR;
- VAR newName: ARRAY OF CHAR);
- VAR
- i, j: CARDINAL;
- fn: ARRAY [0 .. NameLength] OF CHAR;
- BEGIN
- ExtractDirectory(oldName, newName);
- ExtractFileName(oldName, fn);
- i := 0; j := 0;
- WHILE (i <= NameLength) & (fn[i] # 0C) DO
- IF fn[i] = "." THEN j := i + 1 END;
- INC(i)
- END;
- IF (j # i) (* then name did not end with "." *) OR (i = 0) THEN
- IF j # 0 THEN i := j - 1 END;
- IF (ext[0] # ".") & (ext[0] # 0C) THEN
- IF i <= NameLength THEN fn[i] := "."; INC(i) END
- END;
- j := 0;
- WHILE (j <= HIGH(ext)) & (ext[j] # 0C) & (i <= NameLength) DO
- fn[i] := ext[j]; INC(i); INC(j)
- END
- END;
- IF i <= NameLength THEN fn[i] := 0C END;
- Concat(newName, fn, newName)
- END AppendExtension;
- PROCEDURE ChangeExtension (oldName, ext: ARRAY OF CHAR;
- VAR newName: ARRAY OF CHAR);
- VAR
- i, j: CARDINAL;
- fn: ARRAY [0 .. NameLength] OF CHAR;
- BEGIN
- ExtractDirectory(oldName, newName);
- ExtractFileName(oldName, fn);
- i := 0; j := 0;
- WHILE (i <= NameLength) & (fn[i] # 0C) DO
- IF fn[i] = "." THEN j := i + 1 END;
- INC(i)
- END;
- IF j # 0 THEN i := j - 1 END;
- IF (ext[0] # ".") & (ext[0] # 0C) THEN
- IF i <= NameLength THEN fn[i] := "."; INC(i) END
- END;
- j := 0;
- WHILE (j <= HIGH(ext)) & (ext[j] # 0C) & (i <= NameLength) DO
- fn[i] := ext[j]; INC(i); INC(j)
- END;
- IF i <= NameLength THEN fn[i] := 0C END;
- Concat(newName, fn, newName)
- END ChangeExtension;
- PROCEDURE Length (f: File): INT32;
- (* ++++ implementation specific coercion routine may have to be used ++++ *)
- VAR
- pos: RndFile.FilePos;
- BEGIN
- IF NotFile(f) THEN
- Okay := FALSE;
- RETURN Long0
- ELSE
- Okay := TRUE;
- FIO.SetPositionFromEnd(f^.ref,0);
- RETURN VAL(INT32,FIO.FindPosition(f^.ref))
- END;
- END Length;
- PROCEDURE GetPos (f: File): INT32;
- (* ++++ implementation specific coercion routine may have to be used ++++ *)
- VAR
- pos: RndFile.FilePos;
- BEGIN
- IF NotFile(f) THEN
- Okay := FALSE;
- RETURN Long0
- ELSE
- Okay := TRUE;
- RETURN VAL(INT32,FIO.FindPosition(f^.ref))
- END;
- END GetPos;
- PROCEDURE SetPos (f: File; pos: INT32);
- (* ++++ implementation specific coercion routine may have to be used ++++ *)
- BEGIN
- IF NotFile(f)
- THEN
- Okay := FALSE
- ELSE
- Okay := TRUE; f^.haveCh := FALSE;
- FIO.SetPositionFromBeginning(f^.ref,VAL(LONGINT,pos));
- END;
- END SetPos;
- PROCEDURE Reset (f: File);
- BEGIN
- IF NotFile(f)
- THEN
- Okay := FALSE
- ELSE
- SetPos(f, 0);
- IF Okay THEN
- f^.haveCh := FALSE; f^.eof := f^.noInput; f^.eol := f^.noInput
- END
- END
- END Reset;
- PROCEDURE Rewrite (f: File);
- BEGIN
- IF NotFile(f)
- THEN
- Okay := FALSE
- ELSE
- RndFile.Close(f^.ref);
- (* Flags below may have to be altered according to implementation *)
- RndFile.OpenClean(f^.ref, f^.name,
- RndFile.old + (* RndFile.text + *) RndFile.raw, res);
- Okay := res = RndFile.opened;
- IF ~ Okay
- THEN
- DEALLOCATE(f, SYSTEM.TSIZE(FileRec)); f := NIL
- ELSE
- f^.savedCh := 0C; f^.haveCh := FALSE;
- f^.eof := TRUE; f^.eol := TRUE;
- f^.noInput := TRUE; f^.noOutput := FALSE;
- END
- END;
- (*
- EXCEPT (* For ISO compilers *)
- Okay := FALSE; RETURN
- *)
- END Rewrite;
- PROCEDURE EndOfLine (f: File): BOOLEAN;
- BEGIN
- IF NotRead(f)
- THEN Okay := FALSE; RETURN TRUE
- ELSE Okay := TRUE; RETURN f^.eol OR f^.eof
- END
- END EndOfLine;
- PROCEDURE EndOfFile (f: File): BOOLEAN;
- BEGIN
- IF NotRead(f)
- THEN Okay := FALSE; RETURN TRUE
- ELSE Okay := TRUE; RETURN f^.eof
- END
- END EndOfFile;
- PROCEDURE Read (f: File; VAR ch: CHAR);
- BEGIN
- IF NotRead(f) THEN Okay := FALSE; ch := 0C; RETURN END;
- IF f^.haveCh OR f^.eof
- THEN
- ch := f^.savedCh; Okay := ch # 0C;
- ELSE
- Okay := TRUE;
- IF ~ f^.textOK (* Work around as best one can *)
- THEN RawIO.Read(f^.ref, ch)
- ELSE TextIO.ReadChar(f^.ref, ch);
- END;
- IF f^.textOK & (IOResult.ReadResult(f^.ref) = IOResult.endOfLine)
- THEN TextIO.SkipLine(f^.ref); ch := EOL
- ELSIF ch = LF (* Work around possible bug *) THEN ch := EOL
- END;
- IF IOResult.ReadResult(f^.ref) = IOResult.endOfInput THEN
- Okay := FALSE; ch := 0C;
- END;
- IF ch = EOFChar THEN Okay := FALSE; ch := 0C END;
- END;
- IF ~ Okay THEN ch := 0C END;
- f^.savedCh := ch; f^.haveCh := ~ Okay;
- f^.eof := ch = 0C; f^.eol := f^.eof OR (ch = EOL);
- END Read;
- PROCEDURE ReadAgain (f: File);
- BEGIN
- IF NotRead(f)
- THEN Okay := FALSE
- ELSE f^.haveCh := TRUE
- END
- END ReadAgain;
- PROCEDURE ReadLn (f: File);
- VAR
- ch: CHAR;
- BEGIN
- IF NotRead(f) THEN Okay := FALSE; RETURN END;
- WHILE ~ f^.eol DO Read(f, ch) END;
- f^.haveCh := FALSE; f^.eol := FALSE;
- END ReadLn;
- PROCEDURE ReadString (f: File; VAR str: ARRAY OF CHAR);
- VAR
- j: CARDINAL;
- ch: CHAR;
- BEGIN
- str[0] := 0C; j := 0;
- IF NotRead(f) THEN Okay := FALSE; RETURN END;
- REPEAT Read(f, ch) UNTIL (ch # " ") OR ~ Okay;
- IF Okay THEN
- WHILE ch >= " " DO
- IF j <= HIGH(str) THEN str[j] := ch END; INC(j);
- Read(f, ch);
- WHILE (ch = BS) OR (ch = DEL) DO
- IF j > 0 THEN DEC(j) END; Read(f, ch)
- END
- END;
- IF j <= HIGH(str) THEN str[j] := 0C END;
- Okay := j > 0; f^.haveCh := TRUE; f^.savedCh := ch;
- END
- END ReadString;
- PROCEDURE ReadLine (f: File; VAR str: ARRAY OF CHAR);
- VAR
- j: CARDINAL;
- ch: CHAR;
- BEGIN
- str[0] := 0C; j := 0;
- IF NotRead(f) THEN Okay := FALSE; RETURN END;
- Read(f, ch);
- IF Okay THEN
- WHILE ch >= " " DO
- IF j <= HIGH(str) THEN str[j] := ch END; INC(j);
- Read(f, ch);
- WHILE (ch = BS) OR (ch = DEL) DO
- IF j > 0 THEN DEC(j) END; Read(f, ch)
- END
- END;
- IF j <= HIGH(str) THEN str[j] := 0C END;
- Okay := j > 0; f^.haveCh := TRUE; f^.savedCh := ch;
- END
- END ReadLine;
- PROCEDURE ReadToken (f: File; VAR str: ARRAY OF CHAR);
- VAR
- j: CARDINAL;
- ch: CHAR;
- BEGIN
- str[0] := 0C; j := 0;
- IF NotRead(f) THEN Okay := FALSE; RETURN END;
- REPEAT Read(f, ch) UNTIL (ch > " ") OR ~ Okay;
- IF Okay THEN
- WHILE ch > " " DO
- IF j <= HIGH(str) THEN str[j] := ch END; INC(j);
- Read(f, ch);
- WHILE (ch = BS) OR (ch = DEL) DO
- IF j > 0 THEN DEC(j) END; Read(f, ch)
- END
- END;
- IF j <= HIGH(str) THEN str[j] := 0C END;
- Okay := j > 0; f^.haveCh := TRUE; f^.savedCh := ch;
- END
- END ReadToken;
- PROCEDURE ReadInt (f: File; VAR i: INTEGER);
- VAR
- Digit: INTEGER;
- j: CARDINAL;
- Negative: BOOLEAN;
- s: ARRAY [0 .. 80] OF CHAR;
- BEGIN
- i := 0; j := 0;
- IF NotRead(f) THEN Okay := FALSE; RETURN END;
- ReadToken(f, s);
- IF s[0] = "-" (* deal with sign *)
- THEN Negative := TRUE; INC(j)
- ELSE Negative := FALSE; IF s[0] = "+" THEN INC(j) END
- END;
- IF (s[j] < "0") OR (s[j] > "9") THEN Okay := FALSE END;
- WHILE (j <= 80) & (s[j] >= "0") & (s[j] <= "9") DO
- Digit := VAL(INTEGER, ORD(s[j]) - ORD("0"));
- IF i <= (MAX(INTEGER) - Digit) DIV 10
- THEN i := 10 * i + Digit
- ELSE Okay := FALSE
- END;
- INC(j)
- END;
- IF Negative THEN i := -i END;
- IF (j > 80) OR (s[j] # 0C) THEN Okay := FALSE END;
- IF ~ Okay THEN i := 0 END;
- END ReadInt;
- PROCEDURE ReadCard (f: File; VAR i: CARDINAL);
- VAR
- Digit: CARDINAL;
- j: CARDINAL;
- s: ARRAY [0 .. 80] OF CHAR;
- BEGIN
- i := 0; j := 0;
- IF NotRead(f) THEN Okay := FALSE; RETURN END;
- ReadToken(f, s);
- WHILE (j <= 80) & (s[j] >= "0") & (s[j] <= "9") DO
- Digit := ORD(s[j]) - ORD("0");
- IF i <= (MAX(CARDINAL) - Digit) DIV 10
- THEN i := 10 * i + Digit
- ELSE Okay := FALSE
- END;
- INC(j)
- END;
- IF (j > 80) OR (s[j] # 0C) THEN Okay := FALSE END;
- IF ~ Okay THEN i := 0 END;
- END ReadCard;
- PROCEDURE ReadBytes (f: File; VAR buf: ARRAY OF SYSTEM.BYTE; VAR len: CARDINAL);
- VAR
- TooMany: BOOLEAN;
- Wanted: CARDINAL;
- BEGIN
- IF NotRead(f) OR (f = con)
- THEN Okay := FALSE; len := 0;
- ELSE
- IF len = 0 THEN Okay := TRUE; RETURN END;
- TooMany := len - 1 > HIGH(buf);
- IF TooMany THEN Wanted := HIGH(buf) + 1 ELSE Wanted := len END;
- IOChan.RawRead(f^.ref, SYSTEM.ADR(buf), Wanted, Wanted);
- Okay := Wanted # 0;
- IF len # Wanted THEN Okay := FALSE END;
- len := Wanted;
- END;
- IF ~ Okay THEN f^.eof := TRUE END;
- IF TooMany THEN Okay := FALSE END;
- (*
- EXCEPT (* For ISO compilers *)
- Okay := FALSE; len := 0; RETURN
- *)
- END ReadBytes;
- PROCEDURE Write (f: File; ch: CHAR);
- BEGIN
- IF NotWrite(f) THEN Okay := FALSE; RETURN END;
- Okay := TRUE;
- IF ch = EOL
- THEN (* implementation may not support Text operations on all files *)
- IF f^.textOK
- THEN TextIO.WriteLn(f^.ref)
- ELSE ch := LF; RawIO.Write(f^.ref, ch)
- (* but you may have to write CR/LF or CR or LF *)
- END
- ELSE
- IF f^.textOK
- THEN TextIO.WriteChar(f^.ref, ch)
- ELSE RawIO.Write(f^.ref, ch)
- END
- END;
- (*
- EXCEPT (* For ISO compilers *)
- Okay := FALSE; RETURN
- *)
- END Write;
- PROCEDURE WriteLn (f: File);
- BEGIN
- IF NotWrite(f)
- THEN Okay := FALSE;
- ELSE Write(f, EOL)
- END
- END WriteLn;
- PROCEDURE WriteString (f: File; str: ARRAY OF CHAR);
- VAR
- pos: CARDINAL;
- BEGIN
- IF NotWrite(f) THEN Okay := FALSE; RETURN END;
- pos := 0;
- WHILE (pos <= HIGH(str)) & (str[pos] # 0C) DO
- Write(f, str[pos]); INC(pos)
- END
- END WriteString;
- PROCEDURE WriteText (f: File; text: ARRAY OF CHAR; len: INTEGER);
- VAR
- i, slen: INTEGER;
- BEGIN
- IF NotWrite(f) THEN Okay := FALSE; RETURN END;
- slen := LENGTH(text);
- FOR i := 0 TO len - 1 DO
- IF i < slen THEN Write(f, text[i]) ELSE Write(f, " ") END;
- END
- END WriteText;
- PROCEDURE WriteInt (f: File; n: INTEGER; wid: CARDINAL);
- VAR
- l, d: CARDINAL;
- x: INTEGER;
- t: ARRAY [1 .. 25] OF CHAR;
- sign: CHAR;
- BEGIN
- IF NotWrite(f) THEN Okay := FALSE; RETURN END;
- IF n < 0
- THEN sign := "-"; x := - n;
- ELSE sign := " "; x := n;
- END;
- l := 0;
- REPEAT
- d := x MOD 10; x := x DIV 10;
- INC(l); t[l] := CHR(ORD("0") + d);
- UNTIL x = 0;
- IF wid = 0 THEN Write(f, " ") END;
- WHILE wid > l + 1 DO Write(f, " "); DEC(wid); END;
- IF (sign = "-") OR (wid > l) THEN Write(f, sign); END;
- WHILE l > 0 DO Write(f, t[l]); DEC(l); END;
- END WriteInt;
- PROCEDURE WriteCard (f: File; n, wid: CARDINAL);
- VAR
- l, d: CARDINAL;
- t: ARRAY [1 .. 25] OF CHAR;
- BEGIN
- IF NotWrite(f) THEN Okay := FALSE; RETURN END;
- l := 0;
- REPEAT
- d := n MOD 10; n := n DIV 10;
- INC(l); t[l] := CHR(ORD("0") + d);
- UNTIL n = 0;
- IF wid = 0 THEN Write(f, " ") END;
- WHILE wid > l DO Write(f, " "); DEC(wid); END;
- WHILE l > 0 DO Write(f, t[l]); DEC(l); END;
- END WriteCard;
- PROCEDURE WriteBytes (f: File; VAR buf: ARRAY OF SYSTEM.BYTE; len: CARDINAL);
- VAR
- TooMany: BOOLEAN;
- BEGIN
- TooMany := (len > 0) & (len - 1 > HIGH(buf));
- IF NotWrite(f) OR (f = con) OR (f = err)
- THEN
- Okay := FALSE
- ELSE
- Okay := TRUE;
- IF TooMany THEN len := HIGH(buf) + 1 END;
- IOChan.RawWrite(f^.ref, SYSTEM.ADR(buf), len);
- END;
- IF TooMany THEN Okay := FALSE END;
- (*
- EXCEPT (* For ISO compilers *)
- Okay := FALSE; RETURN
- *)
- END WriteBytes;
- PROCEDURE GetDate (VAR Year, Month, Day: CARDINAL);
- VAR
- time: SysClock.DateTime;
- BEGIN
- SysClock.GetClock(time);
- Year := time.year;
- Month := time.month;
- Day := time.day;
- END GetDate;
- PROCEDURE GetTime (VAR Hrs, Mins, Secs, Hsecs: CARDINAL);
- VAR
- time: SysClock.DateTime;
- BEGIN
- SysClock.GetClock(time);
- Hrs := time.hour;
- Mins := time.minute;
- Secs := time.second;
- Hsecs := time.fractions;
- END GetTime;
- PROCEDURE Write2 (f: File; i: CARDINAL);
- BEGIN
- Write(f, CHR(i DIV 10 + ORD("0")));
- Write(f, CHR(i MOD 10 + ORD("0")));
- END Write2;
- PROCEDURE WriteDate (f: File);
- VAR
- Year, Month, Day: CARDINAL;
- BEGIN
- IF NotWrite(f) THEN Okay := FALSE; RETURN END;
- GetDate(Year, Month, Day);
- Write2(f, Day); Write(f, "/"); Write2(f, Month); Write(f, "/");
- WriteCard(f, Year, 1)
- END WriteDate;
- PROCEDURE WriteTime (f: File);
- VAR
- Hrs, Mins, Secs, Hsecs: CARDINAL;
- BEGIN
- IF NotWrite(f) THEN Okay := FALSE; RETURN END;
- GetTime(Hrs, Mins, Secs, Hsecs);
- Write2(f, Hrs); Write(f, ":"); Write2(f, Mins); Write(f, ":");
- Write2(f, Secs)
- END WriteTime;
- VAR
- Hrs0, Mins0, Secs0, Hsecs0: CARDINAL;
- Hrs1, Mins1, Secs1, Hsecs1: CARDINAL;
- PROCEDURE WriteElapsedTime (f: File);
- VAR
- Hrs, Mins, Secs, Hsecs, s, hs: CARDINAL;
- BEGIN
- IF NotWrite(f) THEN Okay := FALSE; RETURN END;
- GetTime(Hrs, Mins, Secs, Hsecs);
- WriteString(f, "Elapsed time: ");
- IF Hrs >= Hrs1
- THEN s := (Hrs - Hrs1) * 3600 + (Mins - Mins1) * 60 + Secs - Secs1
- ELSE s := (Hrs + 24 - Hrs1) * 3600 + (Mins - Mins1) * 60 + Secs - Secs1
- END;
- IF Hsecs >= Hsecs1
- THEN hs := Hsecs - Hsecs1
- ELSE hs := (Hsecs + 100) - Hsecs1; DEC(s);
- END;
- WriteCard(f, s, 1); Write(f, ".");
- Write2(f, hs); WriteString(f, " s"); WriteLn(f);
- Hrs1 := Hrs; Mins1 := Mins; Secs1 := Secs; Hsecs1 := Hsecs;
- END WriteElapsedTime;
- PROCEDURE WriteExecutionTime (f: File);
- VAR
- Hrs, Mins, Secs, Hsecs, s, hs: CARDINAL;
- BEGIN
- IF NotWrite(f) THEN Okay := FALSE; RETURN END;
- GetTime(Hrs, Mins, Secs, Hsecs);
- WriteString(f, "Execution time: ");
- IF Hrs >= Hrs0
- THEN s := (Hrs - Hrs0) * 3600 + (Mins - Mins0) * 60 + Secs - Secs0
- ELSE s := (Hrs + 24 - Hrs0) * 3600 + (Mins - Mins0) * 60 + Secs - Secs0
- END;
- IF Hsecs >= Hsecs0
- THEN hs := Hsecs - Hsecs0
- ELSE hs := (Hsecs + 100) - Hsecs0; DEC(s);
- END;
- WriteCard(f, s, 1); Write(f, "."); Write2(f, hs);
- WriteString(f, " s"); WriteLn(f);
- END WriteExecutionTime;
- (* The code for the next four procedures below may be commented out if your
- compiler supports ISO PROCEDURE constant declarations and these declarations
- are made in the DEFINITION MODULE *)
- PROCEDURE SLENGTH (stringVal: ARRAY OF CHAR): CARDINAL;
- BEGIN
- RETURN LENGTH(stringVal)
- END SLENGTH;
- PROCEDURE Assign (source: ARRAY OF CHAR; VAR destination: ARRAY OF CHAR);
- BEGIN
- (* Be careful - some libraries have the parameters reversed! *)
- Strings.Assign(source, destination)
- END Assign;
- PROCEDURE Extract (source: ARRAY OF CHAR; startIndex: CARDINAL;
- numberToExtract: CARDINAL; VAR destination: ARRAY OF CHAR);
- BEGIN
- Strings.Extract(source, startIndex, numberToExtract, destination)
- END Extract;
- PROCEDURE Concat (source1, source2: ARRAY OF CHAR; VAR destination: ARRAY OF CHAR);
- BEGIN
- Strings.Concat(source1, source2, destination);
- END Concat;
- (* The code for the four procedures above may be commented out if your
- compiler supports ISO PROCEDURE constant declarations and these declarations
- are made in the DEFINITION MODULE *)
- PROCEDURE Compare (stringVal1, stringVal2: ARRAY OF CHAR): INTEGER;
- BEGIN
- RETURN VAL(INTEGER, Strings.Compare(stringVal1, stringVal2)) - 1;
- END Compare;
- PROCEDURE ORDL (n: INT32): CARDINAL;
- BEGIN RETURN VAL(CARDINAL, n) END ORDL;
- PROCEDURE INTL (n: INT32): INTEGER;
- BEGIN RETURN VAL(INTEGER, n) END INTL;
- PROCEDURE INT (n: CARDINAL): INT32;
- BEGIN RETURN VAL(INT32, n) END INT;
- PROCEDURE CloseAll;
- VAR
- handle: CARDINAL;
- BEGIN
- FOR handle := 0 TO MaxFiles - 1 DO
- IF handle IN Handles THEN Close(Opened[handle]) END
- END;
- END CloseAll;
- PROCEDURE QuitExecution;
- BEGIN
- HALT
- END QuitExecution;
- BEGIN
- CheckRedirection; (* Not apparently available on many systems *)
- ProgramArgs.NextArg(); (* Not necessary on some systems *)
- GetTime(Hrs0, Mins0, Secs0, Hsecs0);
- Hrs1 := Hrs0; Mins1 := Mins0; Secs1 := Secs0; Hsecs1 := Hsecs0;
- Handles := BITSET{};
- Okay := FALSE; EOFChar := 04C;
- ALLOCATE(con, SYSTEM.TSIZE(FileRec));
- TermFile.Open(con^.ref, TermFile.read + TermFile.write + TermFile.text
- + TermFile.echo, res);
- con^.savedCh := 0C; con^.haveCh := FALSE; con^.self := con;
- con^.noOutput := FALSE; con^.noInput := FALSE; con^.textOK := TRUE;
- con^.eof := FALSE; con^.eol := FALSE;
- ALLOCATE(StdIn, SYSTEM.TSIZE(FileRec));
- StdIn^.ref := StdChans.StdInChan();
- StdIn^.savedCh := 0C; StdIn^.haveCh := FALSE; StdIn^.self := StdIn;
- StdIn^.noOutput := TRUE; StdIn^.noInput := FALSE; StdIn^.textOK := TRUE;
- StdIn^.eof := FALSE; StdIn^.eol := FALSE;
- ALLOCATE(StdOut, SYSTEM.TSIZE(FileRec));
- StdOut^.ref := StdChans.StdOutChan();
- StdOut^.savedCh := 0C; StdOut^.haveCh := FALSE; StdOut^.self := StdOut;
- StdOut^.noOutput := FALSE; StdOut^.noInput := TRUE; StdOut^.textOK := TRUE;
- StdOut^.eof := TRUE; StdOut^.eol := TRUE;
- ALLOCATE(err, SYSTEM.TSIZE(FileRec));
- err^.ref := StdChans.StdErrChan();
- err^.savedCh := 0C; err^.haveCh := FALSE; err^.self := err;
- err^.noOutput := FALSE; err^.noInput := TRUE; err^.textOK := TRUE;
- err^.eof := TRUE; err^.eol := TRUE;
- (*
- FINALLY (* For ISO compilers *)
- (* Preferably find some way to install CloseAll as an at-exit procedure *)
- CloseAll;
- *)
- END FileIO.
|