1 (* FileSystem.mod provides a PIM [234] FileSystem module.
3 Copyright (C) 2004-2021 Free Software Foundation, Inc.
4 Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
6 This file is part of GNU Modula-2.
8 GNU Modula-2 is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
13 GNU Modula-2 is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 Under Section 7 of GPL version 3, you are granted additional
19 permissions described in the GCC Runtime Library Exception, version
20 3.1, as published by the Free Software Foundation.
22 You should have received a copy of the GNU General Public License and
23 a copy of the GCC Runtime Library Exception along with this program;
24 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 <http://www.gnu.org/licenses/>. *)
27 IMPLEMENTATION MODULE FileSystem ;
29 FROM M2RTS IMPORT InstallTerminationProcedure ;
30 FROM Storage IMPORT ALLOCATE ;
31 FROM SYSTEM IMPORT WORD, BYTE, ADDRESS, ADR ;
32 IMPORT FIO, SFIO, libc, wrapc ;
33 FROM DynamicStrings IMPORT String, InitString, ConCat, ConCatChar, KillString, string ;
34 FROM FormatStrings IMPORT Sprintf2 ;
39 SEEK_SET = 0 ; (* seek relative to from beginning of the file *)
42 FileList = POINTER TO RECORD
49 HeadOfTemp: FileList ;
54 Create - creates a temporary file. To make the file perminant
55 the file must be renamed.
58 PROCEDURE Create (VAR f: File) ;
61 flags := FlagSet{write, temporary} ;
65 name := MakeTemporary() ;
66 fio := SFIO.OpenToWrite(name) ;
80 Close - closes an open file.
83 PROCEDURE Close (f: File) ;
98 name := KillString(name)
104 Lookup - looks for a file, filename. If the file is found
105 then, f, is opened. If it is not found and, newFile,
106 is TRUE then a new file is created and attached to, f.
107 If, newFile, is FALSE and no file was found then f.res
111 PROCEDURE Lookup (VAR f: File; filename: ARRAY OF CHAR; newFile: BOOLEAN) ;
115 IF FIO.Exists(filename)
117 fio := FIO.OpenToRead(filename) ;
122 fio := FIO.OpenToWrite(filename) ;
128 name := InitString(filename) ;
137 Rename - rename a file and change a temporary file to a permanent
138 file. f.res is set appropriately.
141 PROCEDURE Rename (VAR f: File; newname: ARRAY OF CHAR) ;
146 s := InitString(newname) ;
148 r := libc.rename(string(name), string(s)) ;
155 EXCL(flags, temporary) ;
156 name := KillString(name) ;
163 deleteFile - deletes file, name. It also kills the string, name.
166 PROCEDURE deleteFile (VAR name: String; VAR f: File) ;
170 r := libc.unlink(string(name)) ;
177 name := KillString(name) ;
183 Delete - deletes a file, name, and sets the f.res field.
184 f.res is set appropriately.
187 PROCEDURE Delete (name: ARRAY OF CHAR; VAR f: File) ;
191 s := InitString(name) ;
198 ReadWord - reads a WORD, w, from file, f.
199 f.res is set appropriately.
202 PROCEDURE ReadWord (VAR f: File; VAR w: WORD) ;
212 ReadNBytes(f, ADR(w), SIZE(w), n) ;
226 WriteWord - writes one word to a file, f.
227 f.res is set appropriately.
230 PROCEDURE WriteWord (VAR f: File; w: WORD) ;
234 WriteNBytes(f, ADR(w), SIZE(w), n) ;
247 ReadChar - reads one character from a file, f.
250 PROCEDURE ReadChar (VAR f: File; VAR ch: CHAR) ;
257 ch := CHAR(lastByte) ;
260 ReadNBytes(f, ADR(ch), SIZE(ch), n) ;
275 WriteChar - writes a character, ch, to a file, f.
276 f.res is set appropriately.
279 PROCEDURE WriteChar (VAR f: File; ch: CHAR) ;
283 WriteNBytes(f, ADR(ch), SIZE(ch), n) ;
296 ReadByte - reads a BYTE, b, from file, f.
297 f.res is set appropriately.
300 PROCEDURE ReadByte (VAR f: File; VAR b: BYTE) ;
310 ReadNBytes(f, ADR(b), SIZE(b), n) ;
325 WriteByte - writes one BYTE, b, to a file, f.
326 f.res is set appropriately.
329 PROCEDURE WriteByte (VAR f: File; b: BYTE) ;
333 WriteNBytes(f, ADR(b), SIZE(b), n) ;
346 ReadNBytes - reads a sequence of bytes from a file, f.
349 PROCEDURE ReadNBytes (VAR f: File; a: ADDRESS; amount: CARDINAL;
350 VAR actuallyRead: CARDINAL) ;
355 actuallyRead := FIO.ReadNBytes(fio, amount, a) ;
356 IF FIO.IsNoError(fio)
359 IF MAX(CARDINAL)-lowpos<actuallyRead
363 INC(lowpos, actuallyRead)
374 WriteNBytes - writes a sequence of bytes to file, f.
377 PROCEDURE WriteNBytes (VAR f: File; a: ADDRESS; amount: CARDINAL;
378 VAR actuallyWritten: CARDINAL) ;
380 actuallyWritten := 0 ;
384 actuallyWritten := FIO.WriteNBytes(fio, amount, a) ;
385 IF FIO.IsNoError(fio)
388 IF MAX(CARDINAL)-lowpos<actuallyWritten
392 INC(lowpos, actuallyWritten)
402 Again - returns the last character read to the internal buffer
403 so that it can be read again.
406 PROCEDURE Again (VAR f: File) ;
416 PROCEDURE doModeChange (VAR f: File; mode: Flag) ;
421 IF NOT (mode IN flags)
437 fio := SFIO.OpenToRead(name)
440 fio := SFIO.OpenToWrite(name)
442 INCL (flags, opened) ;
443 r := libc.lseek (fio,
444 VAL (LONGINT, lowpos) + VAL (LONGINT, highpos) * VAL (LONGINT, MAX (CARDINAL)),
452 SetRead - puts the file, f, into the read state.
453 The file position is unchanged.
456 PROCEDURE SetRead (VAR f: File) ;
458 doModeChange(f, read)
463 SetWrite - puts the file, f, into the write state.
464 The file position is unchanged.
467 PROCEDURE SetWrite (VAR f: File) ;
469 doModeChange(f, write)
474 SetModify - puts the file, f, into the modify state.
475 The file position is unchanged but the file can be
479 PROCEDURE SetModify (VAR f: File) ;
481 doModeChange(f, modify)
486 SetOpen - places a file, f, into the open state. The file may
487 have been in the read/write/modify state before and
488 in which case the previous buffer contents are flushed
489 and the file state is reset to open. The position is
493 PROCEDURE SetOpen (VAR f: File) ;
495 doModeChange(f, opened)
500 Reset - places a file, f, into the open state and reset the
501 position to the start of the file.
504 PROCEDURE Reset (VAR f: File) ;
512 SetPos - lseek to a position within a file.
515 PROCEDURE SetPos (VAR f: File; high, low: CARDINAL) ;
520 r := libc.lseek(fio, VAL(LONGCARD, low) +
521 (VAL(LONGCARD, MAX(CARDINAL)) * VAL(LONGCARD, high)),
530 GetPos - return the position within a file.
533 PROCEDURE GetPos (VAR f: File; VAR high, low: CARDINAL) ;
543 Length - returns the length of file, in, high, and, low.
546 PROCEDURE Length (VAR f: File; VAR high, low: CARDINAL) ;
551 i := wrapc.filesize(FIO.GetUnixFileDescriptor(fio), high, low)
557 Doio - effectively flushes a file in write mode, rereads the
558 current buffer from disk if in read mode and writes
559 and rereads the buffer if in modify mode.
562 PROCEDURE Doio (VAR f: File) ;
572 fio := SFIO.OpenToRead(name) ;
573 INCL(flags, opened) ;
574 SetPos(f, lowpos, highpos)
577 fio := SFIO.OpenToWrite(name) ;
578 INCL(flags, opened) ;
579 SetPos(f, lowpos, highpos)
586 FileNameChar - checks to see whether the character, ch, is
587 legal in a filename. nul is returned if the
588 character was illegal.
591 PROCEDURE FileNameChar (ch: CHAR) : CHAR ;
598 MakeTemporary - creates a temporary file and returns its name.
601 PROCEDURE MakeTemporary () : String ;
611 n := Sprintf2(InitString('fs-%d-%d'), i, tempNo) ;
612 n := ConCat(ConCatChar(InitString(TMPDIR), DIRSEP), n) ;
619 CleanUp - deletes all temporary files.
633 r := libc.unlink(string(n))
642 Init - installs the termination procedure to tidy up any temporary files.
649 IF NOT InstallTerminationProcedure(CleanUp)