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, Free, Interval, PageNumberForAddress, PageCount, PagesForBytes, SimpleAllocate, SwapIn]; FSFileStreamImpl: CEDAR MONITOR IMPORTS File, FS, FSFileOps, FSReport, IO, PrincOpsUtils, VM EXPORTS FSFileOps = { GMT: TYPE = BasicTime.GMT; STREAM: TYPE = IO.STREAM; CreateFileStream: PUBLIC PROC [file: File.Handle, mode: FSFileOps.FileStreamMode ] RETURNS [STREAM] = { 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]]; }; Copy: PUBLIC PROC [from, to: File.Handle] RETURNS [bytes: INT, createdTime: GMT] = { 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 { ENABLE FS.Error => FreeBuffer[fromS]; UNTIL fromS.index = fromS.lastFileIndexPlusOne DO LoadBuffer[fromS]; toS.index _ fromS.index _ fromS.lastBufferIndexPlusOne; StoreBuffer[toS]; ENDLOOP; }; FreeBuffer[fromS]; }; Close: PROC [self: STREAM, abort: BOOL] = { s: REF StreamObject = NARROW [self.streamData]; IF self.streamProcs = NIL THEN RETURN; IF self.streamProcs = appendProcs AND s.index # 0 THEN { 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]; }; FreeBuffer[s]; self.streamProcs _ NIL; self.streamData _ NIL; }; EndOf: PROC [self: STREAM] RETURNS[BOOL] = { s: REF StreamObject = NARROW [self.streamData]; RETURN[s.index >= s.lastFileIndexPlusOne]; }; GetLength: PROC [self: STREAM] RETURNS[length: INT] = { s: REF StreamObject = NARROW [self.streamData]; RETURN[s.lastFileIndexPlusOne]; }; GetIndex: PROC [self: STREAM] RETURNS [i: INT] = { s: REF StreamObject = NARROW [self.streamData]; RETURN[s.index]; }; SetIndex: PROC [self: STREAM, index: INT] = { s: REF StreamObject = NARROW [self.streamData]; IF index > s.lastFileIndexPlusOne THEN ERROR IO.EndOfStream[self]; s.index _ index; }; GetChar: PROC [self: STREAM] RETURNS[char: CHAR] = TRUSTED { 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; }; PutChar: PROC [self: STREAM, char: CHAR] = TRUSTED { 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; }; GetBlock: PROC [self: STREAM, block: REF TEXT, startIndex: NAT, count: NAT] RETURNS[nBytesRead: NAT] = TRUSTED { s: REF StreamObject = NARROW [self.streamData]; nBytesRead _ 0; count _ MIN[count, block.maxLength-startIndex]; 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; block.length _ startIndex; }; PutBlock: PROC [self: STREAM, block: REF READONLY TEXT, startIndex: NAT, count: NAT] = TRUSTED { s: REF StreamObject = NARROW [self.streamData]; count _ MIN[count, block.length-startIndex]; 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; }; bufferFilePages: INT = 32; -- ____ Was 8, HGM wants to go FAST 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, getLength: GetLength, 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] = { s _ NEW [ StreamObject ]; s.file _ file; s.index _ 0; s.lastFileIndexPlusOne _ lastIndexPlusOne; IF mode = oldReadOnly THEN { s.firstBufferIndex _ s.lastFileIndexPlusOne; s.lastBufferIndexPlusOne _ s.lastFileIndexPlusOne; } ELSE { s.firstBufferIndex _ 0; s.lastBufferIndexPlusOne _ bufferBytes; }; }; PageNumberForByteIndex: PROC [index: INT] RETURNS [INT] = { RETURN[ index/(bytesPerFilePage) ] }; LoadBuffer: PROC [s: REF StreamObject] = { 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 { File.Read[file: s.file, from: [pageNumber], nPages: pageCount, to: s.buffer ! File.Error => FSReport.FileError[why] ]; }; }; StoreBuffer: PROC [s: REF StreamObject] = { pageNumber: INT = PageNumberForByteIndex[s.firstBufferIndex]; pageCount: INT = PageNumberForByteIndex[s.index-1] - pageNumber + 1; IF s.index > s.lastFileIndexPlusOne THEN { newSize: INT = pageNumber + pageCount; FSFileOps.SetFilePages[s.file, newSize]; s.lastFileIndexPlusOne _ newSize * bytesPerFilePage; }; s.firstBufferIndex _ s.lastBufferIndexPlusOne; s.lastBufferIndexPlusOne _ s.firstBufferIndex+bufferBytes; TRUSTED { File.Write[file: s.file, to: [pageNumber], nPages: pageCount, from: s.buffer ! File.Error => FSReport.FileError[why] ]; }; }; retainedBuffer: BufferPtr _ NIL; AllocateBuffer: ENTRY PROC [s: REF StreamObject] = TRUSTED { ENABLE UNWIND => NULL; IF retainedBuffer = NIL THEN { interval: VM.Interval _ VM.SimpleAllocate[count: bufferVMPages]; VM.SwapIn[interval]; s.buffer _ VM.AddressForPageNumber[ interval.page ]; } ELSE { s.buffer _ retainedBuffer; retainedBuffer _ NIL; }; }; FreeBuffer: ENTRY PROC [s: REF StreamObject] = TRUSTED { ENABLE UNWIND => NULL; interval: VM.Interval _ [VM.PageNumberForAddress[s.buffer], bufferVMPages]; IF retainedBuffer = NIL THEN { retainedBuffer _ s.buffer; } ELSE { VM.Free[ interval ]; }; s.buffer _ NIL; }; }. PFSFileStreamImpl.mesa Copyright c 1984 by Xerox Corporation. All rights reserved. Schroeder, December 15, 1983 4:26 pm Levin, September 22, 1983 1:34 pm Russ Atkinson, November 7, 1984 11:17:51 am PST Russ Atkinson (RRA) May 10, 1985 5:09:12 pm PDT Hal Murray, February 18, 1986 7:22:51 pm PST 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 Bob Hagmann January 28, 1986 4:13:35 pm PST added GetIndex to allow STP to find out the stream length changes to: GetIndex, readProcs Κ >– "cedar" style˜šœ™Jšœ Οmœ1™˜QMš žœžœžœžœžœžœ˜GMšœ˜Mšœ˜—Mšœ˜Mšœžœ˜Mšœžœ˜Mšœ˜—š Ÿœžœžœžœžœ˜,Mšœžœžœ˜/Mšžœ$˜*Mšœ˜—š Ÿ œžœžœžœ žœ˜7Mšœžœžœ˜/Mšžœ˜Mšœ˜—š Ÿœžœžœžœžœ˜2Mšœžœžœ˜/Mšžœ ˜Mšœ˜—šŸœžœžœ žœ˜-Mšœžœžœ˜/Mšžœ˜!Mšžœžœ˜ Mšœ˜Mšœ˜—š Ÿœžœžœžœžœžœ˜Mšœžœ˜,Mšœ žœ&˜6Mšœžœ žœ˜