DIRECTORY
BasicTime USING [GetClockPulses, Pulses, PulsesToMicroseconds],
Endian USING [HFromCard],
IO USING [CharsAvail, Close, GetBlock, GetChar, PutBlock, PutChar, STREAM],
RefText USING [AppendRope, New, ObtainScratch, ReleaseScratch],
Rope USING [Concat, Fetch, FromChar, FromRefText, Length, ROPE],
XNS USING [Address, Socket],
XNSAddressParsing USING [AddressFromRope],
XNSSPPBuf USING [maxBodyBytes],
XNSStream USING [AttentionType, CloseReason, ConnectionClosed, Create, CreateListener, DestroyListener, FilterProc, GetStatus, Listener, ListenerProc, SendEndOfMessage, Timeout];
XNSStreamTest:
CEDAR
PROGRAM
IMPORTS BasicTime, Endian, IO, RefText, Rope, XNSAddressParsing, XNSStream
~ {
STREAM: TYPE ~ IO.STREAM;
Pulses: TYPE ~ BasicTime.Pulses;
Now: PROC RETURNS [Pulses] ~ INLINE { RETURN [ BasicTime.GetClockPulses[] ] };
Stream Testing ...
Filter: XNSStream.FilterProc ~ {
RETURN[TRUE] };
EchoFilter: XNSStream.FilterProc ~ {
RETURN[TRUE] };
Listener: XNSStream.ListenerProc ~ {
[stream: STREAM, remote: XNS.Address]
CleanUp: PROC ~ { IO.Close[self~stream, abort~TRUE] };
{
ENABLE {
XNSStream.ConnectionClosed => { CleanUp[]; CONTINUE };
UNWIND => CleanUp[]; };
blockSize: NAT ~ 2048;
block: REF TEXT ~ RefText.New[blockSize];
nChars: NAT;
DO
nChars ← IO.GetBlock[self~stream, block~block
! XNSStream.Timeout => RESUME];
IF nChars = 0 THEN [] ← XNSStream.GetStatus[self~stream, reset~TRUE];
ENDLOOP;
};
};
Listen:
PROC [socketNum:
CARDINAL]
RETURNS [listener: XNSStream.Listener ←
NIL] ~ {
ENABLE XNSStream.ConnectionClosed => {
CONTINUE };
listenerSocket: XNS.Socket;
TRUSTED { listenerSocket ← LOOPHOLE[Endian.HFromCard[socketNum]] };
listener ← XNSStream.CreateListener[socket~listenerSocket, worker~Listener, getTimeout~5000, putTimeout~5000, filter~Filter, echoFilter~EchoFilter];
};
UnListen:
PROC [listener: XNSStream.Listener] ~ {
XNSStream.DestroyListener[listener] };
Create:
PROC [hisAddr: Rope.
ROPE]
RETURNS [stream:
STREAM ←
NIL] ~ {
ENABLE XNSStream.ConnectionClosed => {
CONTINUE };
remote: XNS.Address;
remote ← XNSAddressParsing.AddressFromRope[hisAddr];
stream ← XNSStream.Create[remote~remote];
};
Destroy:
PROC [stream:
STREAM] ~ {
IO.Close[stream];
};
PutCharRope:
PROC [self:
STREAM, rope: Rope.
ROPE] ~ {
FOR i:
INT
IN [0 .. Rope.Length[rope])
DO
IO.PutChar[self~self, char~Rope.Fetch[base~rope, index~i]];
ENDLOOP;
XNSStream.SendEndOfMessage[self];
};
PutNChars:
PROC [self:
STREAM, n:
INT, c:
CHAR ← 'X] ~ {
FOR i: INT IN [1 .. n] DO IO.PutChar[self~self, char~c] ENDLOOP;
XNSStream.SendEndOfMessage[self];
};
PutBlockRope:
PROC [self:
STREAM, rope: Rope.
ROPE] ~ {
len: NAT ~ Rope.Length[rope];
block: REF TEXT;
block ← RefText.ObtainScratch[len];
block ← RefText.AppendRope[to~block, from~rope, start~0, len~len];
IO.PutBlock[self~self, block~block, startIndex~0, count~len];
XNSStream.SendEndOfMessage[self~self];
RefText.ReleaseScratch[block];
};
PutNBlock:
PROC [self:
STREAM, n:
INT, c:
CHAR ← 'X]
RETURNS [usecs:
LONG
CARDINAL] ~ {
startTime: Pulses ~ Now[];
len: NAT ~ XNSSPPBuf.maxBodyBytes;
block: REF TEXT;
block ← RefText.ObtainScratch[len];
FOR i: INT IN [0 .. block.maxLength) DO block[i] ← c; ENDLOOP;
block.length ← len;
FOR chunk:
INT ← n, chunk-len
WHILE chunk > 0
DO
count: NAT ~ IF chunk > len THEN len ELSE NAT[chunk];
IO.PutBlock[self~self, block~block, startIndex~0, count~count];
ENDLOOP;
XNSStream.SendEndOfMessage[self];
usecs ← BasicTime.PulsesToMicroseconds[ BasicTime.GetClockPulses[] - startTime ];
RefText.ReleaseScratch[block];
};
GetCharRope:
PROC [self:
STREAM]
RETURNS [rope: Rope.
ROPE ←
NIL] ~ {
[] ← XNSStream.GetStatus[self~self, reset~TRUE]; -- clear status.
WHILE
IO.CharsAvail[self~self, wait~
FALSE] > 0
DO
c: CHAR ~ IO.GetChar[self~self];
rope ← Rope.Concat[rope, Rope.FromChar[c]];
ENDLOOP;
};
GetBlockRope:
PROC [self:
STREAM]
RETURNS [rope: Rope.
ROPE ←
NIL] ~ {
blockSize: NAT ~ 100;
block: REF TEXT ~ RefText.ObtainScratch[blockSize];
n: NAT;
[] ← XNSStream.GetStatus[self~self, reset~TRUE]; -- clear status.
WHILE (n ←
IO.CharsAvail[self~self, wait~
FALSE]) > 0
DO
[] ← IO.GetBlock[self~self, block~block, startIndex~0, count~MIN[n,blockSize]];
rope ← Rope.Concat[rope, Rope.FromRefText[block]];
ENDLOOP;
RefText.ReleaseScratch[block];
};