-- File: PupByteStreams.mesa, Last Edit: HGM January 20, 1981 12:56 AM -- Initialize options, HGM February 24, 1981 2:31 PM DIRECTORY Environment USING [Byte], Runtime USING [GlobalFrame], ByteBlt USING [ByteBlt], Stream USING [ Byte, Word, Block, CompletionCode, defaultInputOptions, Handle, InputOptions, LongBlock, Object, ShortBlock, SSTChange, SubSequenceType, TimeOut], CommFlags USING [doDebug], DriverDefs USING [Glitch], PupPktDefs USING [ PupPktStream, PupPktStreamAbort, PupPktStreamDestroy, PupPktStreamMake], PupStream USING [PupOpenMode], PupDefs USING [ GetFreePupBuffer, ReturnFreePupBuffer, GetPupContentsBytes, SetPupContentsBytes, Pair, PupAddress, PupBuffer, PupSocketID, Tocks], PupTypes USING [fillInSocketID]; PupByteStreams: MONITOR IMPORTS Runtime, Stream, ByteBlt, DriverDefs, PupPktDefs, PupDefs EXPORTS PupStream = BEGIN OPEN DriverDefs, PupDefs; -- Manager data free: POINTER TO FRAME[PupByteStreams] ← LOOPHOLE[Runtime.GlobalFrame[ PupByteStreamCreate]]; GetInstance: ENTRY PROCEDURE RETURNS [him: POINTER TO FRAME[PupByteStreams]] = BEGIN IF free = NIL THEN BEGIN him ← NEW PupByteStreams; START him; -- Do initialization code RETURN; END; him ← free; free ← free.next; END; FreeInstance: ENTRY PROCEDURE [him: POINTER TO FRAME[PupByteStreams]] = BEGIN him.next ← free; free ← him; END; next: POINTER TO FRAME[PupByteStreams] ← NIL; myPupByteStream: Stream.Object ← [options: , getByte: GetByte, putByte: PutByte, getWord: GetWord, putWord: PutWord, get: GetBlock, put: PutBlock, setSST: SendMark, sendAttention: SendAttention, waitAttention: WaitAttention, delete: ]; myPs: PupPktDefs.PupPktStream; -- Beware, things don't get reinitialized when a module is reused inputBuffer: PupBuffer; inputFinger: CARDINAL; inputBufferSize: CARDINAL; inputSST: Stream.SubSequenceType; outputBuffer: PupBuffer; outputFinger: CARDINAL; -- 0 if aData/aMark sent outputBufferSize: CARDINAL; HandleLooksLikeGarbage: PUBLIC ERROR = CODE; LeftAndRight: TYPE = MACHINE DEPENDENT RECORD [left, right: Environment.Byte]; PupByteStreamCreate: PUBLIC PROCEDURE [remote: PupAddress, ticks: Tocks] RETURNS [Stream.Handle] = BEGIN RETURN[ PupByteStreamMake[PupTypes.fillInSocketID, remote, ticks, sendRfc, [0, 0]]]; END; PupByteStreamMake: PUBLIC PROCEDURE [ local: PupSocketID, remote: PupAddress, ticks: Tocks, mode: PupStream.PupOpenMode, id: Pair] RETURNS [Stream.Handle] = BEGIN newPs: PupPktDefs.PupPktStream; him: POINTER TO FRAME[PupByteStreams]; -- It is ok to UNWIND here if PupPktStreamMake doesn't work. newPs ← PupPktDefs.PupPktStreamMake[local, remote, ticks, mode, id]; him ← GetInstance[]; -- Initialization him.myPs ← newPs; him.myPupByteStream.options ← Stream.defaultInputOptions; him.myPupByteStream.delete ← Destroy; him.inputBuffer ← NIL; him.inputSST ← 0; him.outputBuffer ← NIL; him.outputFinger ← 0; him.outputBufferSize ← 0; RETURN[@him.myPupByteStream]; END; PupByteStreamAbort: PUBLIC --ENTRY--PROCEDURE [bs: Stream.Handle, e: STRING] = BEGIN ENABLE UNWIND => NULL; him: POINTER TO FRAME[PupByteStreams] = LOOPHOLE[Runtime.GlobalFrame[bs.put]]; IF CommFlags.doDebug AND bs.delete # Destroy THEN Glitch[HandleLooksLikeGarbage]; PupPktDefs.PupPktStreamAbort[him.myPs, e]; END; Destroy: PUBLIC --ENTRY--PROCEDURE [bs: Stream.Handle] = BEGIN ENABLE UNWIND => NULL; him: POINTER TO FRAME[PupByteStreams] = LOOPHOLE[Runtime.GlobalFrame[bs.put]]; IF CommFlags.doDebug AND bs.delete # Destroy THEN Glitch[HandleLooksLikeGarbage]; bs.delete ← NIL; PupPktDefs.PupPktStreamDestroy[him.myPs]; IF him.inputBuffer # NIL THEN ReturnBuffer[@him.inputBuffer]; IF him.outputBuffer # NIL THEN ReturnBuffer[@him.outputBuffer]; FreeInstance[him]; END; SendAttention: PROCEDURE [sH: Stream.Handle, byte: Stream.Byte] = BEGIN myPs.sendAttention[]; END; WaitAttention: PROCEDURE [sH: Stream.Handle] RETURNS [Stream.Byte] = BEGIN myPs.waitForAttention[]; RETURN[0]; END; GetByte: --ENTRY--PROCEDURE [sH: Stream.Handle] RETURNS [byte: Stream.Byte] = BEGIN ENABLE UNWIND => NULL; IF inputBuffer # NIL AND inputFinger + 2 < inputBufferSize THEN BEGIN -- "+2" lets GetBlock give back the buffer if we take the last byte byte ← inputBuffer.pupBytes[inputFinger]; inputFinger ← inputFinger + 1; RETURN; END ELSE BEGIN array: PACKED ARRAY [0..1] OF Stream.Byte; [] ← sH.get[sH, [@array, 0, 1], [FALSE, FALSE, FALSE, TRUE, TRUE]]; RETURN[array[0]]; END; END; GetWord: --ENTRY--PROCEDURE [sH: Stream.Handle] RETURNS [word: Stream.Word] = BEGIN OPEN w: LOOPHOLE[word, LeftAndRight]; w.left ← GetByte[sH]; w.right ← GetByte[sH]; END; GetBlock: --ENTRY--PROCEDURE [ sH: Stream.Handle, block: Stream.Block, options: Stream.InputOptions] RETURNS [ bytesTransferred: CARDINAL, why: Stream.CompletionCode, sst: Stream.SubSequenceType] = BEGIN ENABLE UNWIND => NULL; input: Stream.Block; moved: CARDINAL; bytesTransferred ← 0; sst ← inputSST; why ← normal; WHILE block.startIndex < block.stopIndexPlusOne DO UNTIL inputBuffer # NIL DO inputFinger ← 0; inputBuffer ← myPs.get[]; IF inputBuffer = NIL THEN SIGNAL Stream.TimeOut[block.startIndex] ELSE IF inputBuffer.pupType = mark OR inputBuffer.pupType = aMark THEN BEGIN sst ← inputSST ← inputBuffer.pupBytes[0]; ReturnBuffer[@inputBuffer]; IF options.signalSSTChange THEN SIGNAL Stream.SSTChange[inputSST, block.startIndex] ELSE BEGIN why ← sstChange; RETURN; END; END; ENDLOOP; inputBufferSize ← GetPupContentsBytes[inputBuffer]; input ← [blockPointer: @inputBuffer.pupBytes, startIndex: inputFinger, stopIndexPlusOne: inputBufferSize]; moved ← ByteBlt.ByteBlt[block, input]; bytesTransferred ← bytesTransferred + moved; block.startIndex ← block.startIndex + moved; inputFinger ← inputFinger + moved; IF inputFinger = inputBufferSize THEN BEGIN ReturnBuffer[@inputBuffer]; END; IF inputBuffer = NIL AND block.startIndex < block.stopIndexPlusOne AND options.signalLongBlock THEN BEGIN SIGNAL Stream.LongBlock[block.startIndex]; END; IF inputBuffer = NIL AND options.terminateOnEndPhysicalRecord THEN BEGIN why ← endRecord; EXIT; END; ENDLOOP; IF inputBuffer # NIL AND options.signalShortBlock THEN BEGIN ERROR Stream.ShortBlock; END; END; PutByte: --ENTRY--PROCEDURE [sH: Stream.Handle, byte: Stream.Byte] = BEGIN ENABLE UNWIND => NULL; IF outputBuffer # NIL AND outputFinger + 2 < outputBufferSize THEN BEGIN -- "+2" lets PutBlock flush the buffer if we fill the last byte outputBuffer.pupBytes[outputFinger] ← byte; outputFinger ← outputFinger + 1; RETURN; END ELSE BEGIN array: PACKED ARRAY [0..1] OF Stream.Byte ← [byte, ]; PutBlock[sH, [@array, 0, 1], FALSE]; END; END; PutWord: --ENTRY--PROCEDURE [sH: Stream.Handle, word: Stream.Word] = BEGIN OPEN w: LOOPHOLE[word, LeftAndRight]; sH.putByte[sH, w.left]; sH.putByte[sH, w.right]; END; PutBlock: --ENTRY--PROCEDURE [ sH: Stream.Handle, block: Stream.Block, endPhysicalRecord: BOOLEAN] = BEGIN ENABLE UNWIND => NULL; output: Stream.Block; moved: CARDINAL; IF outputBufferSize = 0 THEN outputBufferSize ← myPs.getSenderSizeLimit[]; WHILE block.startIndex < block.stopIndexPlusOne DO IF outputFinger = outputBufferSize THEN FlushOutputBuffer[]; IF outputBuffer = NIL THEN BEGIN outputBuffer ← GetFreePupBuffer[]; outputFinger ← 0; END; output ← [blockPointer: @outputBuffer.pupBytes, startIndex: outputFinger, stopIndexPlusOne: outputBufferSize]; moved ← ByteBlt.ByteBlt[output, block]; block.startIndex ← block.startIndex + moved; outputFinger ← outputFinger + moved; ENDLOOP; IF (endPhysicalRecord AND outputFinger # 0) OR outputFinger = outputBufferSize THEN BEGIN IF outputBuffer = NIL THEN BEGIN outputBuffer ← GetFreePupBuffer[]; outputFinger ← 0; END; IF endPhysicalRecord THEN outputBuffer.pupType ← aData; FlushOutputBuffer[]; IF endPhysicalRecord THEN outputFinger ← 0; END; END; SendMark: --ENTRY--PROCEDURE [sH: Stream.Handle, sst: Stream.SubSequenceType] = BEGIN ENABLE UNWIND => NULL; FlushOutputBuffer[]; outputFinger ← 0; myPs.putMark[sst]; END; FlushOutputBuffer: PROCEDURE = BEGIN b: PupBuffer; -- don't leave outputBuffer dangling in case of StreamClosing IF outputBuffer = NIL THEN RETURN; b ← outputBuffer; outputBuffer ← NIL; SetPupContentsBytes[b, outputFinger]; myPs.put[b]; END; ReturnBuffer: PROCEDURE [p: POINTER TO PupBuffer] = BEGIN b: PupBuffer; b ← p↑; p↑ ← NIL; ReturnFreePupBuffer[b]; END; END.