| (* mcStream.mod provides an interface to create a file from fragments. |
| |
| Copyright (C) 2015-2025 Free Software Foundation, Inc. |
| Contributed by Gaius Mulley <gaius@glam.ac.uk>. |
| |
| 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 |
| <http://www.gnu.org/licenses/>. *) |
| |
| 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. |