-- edited by Teitelman  March 24, 1982 7:45 pm 

DIRECTORY
	ViewersIOStream, IOStream, Rope,  
	ViewerClasses, TypeScript; 

ViewersIOStreamImpl: PROGRAM 

	IMPORTS IOStream, TypeScript  
	EXPORTS ViewersIOStream
	SHARES IOStream = 

BEGIN 

Viewer: TYPE = ViewerClasses.Viewer;

ViewerStreamData: TYPE = REF ViewerStreamDataRecord;
ViewerStreamDataRecord: TYPE = RECORD[
	viewer: Viewer,
	echoTo: IOStream.Handle ← NIL
	];

ViewerInStreamProcs: REF IOStream.StreamProcs ← IOStream.CreateRefStreamProcs[
	getChar: ViewerGetChar, 
	close: ViewerClose,
	endOf: ViewerEndOf,
	charsAvail: ViewerCharsAvail, 
	setEcho: ViewerSetEcho,
	name: "Viewers Input"
	];
	
ViewerOutStreamProcs: REF IOStream.StreamProcs ← IOStream.CreateRefStreamProcs[
	putChar: ViewerPutChar,
	putBlock: ViewerPutBlock,
	close: ViewerClose,
	endOf: ViewerEndOf,
	eraseChar: ViewerEraseChar,
	name: "Viewers Output"
];

CreateViewerStreams: PUBLIC PROC [name: Rope.ROPE ← NIL, viewer: Viewer ← NIL] RETURNS [in: IOStream.Handle, out: IOStream.Handle] =
{OPEN IOStream;
IF viewer = NIL THEN viewer ← TypeScript.Create[info: [name: name]];
{in ← CreateProcsStream[streamProcs: ViewerInStreamProcs, streamData: NEW[ViewerStreamDataRecord ← [viewer: viewer]] ];
out ← CreateProcsStream[streamProcs: ViewerOutStreamProcs, streamData: NEW[ViewerStreamDataRecord ← [viewer: viewer]] ];
[] ← SetEcho[in, out]; -- do the echoing at the level of handle, since this permits echoing to an arbitrary handle.
};
};

ViewerGetChar: PROCEDURE [self: IOStream.Handle] RETURNS [char: CHARACTER] = 
BEGIN
data: ViewerStreamData ← NARROW[self.streamData];
IF data.viewer.destroyed THEN IOStream.Error[StreamClosed];
char ← TypeScript.GetChar[data.viewer];
IF data.echoTo # NIL THEN IOStream.PutChar[data.echoTo, char];
END; -- of ViewerGetChar

ViewerPutChar: PROCEDURE[self: IOStream.Handle, char: CHARACTER] =
BEGIN
data: ViewerStreamData ← NARROW[self.streamData];
IF data.viewer.destroyed THEN IOStream.Error[StreamClosed];
TypeScript.PutChar[data.viewer, char];
END; -- of ViewerPutChar

ViewerPutBlock: PROCEDURE[self: IOStream.Handle, block: REF READONLY TEXT, startIndex: NAT, stopIndexPlusOne: NAT] =
BEGIN
data: ViewerStreamData ← NARROW[self.streamData];
IF data.viewer.destroyed THEN IOStream.Error[StreamClosed];
TypeScript.PutText[ts: data.viewer, text: block, start: startIndex, stopPlusOne: stopIndexPlusOne];
END; -- of ViewerPutChar

ViewerReset: PROCEDURE[self: IOStream.Handle] =
BEGIN
data: ViewerStreamData ← NARROW[self.streamData];
TypeScript.Reset[data.viewer];
END; -- of ViewerClose

ViewerClose: PROCEDURE[self: IOStream.Handle, abort: BOOLEAN] =
BEGIN
data: ViewerStreamData ← NARROW[self.streamData];
IF ~data.viewer.destroyed THEN TypeScript.Destroy[data.viewer];
END; -- of ViewerClose

ViewerEndOf: PROCEDURE[self: IOStream.Handle] RETURNS [BOOLEAN] = 
BEGIN
data: ViewerStreamData ← NARROW[self.streamData];
IF data.viewer.destroyed THEN IOStream.Error[StreamClosed];
RETURN[FALSE];
END; -- ViewerEndOf

ViewerCharsAvail: PROCEDURE[self: IOStream.Handle] RETURNS [BOOLEAN] = 
BEGIN
data: ViewerStreamData ← NARROW[self.streamData];
IF data.viewer.destroyed THEN IOStream.Error[StreamClosed];
RETURN[TypeScript.CharsAvailable[data.viewer]];
END; -- ViewerCharsAvail

ViewerEraseChar: PROCEDURE[self: IOStream.Handle, char: CHARACTER] =
BEGIN
data: ViewerStreamData ← NARROW[self.streamData];
IF data.viewer.destroyed THEN IOStream.Error[StreamClosed];
TypeScript.BackSpace[data.viewer];
END; -- of ViewerEraseChar

ViewerSetEcho: PROCEDURE[self: IOStream.Handle, echoTo: IOStream.Handle] RETURNS[oldEcho: IOStream.Handle] =
BEGIN
data: ViewerStreamData ← NARROW[self.streamData];
IF data.viewer.destroyed THEN IOStream.Error[StreamClosed];
oldEcho ← data.echoTo;
data.echoTo ← echoTo;
END; -- of ViewerSetEcho

DefaultCreateIn: PROC RETURNS [IOStream.Handle] = 
-- creates a viewer. sets defaultOut to same window.
{in, out: IOStream.Handle;
[in, out] ← CreateViewerStreams[];
IOStream.SetDefaultStreams[out: out];
RETURN[in];
};

DefaultCreateError, DefaultCreateOut: PROC RETURNS [IOStream.Handle] = 
{in, out: IOStream.Handle;
[in, out] ← CreateViewerStreams[];
IOStream.SetDefaultStreams[in: in];
RETURN[out];
};

CreateViewerStream1: PROC [name: Rope.ROPE ← NIL] RETURNS [in: IOStream.Handle, out: IOStream.Handle] = {[in, out] ← CreateViewerStreams[name]};

IOStream.SetTTYCreate[CreateViewerStream1];

IOStream.SetDefaultStreams[createIn: DefaultCreateIn, createOut: DefaultCreateOut, createError: DefaultCreateError];


END.

March 24, 1982 7:46 pm W. Teitelman. Fixed Close to check if viewer already destroyed. Added name argument to CreateRefStreamProcs.
13-Apr-82 14:05:22 W. Teitelman. Added checks for whether viewer was destroyed, and if so, raised IOStream error.