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;
= {
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: STREAM ← IO.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: STREAM ← IO.CreateStream[streamProcs: outProcs, streamData: data];
data.stream ← stream;
XNSPSCommander.TalkToUser[in, out];
};
StreamState: TYPE ~ REF StreamStateRep;
StreamStateRep:
TYPE ~
RECORD [
flushed: BOOL ← FALSE, stream: STREAM, closed: BOOL ← FALSE];
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:
BOOL ←
FALSE;
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:
BOOL ←
FALSE] =
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.STREAM ← NIL;
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[];
}.