(* mcStream.mod provides an interface to create a file from fragments. Copyright (C) 2015-2024 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. You should have received a copy of the GNU General Public License along with GNU Modula-2; see the file COPYING3. If not see . *) IMPLEMENTATION MODULE mcStream ; FROM FIO IMPORT File, OpenToWrite, OpenToRead, EOF, ReadNBytes, WriteNBytes, Close, getFileName, IsNoError ; FROM libc IMPORT unlink, printf, getpid, exit ; FROM Indexing IMPORT InitIndex, InBounds, HighIndice, LowIndice, PutIndice, GetIndice, Index, ForeachIndiceInIndexDo ; FROM DynamicStrings IMPORT String, InitString, InitStringCharStar, string ; FROM FormatStrings IMPORT Sprintf2 ; FROM SYSTEM IMPORT ADR ; FROM Storage IMPORT ALLOCATE ; IMPORT alists ; IMPORT SFIO ; TYPE ptrToFile = POINTER TO File ; VAR listOfFiles: alists.alist ; frag : Index ; destFile : File ; seenDest : BOOLEAN ; (* removeLater - *) PROCEDURE removeLater (filename: String) : String ; BEGIN alists.includeItemIntoList (listOfFiles, filename) ; RETURN filename END removeLater ; (* removeNow - removes a single file, s. *) PROCEDURE removeNow (s: String) ; BEGIN IF unlink (string (s)) # 0 THEN END END removeNow ; (* removeFiles - remove any fragment. *) PROCEDURE removeFiles ; BEGIN alists.foreachItemInListDo (listOfFiles, removeNow) ; alists.killList (listOfFiles) ; listOfFiles := alists.initList () END removeFiles ; (* createTemporaryFile - *) PROCEDURE createTemporaryFile (id: CARDINAL) : File ; VAR s: String ; f: File ; p: INTEGER ; BEGIN s := InitString ('/tmp/frag-%d-%d.frag') ; p := getpid () ; s := removeLater (Sprintf2 (s, p, id)) ; f := SFIO.OpenToWrite (s) ; RETURN f END createTemporaryFile ; (* openFrag - create and open fragment, id, and return the file. The file should not be closed by the user. *) PROCEDURE openFrag (id: CARDINAL) : File ; VAR f: File ; p: ptrToFile ; BEGIN f := createTemporaryFile (id) ; NEW (p) ; p^ := f ; PutIndice (frag, id, p) ; RETURN f END openFrag ; (* copy - copies contents of f to the destination file. *) PROCEDURE copy (p: ptrToFile) ; CONST maxBuffer = 4096 ; VAR buffer: ARRAY [0..maxBuffer] OF CHAR ; b : CARDINAL ; s : String ; f : File ; BEGIN IF p # NIL THEN f := p^ ; s := InitStringCharStar(getFileName (f)) ; Close (f) ; f := SFIO.OpenToRead (s) ; WHILE (NOT EOF (f)) AND IsNoError (f) DO b := ReadNBytes (f, HIGH (buffer), ADR (buffer)) ; IF IsNoError (f) THEN b := WriteNBytes (destFile, b, ADR (buffer)) ELSIF NOT EOF (f) THEN printf ("mcStream.mod:copy: error seen when reading file fragment: %s\n", string (s)) ; exit (1) END END ; Close (f) END END copy ; (* setDest - informs the stream module and all fragments must be copied info, f. *) PROCEDURE setDest (f: File) ; BEGIN seenDest := TRUE ; destFile := f END setDest ; (* combine - closes all fragments and then writes them in order to the destination file. The dest file is returned. *) PROCEDURE combine () : File ; BEGIN IF NOT seenDest THEN HALT END ; ForeachIndiceInIndexDo (frag, copy) ; removeFiles ; RETURN destFile END combine ; BEGIN listOfFiles := alists.initList () ; seenDest := FALSE ; frag := InitIndex (1) END mcStream.