XNSPSNetworkUserImpl.mesa
Copyright Ó 1984, 1985, 1987, Xerox Corporation. All rights reserved.
Tim Diebert: April 16, 1987 7:57:21 am PDT
DIRECTORY
IO,
PupStream,
PupWKS USING [telnet],
Rope,
RuntimeError USING [UNCAUGHT],
SimpleTerminal USING [TurnOn],
XNSPSCommander USING [TalkToUser],
XNSPSMessages,
XNSPSUser;
XNSPSNetworkUserImpl: CEDAR MONITOR
IMPORTS IO, PupStream, RuntimeError, SimpleTerminal, XNSPSCommander, XNSPSMessages
EXPORTS XNSPSUser
= {
ROPE: TYPE ~ Rope.ROPE;
STREAM: TYPE ~ IO.STREAM;
TalkWithUser: PUBLIC PROC [stream: IO.STREAM] = {
inProcs: REF IO.StreamProcs ← IO.CreateStreamProcs[
variety: input,
class: $pupRemoteUser,
getChar: GetChar,
endOf: EndOf,
flush: Flush,
close: Close];
data: StreamState ← NEW[StreamStateRep];
in: STREAMIO.CreateStream[streamProcs: inProcs, streamData: data];
outProcs: REF IO.StreamProcs ← IO.CreateStreamProcs[
variety: output,
class: $pupRemoteUser,
putChar: PutChar,
endOf: EndOf,
flush: Flush,
eraseChar: EraseChar,
close: Close];
out: STREAMIO.CreateStream[streamProcs: outProcs, streamData: data];
data.stream ← stream;
XNSPSCommander.TalkToUser[in, out];
};
StreamState: TYPE ~ REF StreamStateRep;
StreamStateRep: TYPE ~ RECORD [
flushed: BOOLFALSE, stream: STREAM, closed: BOOLFALSE];
GetChar: PROC [self: STREAM] RETURNS [CHAR] = TRUSTED {c: CHAR; ignore: INT ← 0;
data: StreamState ← NARROW[self.streamData];
IF NOT data.flushed THEN SendNow[self];
WHILE ignore >= 0 DO
ENABLE PupStream.StreamClosing, PupStream.Timeout => GOTO Closing;
mark: NAT ← 0; timingMark: NAT = 5; timingMarkReply: NAT = 6; dataMark: NAT = 1;
charsAvail: INT ← 0; bytes: PACKED ARRAY [0..4] OF CHAR;
charsAvail ← IO.UnsafeGetBlock[data.stream, [LOOPHOLE[LONG[@bytes]], 0, 1]];
IF charsAvail # 0 THEN c ← bytes[0]
ELSE {gotMark: BOOLFALSE;
IF data.stream.GetInfo.class = $Pup THEN {gotMark ← TRUE;
mark ← PupStream.ConsumeMark[data.stream
! RuntimeError.UNCAUGHT => {gotMark ← FALSE; CONTINUE}]}};
SELECT mark FROM 0 => NULL; dataMark => {ignore ← 1};
timingMark => {ignore ← 1}; ENDCASE => ignore ← 2;
ignore ← ignore - 1;
REPEAT Closing => {data.closed ← TRUE; ERROR IO.EndOfStream[stream: self]};
ENDLOOP;
RETURN [c]
};
PutChar: PROC[self: IO.STREAM, char: CHAR] = BEGIN
data: StreamState ← NARROW[self.streamData];
IO.PutChar[data.stream, char];
IF char = '\n THEN IO.PutChar[data.stream, '\l];
data.flushed ← FALSE;
END;
EndOf: PUBLIC PROC[self: IO.STREAM] RETURNS [BOOL] = BEGIN
data: StreamState ← NARROW[self.streamData];
RETURN [IO.EndOf[data.stream]];
END;
EraseChar: PROC [self: STREAM, char: CHAR] = {
data: StreamState ← NARROW[self.streamData];
IO.PutChar[data.stream, IO.BS];
data.flushed ← FALSE;
};
Flush: PUBLIC PROC [ self: IO.STREAM ] = BEGIN
data: StreamState ← NARROW[self.streamData];
IO.Flush[data.stream];
data.flushed ← TRUE;
END;
Close: ENTRY PROC [self: IO.STREAM, abort: BOOLFALSE] = BEGIN
data: StreamState;
IF self = NIL THEN RETURN;
IF self.streamData = NIL THEN RETURN;
data ← NARROW[self.streamData];
IF NOT data.closed THEN IO.Close[data.stream];
data.closed ← TRUE;
END;
SendNow: PROC [self: IO.STREAM] = BEGIN
data: StreamState ← NARROW[self.streamData];
IO.Flush[data.stream];
data.flushed ← TRUE;
END;
logStream: IO.STREAMNIL;
MakeLogViewer: PROC = {
IF logStream # NIL THEN RETURN;
SimpleTerminal.TurnOff[];
logStream ← SimpleTerminal.TurnOn[].out;
XNSPSMessages.RegisterTTY[logStream];
};
NewConnection: PupStream.ListenerProc = TRUSTED {
TalkWithUser[stream ! PupStream.StreamClosing => CONTINUE];
IO.Close[stream];
};
Init: PROC = TRUSTED {
MakeLogViewer[];
pupListener ← PupStream.CreateListener[
local: PupWKS.telnet,
worker: NewConnection,
getTimeout: 300000,
putTimeout: 300000
];
};
pupListener: PupStream.Listener ← NIL;
Init[];
}.