DIRECTORY Basics, BasicTime, File, FS USING [Error, PagesForBytes], FSFileOps USING [FileStreamMode, GetFileInfo, GetProps, SetFilePages], FSReport USING [FileError], IO USING [CreateStream, CreateStreamProcs, EndOfStream, STREAM, StreamProcs], PrincOpsUtils USING [ByteBlt], VM; FSFileStreamImpl: CEDAR MONITOR IMPORTS Basics, 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] = { lastIndex: INT = (IF mode = oldReadOnly THEN FSFileOps.GetProps[file].bytes ELSE bytesPerFilePage*FSFileOps.GetFileInfo[file].pages); s: REF StreamObject = 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: REF StreamObject; toS: REF StreamObject _ 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 [INT] = { s: REF StreamObject = NARROW [self.streamData]; RETURN[s.lastFileIndexPlusOne]; }; GetIndex: PROC [self: STREAM] RETURNS [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 _ 0] = TRUSTED { s: REF StreamObject = NARROW [self.streamData]; IF startIndex >= block.maxLength THEN RETURN; 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 + nBytesRead; }; PutBlock: PROC [self: STREAM, block: REF READONLY TEXT, startIndex: NAT, count: NAT] = TRUSTED { 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; }; bytesPerFilePage: CARDINAL = File.wordsPerPage*Basics.bytesPerWord; bufferBytes: CARDINAL _ 8 * bytesPerFilePage; BufferPtr: TYPE = LONG POINTER TO Basics.RawChars; StreamObject: TYPE = RECORD [ file: File.Handle, lastFileIndexPlusOne: INT, 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] = INLINE { 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: VM.PagesForBytes[bufferBytes]]; 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], VM.PagesForBytes[bufferBytes]]; IF retainedBuffer = NIL THEN { retainedBuffer _ s.buffer; } ELSE { VM.Free[ interval ]; }; s.buffer _ NIL; }; }. LFSFileStreamImpl.mesa Copyright c 1984, 1986 by Xerox Corporation. All rights reserved. Russ Atkinson (RRA) March 28, 1986 12:40:02 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 Note: bufferBytes should always be a multiple of file pages, and bufferBytes <= 32K. byte count for oldReadOnly, bytes in file pages for newAppendOnly 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˜codešœ™Kšœ Οmœ7™BK™2K˜šΟk ˜ Kšœ˜Kšœ ˜ Kšœ˜Kšžœžœ˜ Kšœ žœ7˜FKšœ žœ ˜Kšžœžœ0žœ˜MKšœžœ ˜Kšžœ˜——headšœžœž˜Kšžœžœžœž˜DKšžœ ˜Kšœ˜K˜Kšžœžœ žœ˜Kšžœžœžœžœ˜—head2šœ™š Οnœžœžœ6žœžœ˜gKšœ(™(Kš œ žœžœžœ žœ5˜…Kšœžœ:˜@Kšœ˜Kš žœžœžœžœ žœ˜QKšœ˜K˜—š Ÿœžœžœžœ žœžœ˜TKšœ@™@Kšœžœ˜Kšœžœh˜pKšœ@˜@Kšœ5˜5Kšœ˜KšœΟc˜0šœžœžœ˜'šžœ*ž˜1Kšœ˜Kšœ7˜7Kšœ˜Kšžœ˜—Kšœ˜—Kšœ˜Kšœ˜K˜——™ šŸœžœžœ žœ˜+Kšœžœžœ˜/Kšžœžœžœžœ˜&šžœ žœ žœ˜8Kšœžœ ˜/Kšœžœžœ>˜QKš žœžœžœžœžœžœ˜GKšœ˜Kšœ˜—Kšœ˜Kšœžœ˜Kšœžœ˜Kšœ˜K˜—š Ÿœžœžœžœžœ˜-Kšœžœžœ˜/Kšžœ$˜*Kšœ˜K˜—š Ÿ œžœžœžœžœ˜0Kšœžœžœ˜/Kšžœ˜Kšœ˜K˜—š Ÿœžœžœžœžœ˜/Kšœžœžœ˜/Kšžœ ˜Kšœ˜K˜—šŸœžœžœ žœ˜-Kšœžœžœ˜/Kšžœžœžœ˜BKšœ˜Kšœ˜K˜—š Ÿœžœžœžœžœžœ˜=Kšœžœžœ˜/Kšžœ"žœžœžœ˜EKšžœ žœžœ1žœ˜VKšœ.˜.K˜Kšœ˜K˜—š Ÿœžœžœžœžœ˜4Kšœžœžœ˜/Kšžœ$žœ˜;Kšœ.˜.K˜Kšœ˜K˜—šŸœžœžœ žœžœžœ žœžœžœžœ˜uKšœžœžœ˜/Kšžœžœžœ˜-Kšœžœ$˜/šžœ žœ"ž˜6Kšœ&žœ˜/Kšžœ žœžœ2žœ˜VKšœ1˜1Kšœ+˜+Kšœ žœ˜%šœ˜Kšœžœž œ.˜CKšœ7˜7Kšœ˜—Kšœ˜Kšœ˜Kšœ%˜%Kšœ%˜%Kšžœ˜—KšΟr'˜'Kšœ˜K˜—šŸœžœžœ žœžœžœžœ žœžœ˜`Kšœžœžœ˜/šžœ ž˜Kšœ&žœ˜/Kšœ&˜&Kšžœ˜Kšœ1˜1Kšœ+˜+Kšœ žœ˜%šœ˜Kšœ6˜6Kšœžœž œ-˜DKšœ˜—Kšœ˜Kšœ˜Kšœ%˜%Kšžœ˜—Kšœ˜K˜——™Kšœžœ)˜Cšœ žœ˜-KšœT™T—Kš œ žœžœžœžœ˜2šœžœžœ˜Kšœ˜šœžœ˜KšœA™A—Kšœžœ ˜Kšœ˜Kšœžœ˜Kšœž˜K˜K˜—Kšœ žœžœžœΑ˜γKšœ žœžœžœz˜žK˜š ŸœžœGžœžœžœ˜…Kšœžœ˜Kšœ˜K˜ Kšœ*˜*šžœ˜šžœ˜Kšœ,˜,Kšœ2˜2Kšœ˜—šžœ˜Kšœ˜Kšœ'˜'Kšœ˜——Kšœ˜K˜—š Ÿœžœ žœžœžœžœ˜BKšžœ˜"Kšœ˜K˜—šŸ œžœžœ˜*Kšœ žœ#˜2Kšœ žœ˜Kšœ3˜3Kšœžœ9˜WKšœP˜Pšžœ˜ šœK˜KKšœ*˜*—Kšœ˜—Kšœ˜K˜—šŸ œžœžœ˜+Kšœ žœ.˜=Kšœ žœ6˜Dšžœ!žœ˜*Kšœ žœ˜&Kšœ(˜(Kšœ4˜4Kšœ˜—Kšœ.˜.Kšœ:˜:šžœ˜ šœL˜LKšœ*˜*—Kšœ˜—Kšœ˜K˜—Kšœžœ˜!š Ÿœžœžœžœžœ˜