FileStream.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Taft, November 22, 1983 10:03 am
Russ Atkinson (RRA) February 4, 1985 2:51:30 pm PST
Doug Wyatt, February 27, 1985 11:47:15 am PST
Interface to the generic file stream facilities. The FileStream facilities are generic in the sense that they are implemented entirely in terms of the generic FS operations, and therefore are applicable to any class of FS.OpenFile (workstation or Alpine). This interface is intended to be imported by the implementations of the specific file stream classes, namely the workstation FS and AlpineFS, and not directly by ordinary clients.
DIRECTORY
FS USING [defaultStreamBufferParms, defaultStreamOptions, ErrorDesc, ExtendFileProc, InitialPosition, Lock, OpenFile, StreamBufferParms, StreamOptions],
IO USING [STREAM, UnsafeBlock];
FileStream: CEDAR DEFINITIONS
= BEGIN
STREAM: TYPE = IO.STREAM;
UnsafeBlock: TYPE = IO.UnsafeBlock;
OpenFile: TYPE = FS.OpenFile;
Error handling
All errors from this package are reported by FS.Error or IO.Error. For FS.Error, the code ATOMs that may be passed are a subset of the ones defined in FS. Only codes in ErrorGroups $client, $lock, and $user are documented below; others can be assumed to arise during any attempted file system access due to conditions not directly under the control of the client or user.
Creating a file stream
The procedures in this section create a generic stream on an FS.OpenFile of any class, and returns an IO.STREAM handle of class $FS (generic file stream) on which stream operations may be performed.
The intended caller of this procedure is the StreamOpen, StreamFromOpenFile, or StreamFromOpenStream procedure of a particular file stream class implementation, namely the workstation FS or AlpineFS. That implementation may modify or extend the semantics by replacing the StreamProcs record in the STREAM object, supplying its own stream procedures for operations that have specialized semantics and using the generic operations from FileStream for the rest.
As a practical matter, it is expected that workstation FS streams will employ the generic operations exclusively, and only AlpineFS streams will have special class-specific implementations of certain operations. (To put it another way, the semantics of Alpine streams are a superset of the semantics of workstation FS streams.)
StreamFromOpenFile: PROC [openFile: FS.OpenFile,
accessRights: FS.Lock ← $read,
initialPosition: FS.InitialPosition ← $start,
streamOptions: FS.StreamOptions ← FS.defaultStreamOptions,
streamBufferParms: FS.StreamBufferParms ← FS.defaultStreamBufferParms,
extendFileProc: FS.ExtendFileProc ← NIL
] RETURNS [STREAM];
! client: FS.Error[$notImplemented, $wrongLock];
! user: FS.Error[$cantUpdateTiogaFile];
Creates a new stream on the open file. If accessRights=$read then PutChar, PutBlock, UnsafePutBlock, and SetLength are disallowed on the resulting stream. InitialPosition specifies the initial value of streamIndex: start means 0, end means the file's byte count.
StreamFromOpenStream: PROC [self: STREAM] RETURNS [STREAM];
! client: FS.Error[$notImplemented];
Given an existing file stream open for writing (accessRights=$write), creates a new stream on the same file with accessRights=$read. The two streams are then independently positionable, but are internally linked together so that the reader sees data written by the writer. At most one read stream may be linked in this way with any given write stream.
Generic operations
These are the procedures referenced from the StreamProcs record of the STREAM that FileStream.Create returns. They are also exported explicitly to the FileStream interface so that they may be called directly from the file stream class implementation. For example, for a particular stream class Flush may perform actions in addition to the generic Flush (which just writes out dirty buffers). The Flush procedure for that stream class will call FileStream.Flush directly as part of its implementation.
GetChar: PROC [self: STREAM] RETURNS [CHAR];
! IO.EndOfStream, IO.Error[$StreamClosed, $Failure];
GetBlock: PROC [self: STREAM, block: REF TEXT, startIndex: NAT, count: NAT] RETURNS [nBytesRead: NAT];
! IO.Error[$StreamClosed, $Failure];
UnsafeGetBlock: UNSAFE PROC [self: STREAM, block: UnsafeBlock] RETURNS [nBytesRead: INT];
! IO.Error[$StreamClosed, $Failure];
EndOf: PROC [self: STREAM] RETURNS [BOOL];
! IO.Error[$StreamClosed];
CharsAvail: PROC [self: STREAM, wait: BOOL] RETURNS [INT];
! IO.Error[$StreamClosed];
Backup: PROC [self: STREAM, char: CHAR];
! IO.Error[$StreamClosed, $Failure, $IllegalBackup];
PutChar: PROC [self: STREAM, char: CHAR];
! IO.Error[$NotImplementedForThisStream, $StreamClosed, $Failure];
PutBlock: PROC [self: STREAM, block: REF READONLY TEXT, startIndex: NAT, count: NAT];
! IO.Error[$NotImplementedForThisStream, $StreamClosed, $Failure];
UnsafePutBlock: PROC [self: STREAM, block: UnsafeBlock];
! IO.Error[$NotImplementedForThisStream, $StreamClosed, $Failure];
Flush: PROC [self: STREAM];
! IO.Error[$NotImplementedForThisStream, $StreamClosed, $Failure];
EraseChar: PROC [self: STREAM, char: CHAR];
! IO.Error[$NotImplementedForThisStream, $StreamClosed, $Failure, $IllegalBackup];
Reset: PROC [self: STREAM];
! IO.Error[$StreamClosed, $Failure];
Close: PROC [self: STREAM, abort: BOOL];
! IO.Error[$StreamClosed, $Failure];
GetIndex: PROC [self: STREAM] RETURNS [index: INT];
! IO.Error[$StreamClosed];
SetIndex: PROC [self: STREAM, index: INT];
! IO.EndOfStream, IO.Error[$StreamClosed, $Failure, $BadIndex];
GetLength: PROC [self: STREAM] RETURNS [length: INT];
! IO.Error[$StreamClosed];
SetLength: PROC [self: STREAM, length: INT];
! IO.Error[$StreamClosed, $Failure, $BadIndex];
File stream specific operations
These procedures apply to all file streams, but are not in the cluster for IO.STREAM so must be called explicitly.
The following procedures are intended simply to be re-exported to FS and AlpineFS:
OpenFileFromStream: PROC [self: STREAM] RETURNS [FS.OpenFile];
! IO.Error[$NotImplementedForThisStream];
Returns the OpenFile associated with this stream, which must be a file stream.
ErrorFromStream: PROC [self: STREAM] RETURNS [FS.ErrorDesc];
! IO.Error[$NotImplementedForThisStream];
Returns the error information about the most recent FS-level error involving this stream, which must be a file stream. This procedure is intended to be called by a client who just caught IO.Error[$Failure, self] and wants more detailed information about what went wrong.
The remaining procedures are intended to be called only by FS stream class implementations.
SaveStreamError: PROC [self: STREAM, error: FS.ErrorDesc];
! IO.Error[$NotImplementedForThisStream];
Saves the ErrorDesc from an FS.Error for later retrieval by the client. This procedure is intended for use by an FS stream class implementation when it catches FS.Error and raises IO.Error itself.
The StreamData record is the same for all classes of file streams, and its representation is private to the generic FileStream implementation. If a particular file stream class requires a place to keep class-specific information, it should define its own private data record and associate it with the stream by means of the following procedures.
SetStreamClassData: PROC [self: STREAM, data: REF ANY];
! IO.Error[$NotImplementedForThisStream];
GetStreamClassData: PROC [self: STREAM] RETURNS [data: REF ANY];
! IO.Error[$NotImplementedForThisStream];
Returns NIL if SetStreamClassData has not been called for this stream instance.
Finalization of file streams must be performed in a context in which the STREAM is not known, only the StreamData. Consequently, if any stream class specific finalization is to be performed, it is necessary to register a procedure that will be called as part of StreamData finalization procedure. The procedure is passed only the OpenFile and the the stream class specific data, not the FileStream StreamData record (which is private to FileStream); and it must not call any FileStream facilities or raise any signals.
Note: this stuff will go away if the IO package is changed to perform finalization for all STREAMs and call Close on any that haven't already been closed.
FinalizationProc: TYPE = PROC [openFile: FS.OpenFile, data: REF ANY, closed: BOOL];
Data is the stream class data that was established by SetStreamClassData. Closed is TRUE if the stream has already been closed by a client call to IO.Close, and FALSE if the stream is being finalized without the client's having explicitly closed it.
SetFinalizationProc: PROC [self: STREAM, proc: FinalizationProc];
! IO.Error[$NotImplementedForThisStream];
GetFinalizationProc: PROC [self: STREAM] RETURNS [proc: FinalizationProc];
! IO.Error[$NotImplementedForThisStream];
Returns NIL if SetFinalizationProc has not been called for this stream instance.
END.