DIRECTORY BasicTime USING [GMT], File USING [Error, Handle, Read, wordsPerPage, Write], FS USING [Error, PagesForBytes], FSFileOps USING [FileStreamMode, GetFileInfo, GetProps, SetFilePages], FSReport USING [FileError], IO USING [CreateStream, CreateStreamProcs, EndOfStream, STREAM, StreamProcs], PrincOpsUtils USING [ByteBlt], VM USING [AddressForPageNumber, Allocate, Free, PageNumberForAddress, PageCount, PagesForBytes]; FSFileStreamImpl: CEDAR MONITOR IMPORTS File, FS, FSFileOps, FSReport, IO, PrincOpsUtils, VM EXPORTS FSFileOps = BEGIN CreateFileStream: PUBLIC PROC [file: File.Handle, mode: FSFileOps.FileStreamMode ] RETURNS [IO.STREAM] = BEGIN s: REF StreamObject; lastIndex: INT = (IF mode = oldReadOnly THEN FSFileOps.GetProps[file].bytes ELSE bytesPerFilePage*FSFileOps.GetFileInfo[file].pages); s _ CreateStreamObject[file, mode, lastIndex]; AllocateBuffer[s]; RETURN [IO.CreateStream[IF mode=oldReadOnly THEN readProcs ELSE appendProcs, s]]; END; Copy: PUBLIC PROC [from, to: File.Handle] RETURNS [bytes: INT, createdTime: BasicTime.GMT] = BEGIN fromS, toS: REF StreamObject; toS _ CreateStreamObject[to, newAppendOnly, bytesPerFilePage*FSFileOps.GetFileInfo[to].pages]; [bytes: bytes, created: createdTime] _ FSFileOps.GetProps[from]; fromS _ CreateStreamObject[from, oldReadOnly, bytes]; AllocateBuffer[fromS]; toS.buffer _ fromS.buffer; -- for faster copying BEGIN ENABLE FS.Error => FreeBuffer[fromS]; UNTIL fromS.index = fromS.lastFileIndexPlusOne DO LoadBuffer[fromS]; toS.index _ fromS.index _ fromS.lastBufferIndexPlusOne; StoreBuffer[toS]; ENDLOOP; END; FreeBuffer[fromS]; END; Close: PROC [self: IO.STREAM, abort: BOOL] = BEGIN s: REF StreamObject = NARROW [self.streamData]; IF self.streamProcs = NIL THEN RETURN; IF self.streamProcs = appendProcs AND s.index # 0 THEN BEGIN start: CARDINAL = s.index - s.firstBufferIndex; stop: CARDINAL = FS.PagesForBytes[s.index]*bytesPerFilePage - s.firstBufferIndex; FOR i: INT IN [start .. stop) DO TRUSTED { s.buffer[i] _ 0C }; ENDLOOP; StoreBuffer[s]; END; FreeBuffer[s]; self.streamProcs _ NIL; self.streamData _ NIL; END; EndOf: PROC [self: IO.STREAM] RETURNS[BOOL] = BEGIN s: REF StreamObject = NARROW [self.streamData]; RETURN[s.index >= s.lastFileIndexPlusOne]; END; GetIndex: PROC [self: IO.STREAM] RETURNS [i: INT] = BEGIN s: REF StreamObject = NARROW [self.streamData]; RETURN[s.index]; END; SetIndex: PROC [self: IO.STREAM, index: INT] = BEGIN s: REF StreamObject = NARROW [self.streamData]; IF index > s.lastFileIndexPlusOne THEN ERROR IO.EndOfStream[self]; s.index _ index; END; GetChar: PROC [self: IO.STREAM] RETURNS[char: CHAR] = TRUSTED BEGIN s: REF StreamObject = NARROW [self.streamData]; IF s.index >= s.lastFileIndexPlusOne THEN ERROR IO.EndOfStream[self]; IF s.index NOT IN [s.firstBufferIndex .. s.lastBufferIndexPlusOne) THEN LoadBuffer[s]; char _ s.buffer[s.index - s.firstBufferIndex]; s.index _ s.index + 1; END; PutChar: PROC [self: IO.STREAM, char: CHAR] = TRUSTED BEGIN s: REF StreamObject = NARROW [self.streamData]; IF s.index >= s.lastBufferIndexPlusOne THEN StoreBuffer[s]; s.buffer[s.index - s.firstBufferIndex] _ char; s.index _ s.index + 1; END; GetBlock: PROC [self: IO.STREAM, block: REF TEXT, startIndex: NAT, count: NAT] RETURNS[nBytesRead: NAT] = TRUSTED BEGIN s: REF StreamObject = NARROW [self.streamData]; nBytesRead _ 0; UNTIL count = 0 OR s.index = s.lastFileIndexPlusOne DO bufferChars, bufferIndex, bytesToGet: CARDINAL; IF s.index NOT IN [s.firstBufferIndex .. s.lastBufferIndexPlusOne) THEN LoadBuffer[s]; bufferChars _ s.lastBufferIndexPlusOne - s.index; bufferIndex _ s.index - s.firstBufferIndex; bytesToGet _ MIN[count, bufferChars]; [] _ PrincOpsUtils.ByteBlt[ to: [ BASE[DESCRIPTOR[block]], startIndex, startIndex+bytesToGet ], from: [ s.buffer, bufferIndex, bufferIndex+bytesToGet ] ]; s.index _ s.index + bytesToGet; count _ count - bytesToGet; startIndex _ startIndex + bytesToGet; nBytesRead _ nBytesRead + bytesToGet; ENDLOOP; END; PutBlock: PROC [self: IO.STREAM, block: REF READONLY TEXT, startIndex: NAT, count: NAT] = TRUSTED BEGIN s: REF StreamObject = NARROW [self.streamData]; UNTIL count = 0 DO bufferChars, bufferIndex, bytesToPut: CARDINAL; IF s.index >= s.lastBufferIndexPlusOne THEN StoreBuffer[s]; bufferChars _ s.lastBufferIndexPlusOne - s.index; bufferIndex _ s.index - s.firstBufferIndex; bytesToPut _ MIN[count, bufferChars]; [] _ PrincOpsUtils.ByteBlt[ to: [ s.buffer, bufferIndex, bufferIndex+bytesToPut ], from: [ BASE[DESCRIPTOR[block]], startIndex, startIndex+bytesToPut ] ]; s.index _ s.index + bytesToPut; count _ count - bytesToPut; startIndex _ startIndex + bytesToPut; ENDLOOP; END; bufferFilePages: INT = 8; bytesPerFilePage: INT = File.wordsPerPage*2; bufferBytes: INT = bufferFilePages * bytesPerFilePage; bufferVMPages: VM.PageCount = VM.PagesForBytes[bufferBytes]; BufferPtr: TYPE = LONG POINTER TO PACKED ARRAY [0 .. 0) OF CHAR; StreamObject: TYPE = RECORD [ file: File.Handle, lastFileIndexPlusOne: INT, -- byte count for oldReadOnly, bytes in file pages for newAppendOnly index: INT, -- stream index buffer: BufferPtr, firstBufferIndex: INT, lastBufferIndexPlusOne: INT ]; readProcs: REF IO.StreamProcs = IO.CreateStreamProcs[variety: input, class: $FSFileStreamImplRead, close: Close, endOf: EndOf, getIndex: GetIndex, setIndex: SetIndex, getChar: GetChar, getBlock: GetBlock]; appendProcs: REF IO.StreamProcs = IO.CreateStreamProcs[variety: output, class: $FSFileStreamImplAppend, close: Close, getIndex: GetIndex, putBlock: PutBlock]; CreateStreamObject: PROC [file: File.Handle, mode: FSFileOps.FileStreamMode, lastIndexPlusOne: INT] RETURNS [s: REF StreamObject] = BEGIN s _ NEW [ StreamObject ]; s.file _ file; s.index _ 0; s.lastFileIndexPlusOne _ lastIndexPlusOne; IF mode = oldReadOnly THEN BEGIN s.firstBufferIndex _ s.lastFileIndexPlusOne; s.lastBufferIndexPlusOne _ s.lastFileIndexPlusOne; END ELSE BEGIN s.firstBufferIndex _ 0; s.lastBufferIndexPlusOne _ bufferBytes; END; END; PageNumberForByteIndex: PROC [index: INT] RETURNS [INT] = BEGIN RETURN[ index/(bytesPerFilePage) ] END; LoadBuffer: PROC [s: REF StreamObject] = BEGIN pageNumber: INT = PageNumberForByteIndex[s.index]; pageCount: INT; s.firstBufferIndex _ pageNumber * bytesPerFilePage; s.lastBufferIndexPlusOne _ MIN[s.lastFileIndexPlusOne, s.firstBufferIndex+bufferBytes]; pageCount _ PageNumberForByteIndex[s.lastBufferIndexPlusOne-1] - pageNumber + 1; TRUSTED BEGIN File.Read[file: s.file, from: [pageNumber], nPages: pageCount, to: s.buffer ! File.Error => FSReport.FileError[why] ]; END; END; StoreBuffer: PROC [s: REF StreamObject] = BEGIN pageNumber: INT = PageNumberForByteIndex[s.firstBufferIndex]; pageCount: INT = PageNumberForByteIndex[s.index-1] - pageNumber + 1; IF s.index > s.lastFileIndexPlusOne THEN BEGIN newSize: INT = pageNumber + pageCount; FSFileOps.SetFilePages[s.file, newSize]; s.lastFileIndexPlusOne _ newSize * bytesPerFilePage; END; s.firstBufferIndex _ s.lastBufferIndexPlusOne; s.lastBufferIndexPlusOne _ s.firstBufferIndex+bufferBytes; TRUSTED BEGIN File.Write[file: s.file, to: [pageNumber], nPages: pageCount, from: s.buffer ! File.Error => FSReport.FileError[why] ]; END; END; retainedBuffer: BufferPtr _ NIL; AllocateBuffer: ENTRY PROC [s: REF StreamObject] = TRUSTED BEGIN IF retainedBuffer = NIL THEN s.buffer _ VM.AddressForPageNumber[ VM.Allocate[count: bufferVMPages].page ] ELSE { s.buffer _ retainedBuffer; retainedBuffer _ NIL }; END; FreeBuffer: ENTRY PROC [s: REF StreamObject] = TRUSTED BEGIN IF retainedBuffer = NIL THEN retainedBuffer _ s.buffer ELSE VM.Free[ [VM.PageNumberForAddress[s.buffer], bufferVMPages] ]; s.buffer _ NIL; END; END.  FSFileStreamImpl.mesa Last Edited by: Schroeder, December 15, 1983 4:26 pm Last Edited by: Levin, September 22, 1983 1:34 pm Exported to FSFileOps Produces a stream on the indicated file. The contents of the "from" file are transfered to the "to" file. Stream procs Internal stuff Κ Β– "cedar" style˜Icode2šœ™K™4K™1code1šΟk ˜ Lšœ œœ˜Lšœœ,˜6Lšœœ˜ Lšœ œ7˜FLšœ œ ˜Lšœœ0œ˜MLšœœ ˜LšœœX˜`—šœœ˜Lšœœœ˜˜QKš œœœœœœ˜GKšœ˜Kšœ˜—Kšœ˜Kšœœ˜Kšœœ˜Kšœ˜—š žœœœœœœ˜-Kš˜Kšœœœ˜/Kšœ$˜*Kšœ˜—š žœœœœœœ˜3Kš˜Kšœœœ˜/Kšœ ˜Kšœ˜—šžœœ œ œ˜.Kš˜Kšœœœ˜/Kšœ˜!Kšœœ˜ Kšœ˜Kšœ˜—š žœœ œœœ˜=Kš˜Kšœœœ˜/Kšœ"˜$Kšœœœ˜ Kšœ œœ1˜BKšœ˜Kšœ.˜.K˜Kšœ˜—š žœœœœœ˜5Kš˜Kšœœœ˜/Kšœ$˜&Kšœ˜Kšœ.˜.K˜Kšœ˜—šžœœ œ œœœ œœ œ˜qKš˜Kšœœœ˜/Kšœ˜šœ œ"˜6Kšœ&œ˜/Kšœ œœ1˜BKšœ˜Kšœ1˜1Kšœ+˜+Kšœ œ˜%šœ˜Kšœœ œ.˜CKšœ7˜7Kšœ˜—Kšœ˜Kšœ˜Kšœ%˜%Kšœ%˜%Kšœ˜—Kšœ˜—šžœœ œ œœœœ œ˜aKš˜Kšœœœ˜/šœ ˜Kšœ&œ˜/Kšœ&˜&Kšœ˜Kšœ1˜1Kšœ+˜+Kšœ œ˜%šœ˜Kšœ6˜6Kšœœ œ-˜DKšœ˜—Kšœ˜Kšœ˜Kšœ%˜%Kšœ˜—Kšœ˜——™Kšœœ˜Kšœœ˜,Kšœ œ&˜6Kšœœ œ˜