<<>> <> <> <> <> DIRECTORY Basics USING [RawBytes, UnsafeBlock], IO USING [PutR1, RIS, Value], PFS USING [AccessOptions, AttributeSource, Close, CreateOptions, defaultCreateOptions, Error, FileInfo, FileType, Mutability, NameFormat, nullUniqueID, Open, OpenFile, OpenFileObject, Read, RopeFromPath, UniqueID], PFSNames USING [Equal, PATH], Rope USING [Substr, ROPE], RopeFile USING [ByteSequenceObject, CreateByteSequenceObject, DeactivateResult, FromByteSequenceObject], TiogaFileIO USING [GetParts, Parts]; PFSRopeFileImpl: CEDAR MONITOR LOCKS self USING self: ByteSequenceObject IMPORTS PFS, RopeFile, IO, PFSNames, Rope, TiogaFileIO EXPORTS PFS ~ BEGIN OPEN PFS; PATH: TYPE ~ PFSNames.PATH; ROPE: TYPE ~ Rope.ROPE; ByteSequenceObject: TYPE ~ RopeFile.ByteSequenceObject; DeactivateResult: TYPE ~ RopeFile.DeactivateResult; Data: TYPE ~ REF DataRep; DataRep: TYPE ~ RECORD [ fullFName: PATH, uniqueID: UniqueID, fileName: ROPE, created: ROPE, openFile: OpenFile ]; PFSDeactivate: ENTRY PROC [self: ByteSequenceObject, final: BOOL] RETURNS [result: DeactivateResult ¬ ok] ~ { data: Data ~ NARROW[self.data]; openFile: OpenFile ¬ data.openFile; IF openFile = NIL THEN RETURN [alreadyInactive]; data.openFile ¬ NIL; PFS.Close[openFile ! PFS.Error => { result ¬ cant } ]; }; PFSEqual: ENTRY PROC [self, other: ByteSequenceObject] RETURNS [BOOL] ~ { data: Data ~ NARROW[self.data]; WITH other.data SELECT FROM otherData: Data => { IF self.length # other.length THEN RETURN [FALSE]; IF data.uniqueID # otherData.uniqueID THEN RETURN [FALSE]; IF NOT PFSNames.Equal[data.fullFName, otherData.fullFName] THEN RETURN [FALSE]; <> RETURN [TRUE] }; ENDCASE; RETURN [FALSE] }; PFSDescribe: ENTRY PROC [self: ByteSequenceObject] RETURNS [fileName: ROPE, created: ROPE, open: BOOL] ~ { data: Data ~ NARROW[self.data]; RETURN [fileName: data.fileName, created: data.created, open: data.openFile#NIL]; }; PFSMove: ENTRY UNSAFE PROC [self: ByteSequenceObject, block: Basics.UnsafeBlock, start: INT] RETURNS [charsMoved: INT ¬ 0] ~ UNCHECKED { ENABLE UNWIND => NULL; << FIXTHIS Turn PFS.Error into RopeFile.Error >> data: Data ~ NARROW[self.data]; IF data.openFile = NIL THEN { data.openFile ¬ PFS.Open[name: data.fullFName, wantedUniqueID: data.uniqueID]; }; charsMoved ¬ PFS.Read[file: data.openFile, filePosition: start, nBytes: block.count, to: block.base, toStart: block.startIndex]; }; RopeOpen: PUBLIC PROC [fileName: PFSNames.PATH, wantedUniqueID: UniqueID ¬ nullUniqueID, includeFormatting: BOOL ¬ FALSE, checkMutability: BOOL ¬ TRUE] RETURNS [rope: ROPE, fullFName: PATH, uniqueID: UniqueID] ~ { length: INT; mutability: Mutability; data: Data ~ NEW[DataRep]; [fullFName: fullFName, attachedTo: data.fullFName, uniqueID: uniqueID, bytes: length, mutability: mutability] ¬ FileInfo[fileName, wantedUniqueID]; data.uniqueID ¬ uniqueID; IF data.fullFName = NIL THEN data.fullFName ¬ fullFName; data.fileName ¬ RopeFromPath[fullFName]; data.created ¬ IO.PutR1[[time[uniqueID.egmt.gmt]]]; rope ¬ RopeFile.FromByteSequenceObject[byteSequenceObject: RopeFile.CreateByteSequenceObject[length: length, data: data, equal: PFSEqual, deactivate: PFSDeactivate, describe: PFSDescribe, move: PFSMove], flatten: checkMutability AND mutability=mutable]; IF NOT includeFormatting THEN { parts: TiogaFileIO.Parts ~ TiogaFileIO.GetParts[IO.RIS[rope]]; IF parts.isTioga THEN rope ¬ Rope.Substr[rope, parts.start1, parts.len1]; }; }; END.