DIRECTORY IO USING [STREAM], Rope USING [ROPE], TapeOps USING [TapeHandle, TapeStatus]; TapeStreams: CEDAR DEFINITIONS = BEGIN AccessOptions: TYPE ~ {read, write}; FillBlockOptions: TYPE ~ {truncate, zeroes, blanks}; ConversionList: TYPE = LIST OF REF ConversionRecord _ NIL; ConversionRecord: TYPE ~ RECORD [ name: ATOM _ NIL, proc: Conversion _ NIL, clientData: REF ANY _ NIL ]; Conversion: TYPE = PROC [ base: IO.STREAM , clientData: REF ANY _ NIL] RETURNS [ s: IO.STREAM ]; Error: PUBLIC ERROR [error: ErrorDesc]; ErrorDesc: TYPE ~ RECORD [group: ErrorGroup, explanation: Rope.ROPE] _ [ok, NIL]; ErrorGroup: TYPE = { ok, -- initial group for a new TapeStreams.ErrorDesc bug, -- error on the part of this software, TapeOps, or the TapeServer environment, -- something's wrong in the environment; human intervention required user -- illegal operation, probably due to user action }; StreamOpen: PROC [tape: TapeOps.TapeHandle, access: AccessOptions _ read, blocking: NAT _ 80, padding: FillBlockOptions _ blanks, conversions: ConversionList _ NIL, tapeRecordProc: TapeRecordProc _ NIL, clientData: REF ANY _ NIL, allowSoftErrors: BOOL _ TRUE] RETURNS[stream: IO.STREAM]; TapeRecordProc: TYPE ~ PROC [clientData: REF ANY _ NIL]; FlushBlockProc: TYPE ~ PROC [ self: IO.STREAM, padChar: CHAR _ '\000, bytesRequired: INT _ LAST[INT], truncate: BOOL _ FALSE ]; TapeStreamState: PRIVATE TYPE = REF TapeStreamStateRec _ NIL; TapeStreamStateRec: PRIVATE TYPE = RECORD [ index: INT, -- stream index buffer: REF TEXT, lastBufferIndexPlusOne: INT, tapeHandle: TapeOps.TapeHandle, blockSize: INT _ 80, writing: BOOL _ FALSE, clientData: REF ANY _ NIL, tapeRecordProc: TapeRecordProc _ NIL, access: AccessOptions _ read, eof: BOOL _ FALSE, firstRecordRead: BOOL _ FALSE, padding: FillBlockOptions _ blanks, status: TapeOps.TapeStatus, allowSoftErrors: BOOL _ TRUE ]; END. -- of TapeStreams PTapeStreams.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reserved. Last edited by Tim Diebert: March 18, 1986 8:19:37 am PST Last Edited by: McCreight, February 26, 1985 10:06:41 am PST .. takes a IO.STREAM and produces a layered IO.STREAM on it. Used for format conversion. StreamOpen takes a "tape" returned from TapeOps.Open and creates an IO.STREAM on it at the place the tape was positioned to prior to the call to StreamOpen. "access" is used to tell whether the stream is to be written or read. The "blocking" parameter is used to indicate the physical block size to be written onto the tape during writes. The "padding" tells what to do if fewer than blocksize bytes are to be written. The default is to fill this space with blanks. Other options include zero fill, and truncation. Note that if the record is truncated, there may be only 1 byte written, which makes our tape server and most other tape sites, very unhappy. The "conversions" parameter allows a general way for format conversions to be specified by means of layered IO.STREAM's. The first conversion is done just on top of the real tape stream. The "tapeRecordProc" entry allow the user to provide a procedure call whenever a tape block is written onto, or read from, the tape. Write Streams: are streams that support the following procedures from IO.mesa. PutChar: PROC [self: STREAM, char: CHAR] This causes the char to be put into the internal buffer and written onto the tape when the buffer is filled to the blocking size as specified in the StreamOpen. PutBlock: PROC [self: STREAM, block: REF READONLY TEXT, startIndex: NAT _ 0, count: NAT _ NAT.LAST] This procedure writes bytes from "block" starting at startIndex for count bytes. These bytes are moved into the tape buffer and the tape buffer is written onto the tape when the buffer is filled to the blocking size as specified in the StreamOpen. Flush: PROC [self: STREAM] This causes whatever bytes are in the tape buffer to be padded out to a full tape block and written onto the tape. Flush is called by Close and should not be called by the client before calling Close. Close: PROC [self: STREAM, abort: BOOL _ FALSE] This proc performs a Flush and then writes two tapemarks onto the tape and backs over one. In general, the end of tape volume is two tapemarks in consesion. If abort is true the tape is unloaded from the drive. Read Streams: are streams that support the following procedures from IO.mesa. GetChar: PROC [self: STREAM] RETURNS [CHAR] This procedure reads 1 byte from the tape stream raising IO.EndOfStream if a tapemark has been read from the tape. GetBlock: PROC [self: STREAM, block: REF TEXT, startIndex: NAT _ 0, count: NAT _ NAT.LAST] RETURNS [nBytesRead: NAT] This procedure reads bytes into "block" using the indexes as shown in IO.mesa. Returns 0 bytes if end of file is reached. EndOf: PROC [self: STREAM] RETURNS [BOOL] Returns true if the last tape block read was a tapemark. Close: PROC [self: STREAM, abort: BOOL _ FALSE] This proc closes the stream. If the stream is not at the end of file mark on the tape the tape is NOT moved to that point. If abort is true the tape is unloaded from the drive. Procedure to call on a record read or write of block by the lower level software Procedure available as the $FlushBlock property of an output stream Private Types for use by Conversion procedures Κ~˜codešœ™Kšœ Οmœ7™BKšœ9™9Kšœ<™<—K˜šΟk ˜ Kšžœžœžœ˜Kšœžœžœ˜Kšœžœ˜'—K˜šΟb œžœž œž˜&K˜Kšœžœ˜$Kšœžœ˜4K˜Kš œžœžœžœžœžœ˜:šœžœž˜Kš œžœžœžœžœžœžœ˜H—šΟn œžœžœ žœžœžœžœžœžœžœžœ˜bKšœY™Y—K˜KšŸœžœžœ˜'K˜Kš œ žœžœ'žœ žœ˜QK˜Kšœ žœ˜KšœΟc0˜4Kšœ‘B˜FKšœ ‘D˜QKšœ‘1˜6Kšœ˜K˜K˜šΠbn œžœDžœIžœ#žœžœžœžœžœžœžœ žœžœ˜ŸK˜KšœDž œDŸ œΌ™ΨK™K™Pš œžœžœžœ™(K™ —š œžœžœ žœžœžœžœ žœžœ™cKšœψ™ψ—š œžœžœ™Kšœ‡Ÿœ7Ÿœ™Ι—š  œžœžœ žœžœ™/K™ΤK™—K™Nš  œžœžœžœžœ™+Kšœr™r—š  œžœžœ žœžœ™.Kšœ žœ žœžœ™+Kšžœ žœ™K™z—š  œžœžœžœžœ™)K™8—š  œžœžœ žœžœ™/K™²—K˜K˜—KšœP™PKš ’œžœžœžœžœžœ˜8K˜KšœC™CKš œžœžœ žœžœ žœžœžœžœ žœžœ˜K˜K˜Kšœ.™.K˜Kš œžœžœžœžœ˜=šœžœžœž˜)Kšœ˜Kšœžœ‘˜Kšœžœžœ˜Kšœžœ˜Kšœ˜Kšœ žœ˜Kšœ žœžœ˜Kšœ žœžœžœ˜Kšœ!žœ˜%Kšœ˜Kšœžœžœ˜Kšœžœžœ˜Kšœ#˜#K˜Kšœžœž˜Kšœ˜—K˜Kšžœ‘˜K˜——…—l: