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.