-- File: PupByteStreams.mesa, Last Edit: -- HGM January 5, 1980 4:13 PM -- MAS August 8, 1980 2:20 PM -- Copyright Xerox Corporation 1979, 1980 DIRECTORY ByteBltDefs: FROM "ByteBltDefs" USING [ByteBlt], Stream: FROM "Stream" USING [ Byte, Block, CompletionCode, defaultInputOptions, Handle, InputOptions, LongBlock, Object, ShortBlock, SSTChange, SubSequenceType, TimeOut], CommUtilDefs: FROM "CommUtilDefs" USING [SelfDestruct], DriverDefs: FROM "DriverDefs" USING [doDebug, Glitch], PupPktDefs: FROM "PupPktDefs" USING [PupPktStream, PupPktStreamDestroy, PupPktStreamMake], PupStream: FROM "PupStream" USING [PupOpenMode], PupDefs: FROM "PupDefs" USING [ GetFreePupBuffer, ReturnFreePupBuffer, GetPupContentsBytes, SetPupContentsBytes, Pair, PupAddress, PupBuffer, PupSocketID, Tocks], PupTypes: FROM "PupTypes" USING [fillInSocketID]; PupByteStreams: MONITOR IMPORTS ByteBltDefs, Stream, CommUtilDefs, DriverDefs, PupPktDefs, PupDefs EXPORTS PupStream = BEGIN OPEN DriverDefs, PupDefs; myPupByteStream: Stream.Object ← [ options: Stream.defaultInputOptions, get: GetBlock, put: PutBlock, setSST: SendMark, sendAttention: SendAttention, waitAttention: WaitAttention, delete: Destroy ]; myPs: PupPktDefs.PupPktStream; inputBuffer: PupBuffer ← NIL; inputFinger: CARDINAL; inputSST: Stream.SubSequenceType ← 0; outputBuffer: PupBuffer ← NIL; outputFinger: CARDINAL ← 0; -- 0 if aData/aMark sent outputBufferSize: CARDINAL ← 0; HandleLooksLikeGarbage: PUBLIC ERROR = CODE; 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 ← NEW PupByteStreams; START him; -- Do initialization code him.myPs ← newPs; RETURN[@him.myPupByteStream]; END; Destroy: PUBLIC --ENTRY-- PROCEDURE [bs: Stream.Handle] = BEGIN ENABLE UNWIND => NULL; IF doDebug AND bs.delete#Destroy THEN Glitch[HandleLooksLikeGarbage]; bs.delete ← LOOPHOLE[3]; PupPktDefs.PupPktStreamDestroy[myPs]; IF inputBuffer#NIL THEN ReturnBuffer[@inputBuffer]; IF outputBuffer#NIL THEN ReturnBuffer[@outputBuffer]; CommUtilDefs.SelfDestruct[]; 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; GetBlock: --ENTRY-- PROCEDURE[sH: Stream.Handle, block: Stream.Block, options: Stream.InputOptions] RETURNS[bytesTransferred: CARDINAL, why: Stream.CompletionCode, sst: Stream.SubSequenceType] = -- NB: block has been passed by VALUE, so we are upadting our copy, not the clients 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; input ← [ blockPointer: @inputBuffer.pupBytes, startIndex: inputFinger, stopIndexPlusOne: GetPupContentsBytes[inputBuffer] ]; moved ← ByteBltDefs.ByteBlt[block,input]; bytesTransferred ← bytesTransferred+moved; block.startIndex ← block.startIndex+moved; inputFinger ← inputFinger+moved; IF inputFinger=input.stopIndexPlusOne 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; PutBlock: --ENTRY-- PROCEDURE [sH: Stream.Handle, block: Stream.Block, endPhysicalRecord: BOOLEAN] = -- NB: Block has been passed by VALUE, so we are updating our copy, not the clients 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 ← ByteBltDefs.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.