EchoStreamImpl.mesa
Copyright Ó 1990, 1992 by Xerox Corporation. All rights reserved.
Last tweaked by Mike Spreitzer on September 20, 1990 9:26:21 am PDT
DIRECTORY Basics, EchoStream, IO, IOUtils;
EchoStreamImpl: CEDAR PROGRAM
IMPORTS IO, IOUtils
EXPORTS EchoStream
= BEGIN
STREAM: TYPE ~ IO.STREAM;
EchoStreamData: TYPE ~ REF EchoStreamDataPrivate;
EchoStreamDataPrivate: TYPE ~ RECORD [
in, out: IO.STREAM,
mapErrors, eraseBackup, resetOutput, closeIn, closeOut: BOOL,
index, backed: INT ¬ 0];
echoProcs: REF IO.StreamProcs ~ IO.CreateStreamProcs[
variety: input,
class: $Echo,
getChar: GetChar,
unsafeGetBlock: UnsafeGetBlock,
endOf: EndOf,
charsAvail: CharsAvail,
backup: Backup,
reset: Reset,
close: Close,
getIndex: GetIndex,
getLength: GetLength];
CreateEchoStream: PUBLIC PROC [in, out: IO.STREAM, mapErrors: BOOL ¬ TRUE, eraseBackup, resetOutput, closeIn, closeOut: BOOL ¬ FALSE] RETURNS [IO.STREAM] ~ {
esd: EchoStreamData ~ NEW [EchoStreamDataPrivate ¬ [in, out, mapErrors, eraseBackup, resetOutput, closeIn, closeOut]];
RETURN [IO.CreateStream[echoProcs, esd, NIL]]};
GetChar: PROC [self: STREAM] RETURNS [CHAR] ~ {
esd: EchoStreamData ~ NARROW[self.streamData];
c: CHAR ~ esd.in.GetChar[!
IO.Error => IF esd.mapErrors THEN IO.Error[ec, self];
IO.EndOfStream => IF esd.mapErrors THEN IO.EndOfStream[self] ];
IF esd.backed<=0 OR esd.eraseBackup
THEN esd.out.PutChar[c !IO.Error => IF esd.mapErrors THEN IO.Error[ec, self]];
IF esd.backed>0
THEN esd.backed ¬ esd.backed.PRED
ELSE esd.index ¬ esd.index.SUCC;
RETURN [c]};
UnsafeGetBlock: UNSAFE PROC [self: STREAM, block: Basics.UnsafeBlock] RETURNS [nBytesRead: INT ¬ 0] ~ {
esd: EchoStreamData ~ NARROW[self.streamData];
unbacked: INT;
TRUSTED {nBytesRead ¬ esd.in.UnsafeGetBlock[block !
IO.Error => IF esd.mapErrors THEN IO.Error[ec, self];
IO.EndOfStream => IF esd.mapErrors THEN IO.EndOfStream[self] ]};
unbacked ¬ MIN[nBytesRead, esd.backed];
{ENABLE IO.Error => IF esd.mapErrors THEN IO.Error[ec, self];
IF esd.eraseBackup
THEN esd.out.UnsafePutBlock[[block.base, block.startIndex, nBytesRead]]
ELSE esd.out.UnsafePutBlock[[block.base, block.startIndex+unbacked, nBytesRead-unbacked]];
};
esd.backed ¬ esd.backed - unbacked;
esd.index ¬ esd.index + nBytesRead - unbacked;
RETURN};
EndOf: PROC [self: STREAM] RETURNS [BOOL] ~ {
esd: EchoStreamData ~ NARROW[self.streamData];
RETURN esd.in.EndOf[!
IO.Error => IF esd.mapErrors THEN IO.Error[ec, self];
IO.EndOfStream => IF esd.mapErrors THEN IO.EndOfStream[self] ]};
CharsAvail: PROC [self: STREAM, wait: BOOL] RETURNS [INT] ~ {
esd: EchoStreamData ~ NARROW[self.streamData];
RETURN esd.in.CharsAvail[!
IO.Error => IF esd.mapErrors THEN IO.Error[ec, self];
IO.EndOfStream => IF esd.mapErrors THEN IO.EndOfStream[self] ]};
Backup: PROC [self: STREAM, char: CHAR] ~ {
esd: EchoStreamData ~ NARROW[self.streamData];
esd.in.Backup[char !
IO.Error => IF esd.mapErrors THEN IO.Error[ec, self];
IO.EndOfStream => IF esd.mapErrors THEN IO.EndOfStream[self] ];
esd.backed ¬ esd.backed.SUCC;
IF esd.eraseBackup THEN esd.out.EraseChar[char ! IO.Error => IF esd.mapErrors THEN IO.Error[ec, self]];
RETURN};
Reset: PROC [self: STREAM] ~ {
esd: EchoStreamData ~ NARROW[self.streamData];
esd.in.Reset[!
IO.Error => IF esd.mapErrors THEN IO.Error[ec, self];
IO.EndOfStream => IF esd.mapErrors THEN IO.EndOfStream[self] ];
IF esd.resetOutput
THEN esd.out.Reset[!IO.Error => IF esd.mapErrors THEN IO.Error[ec, self] ];
RETURN};
Close: PROC [self: STREAM, abort: BOOL ¬ FALSE] ~ {
esd: EchoStreamData ~ NARROW[self.streamData];
IF esd.closeIn THEN esd.in.Close[abort !
IO.Error => IF esd.mapErrors THEN IO.Error[ec, self];
IO.EndOfStream => IF esd.mapErrors THEN IO.EndOfStream[self] ];
IF esd.closeOut THEN esd.out.Close[abort !
IO.Error => IF esd.mapErrors THEN IO.Error[ec, self] ];
IOUtils.AmbushStream[self, IOUtils.closedStreamProcs, NIL, NIL];
RETURN};
GetIndex: PROC [self: STREAM] RETURNS [INT] ~ {
esd: EchoStreamData ~ NARROW[self.streamData];
RETURN [esd.index - esd.backed]};
GetLength: PROC [self: STREAM] RETURNS [length: INT] ~ {
esd: EchoStreamData ~ NARROW[self.streamData];
RETURN esd.in.GetLength[!
IO.Error => IF esd.mapErrors THEN IO.Error[ec, self];
IO.EndOfStream => IF esd.mapErrors THEN IO.EndOfStream[self] ]};
END.