(* FileSystem.mod provides a PIM [234] FileSystem module. Copyright (C) 2004-2023 Free Software Foundation, Inc. Contributed by Gaius Mulley . This file is part of GNU Modula-2. GNU Modula-2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNU Modula-2 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. See the GNU General Public License for more details. Under Section 7 of GPL version 3, you are granted additional permissions described in the GCC Runtime Library Exception, version 3.1, as published by the Free Software Foundation. You should have received a copy of the GNU General Public License and a copy of the GCC Runtime Library Exception along with this program; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . *) IMPLEMENTATION MODULE FileSystem ; FROM M2RTS IMPORT InstallTerminationProcedure ; FROM Storage IMPORT ALLOCATE ; FROM SYSTEM IMPORT WORD, BYTE, ADDRESS, ADR ; IMPORT FIO, SFIO, libc, wrapc ; FROM DynamicStrings IMPORT String, InitString, ConCat, ConCatChar, KillString, string ; FROM FormatStrings IMPORT Sprintf2 ; CONST TMPDIR = '/tmp' ; DIRSEP = '/' ; SEEK_SET = 0 ; (* seek relative to from beginning of the file *) TYPE FileList = POINTER TO RECORD next : FileList ; n : String ; stillTemp: BOOLEAN ; END ; VAR HeadOfTemp: FileList ; tempNo : CARDINAL ; (* Create - creates a temporary file. To make the file perminant the file must be renamed. *) PROCEDURE Create (VAR f: File) ; BEGIN WITH f DO flags := FlagSet{write, temporary} ; eof := FALSE ; lastWord := WORD(0) ; lastByte := CHAR(0) ; name := MakeTemporary() ; fio := SFIO.OpenToWrite(name) ; IF FIO.IsNoError(fio) THEN res := done ELSE res := notdone END ; highpos := 0 ; lowpos := 0 END END Create ; (* Close - closes an open file. *) PROCEDURE Close (f: File) ; BEGIN WITH f DO eof := TRUE ; FIO.Close(fio) ; IF FIO.IsNoError(fio) THEN res := done ELSE res := notdone END ; IF temporary IN flags THEN deleteFile(name, f) END ; name := KillString(name) END END Close ; (* Lookup - looks for a file, filename. If the file is found then, f, is opened. If it is not found and, newFile, is TRUE then a new file is created and attached to, f. If, newFile, is FALSE and no file was found then f.res is set to notdone. *) PROCEDURE Lookup (VAR f: File; filename: ARRAY OF CHAR; newFile: BOOLEAN) ; BEGIN WITH f DO flags := FlagSet{} ; IF FIO.Exists(filename) THEN fio := FIO.OpenToRead(filename) ; INCL(flags, read) ; res := done ELSIF newFile THEN fio := FIO.OpenToWrite(filename) ; INCL(flags, write) ; res := done ELSE res := notdone END ; name := InitString(filename) ; eof := FALSE ; highpos := 0 ; lowpos := 0 END END Lookup ; (* Rename - rename a file and change a temporary file to a permanent file. f.res is set appropriately. *) PROCEDURE Rename (VAR f: File; newname: ARRAY OF CHAR) ; VAR s: String ; r: INTEGER ; BEGIN s := InitString(newname) ; WITH f DO r := libc.rename(string(name), string(s)) ; IF r=0 THEN res := done ELSE res := notdone END ; EXCL(flags, temporary) ; name := KillString(name) ; name := s END END Rename ; (* deleteFile - deletes file, name. It also kills the string, name. *) PROCEDURE deleteFile (VAR name: String; VAR f: File) ; VAR r: INTEGER ; BEGIN r := libc.unlink(string(name)) ; IF r=0 THEN f.res := done ELSE f.res := notdone END ; name := KillString(name) ; name := NIL END deleteFile ; (* Delete - deletes a file, name, and sets the f.res field. f.res is set appropriately. *) PROCEDURE Delete (name: ARRAY OF CHAR; VAR f: File) ; VAR s: String ; BEGIN s := InitString(name) ; deleteFile(s, f) ; s := KillString(s) END Delete ; (* ReadWord - reads a WORD, w, from file, f. f.res is set appropriately. *) PROCEDURE ReadWord (VAR f: File; VAR w: WORD) ; VAR n: CARDINAL ; BEGIN WITH f DO IF again IN flags THEN w := lastWord ; EXCL(flags, again) ELSE ReadNBytes(f, ADR(w), SIZE(w), n) ; IF n=SIZE(w) THEN res := done ELSE res := notdone ; eof := TRUE END END END END ReadWord ; (* WriteWord - writes one word to a file, f. f.res is set appropriately. *) PROCEDURE WriteWord (VAR f: File; w: WORD) ; VAR n: CARDINAL ; BEGIN WriteNBytes(f, ADR(w), SIZE(w), n) ; WITH f DO IF n=SIZE(w) THEN res := done ELSE res := notdone END END END WriteWord ; (* ReadChar - reads one character from a file, f. *) PROCEDURE ReadChar (VAR f: File; VAR ch: CHAR) ; VAR n: CARDINAL ; BEGIN WITH f DO IF again IN flags THEN ch := CHAR(lastByte) ; EXCL(flags, again) ELSE ReadNBytes(f, ADR(ch), SIZE(ch), n) ; IF n=SIZE(ch) THEN res := done ; lastByte := BYTE(ch) ELSE res := notdone ; eof := TRUE END END END END ReadChar ; (* WriteChar - writes a character, ch, to a file, f. f.res is set appropriately. *) PROCEDURE WriteChar (VAR f: File; ch: CHAR) ; VAR n: CARDINAL ; BEGIN WriteNBytes(f, ADR(ch), SIZE(ch), n) ; WITH f DO IF n=SIZE(ch) THEN res := done ELSE res := notdone END END END WriteChar ; (* ReadByte - reads a BYTE, b, from file, f. f.res is set appropriately. *) PROCEDURE ReadByte (VAR f: File; VAR b: BYTE) ; VAR n: CARDINAL ; BEGIN WITH f DO IF again IN flags THEN b := lastByte ; EXCL(flags, again) ELSE ReadNBytes(f, ADR(b), SIZE(b), n) ; IF n=SIZE(b) THEN res := done ; lastByte := b ELSE res := notdone ; eof := TRUE END END END END ReadByte ; (* WriteByte - writes one BYTE, b, to a file, f. f.res is set appropriately. *) PROCEDURE WriteByte (VAR f: File; b: BYTE) ; VAR n: CARDINAL ; BEGIN WriteNBytes(f, ADR(b), SIZE(b), n) ; WITH f DO IF n=SIZE(b) THEN res := done ELSE res := notdone END END END WriteByte ; (* ReadNBytes - reads a sequence of bytes from a file, f. *) PROCEDURE ReadNBytes (VAR f: File; a: ADDRESS; amount: CARDINAL; VAR actuallyRead: CARDINAL) ; BEGIN WITH f DO IF amount>0 THEN actuallyRead := FIO.ReadNBytes(fio, amount, a) ; IF FIO.IsNoError(fio) THEN res := done ; IF MAX(CARDINAL)-lowpos0 THEN actuallyWritten := FIO.WriteNBytes(fio, amount, a) ; IF FIO.IsNoError(fio) THEN res := done ; IF MAX(CARDINAL)-lowpos