-- 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.