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. ’ 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 Κ•NewlineDelimiter –(cedarcode) style™codešœ™Kšœ Οeœ7™BKšœC™C—K˜KšΟk œžœ ˜*K˜šΟnœžœž˜Kšžœžœ ˜Kšžœ ˜—Kšœž˜K˜Kšžœžœžœžœ˜K˜Kšœžœžœ˜1šœžœžœ˜&Kšœ žœžœ˜Kšœ8žœ˜=Kšœžœ˜—K˜šœ žœžœžœ˜5Kšœ˜K˜ K˜Kšœ˜K˜ Kšœ˜K˜K˜ K˜ K˜K˜—K˜šŸœžœžœ žœžœ žœžœ/žœžœžœžœžœ˜Kšœžœ]˜vKšžœžœžœ˜/—K˜š Ÿœžœžœžœžœ˜/Kšœžœ˜.šœžœ˜Kšžœ žœžœžœ˜5Kšžœžœžœžœ˜?—šžœžœ˜#Kš žœžœ žœžœžœ˜N—šžœ ˜Kšžœž˜!Kšžœžœ˜ —Kšžœ˜ —K˜š Ÿœžœžœžœžœžœ ˜gKšœžœ˜.Kšœ žœ˜šžœ,˜3Kšžœ žœžœžœ˜5Kšžœžœžœžœ˜@—Kšœ žœ˜'Kš œžœžœ žœžœžœ˜=šžœ˜KšžœC˜GKšžœV˜Z—K˜K˜#K˜.Kšžœ˜—K˜š Ÿœžœžœžœžœ˜-Kšœžœ˜.šžœ˜Kšžœ žœžœžœ˜5Kšžœžœžœžœ˜@——K˜š Ÿ œžœžœžœžœžœ˜=Kšœžœ˜.šžœ˜Kšžœ žœžœžœ˜5Kšžœžœžœžœ˜@——K˜šŸœžœžœžœ˜+Kšœžœ˜.šœ˜Kšžœ žœžœžœ˜5Kšžœžœžœžœ˜?—Kšœžœ˜Kš žœžœžœ žœžœžœ˜gKšžœ˜—K˜šŸœžœžœ˜Kšœžœ˜.šœ˜Kšžœ žœžœžœ˜5Kšžœžœžœžœ˜?—šžœ˜Kš žœžœ žœžœžœ˜K—Kšžœ˜—K˜š Ÿœžœžœ žœžœ˜3Kšœžœ˜.šžœ žœ˜(Kšžœ žœžœžœ˜5Kšžœžœžœžœ˜?—šžœžœ˜*Kšžœ žœžœžœ˜7—Kšœ6žœžœ˜@Kšžœ˜—K˜š Ÿœžœžœžœžœ˜/Kšœžœ˜.Kšžœ˜!—K˜š Ÿ œžœžœžœ žœ˜8Kšœžœ˜.šžœ˜Kšžœ žœžœžœ˜5Kšžœžœžœžœ˜@——K˜Kšžœ˜—…—¨