<> <> <> DIRECTORY IO, Process USING [GetPriority, Priority, priorityForeground, SetPriority], TTY, TTYPort USING [ChannelQuiesced, ChannelHandle, CharsAvailable, Create, Delete, Get, Put, Quiesce, SetParameter, TransferStatus]; TTYDLionImpl: CEDAR MONITOR IMPORTS IO, Process, TTY, TTYPort EXPORTS TTY ~ BEGIN OutOfInstances: PUBLIC ERROR = CODE; Create: PUBLIC ENTRY PROC [] RETURNS [stream: IO.STREAM] = TRUSTED BEGIN streamProcs: REF IO.StreamProcs _ IO.CreateStreamProcs[class: $TTY, variety: inputOutput, getChar: GetChar, charsAvail: CharsAvail, putChar: PutChar, close: Close]; IF myTTY.channel # NIL THEN RETURN WITH ERROR TTY.OutOfInstances; myTTY.channel _ TTYPort.Create[0]; myTTY.breakDetected _ FALSE; myTTY.breakCount _ 0; TTYPort.SetParameter[myTTY.channel, [dataSetReady[TRUE]]]; TTYPort.SetParameter[myTTY.channel, [clearToSend[TRUE]]]; TTYPort.SetParameter[myTTY.channel, [lineSpeed[bps9600]]]; stream _ IO.CreateStream[streamProcs, NIL]; END; myTTY: RECORD [ breakDetected: BOOLEAN _ NULL, breakCount: INTEGER _ NULL, channel: TTYPort.ChannelHandle _ NIL -- also on/off flag ] _ [NULL, NULL, NIL]; PutChar: ENTRY PROC [self: IO.STREAM, char: CHAR] = BEGIN PutByteInternal[char]; END; PutByteInternal: INTERNAL PROC [c: CHAR] = TRUSTED { PutIt: PROCEDURE [c: CHAR] = TRUSTED INLINE {[] _ TTYPort.Put[myTTY.channel, c ! TTYPort.ChannelQuiesced => CONTINUE]}; IF myTTY.channel = NIL THEN RETURN; PutIt[c]; SELECT c FROM IO.CR => PutIt[IO.LF]; IO.BS => {PutIt[IO.SP]; PutIt[IO.BS]}; ENDCASE; }; GetChar: PROC [self: IO.STREAM] RETURNS [c: CHAR _ ' ] = TRUSTED { csmPriority: Process.Priority = Process.priorityForeground; NotifyNextOfKin: ENTRY PROC = TRUSTED INLINE {myTTY.channel _ NIL; NOTIFY receiveDeath}; oldPriority: Process.Priority = Process.GetPriority[]; ProcessChar: ENTRY PROC RETURNS [done: BOOLEAN _ FALSE] = TRUSTED INLINE { IF stat = breakDetected OR ch = controlStop THEN { myTTY.breakDetected _ TRUE; myTTY.breakCount _ myTTY.breakCount + 1; TTYPort.SetParameter[myTTY.channel, [breakDetectedClear[TRUE]] ! TTYPort.ChannelQuiesced => CONTINUE]} ELSE {c _ ch; RETURN[TRUE]}}; ch: CHARACTER; stat: TTYPort.TransferStatus; Process.SetPriority[csmPriority]; DO [ch, stat] _ TTYPort.Get[myTTY.channel ! TTYPort.ChannelQuiesced => EXIT]; IF stat=aborted OR stat=abortedByDelete THEN EXIT; IF ProcessChar[] THEN RETURN; ENDLOOP; Process.SetPriority[oldPriority]; NotifyNextOfKin[] }; CharsAvail: PUBLIC PROC [self: IO.STREAM, wait: BOOL] RETURNS [INT] = TRUSTED BEGIN RETURN [TTYPort.CharsAvailable[myTTY.channel]]; END; Close: ENTRY PROC[self: IO.STREAM, abort: BOOL _ FALSE] = TRUSTED BEGIN channel: TTYPort.ChannelHandle = myTTY.channel; IF channel=NIL THEN RETURN; TTYPort.Quiesce[channel]; <> TTYPort.Delete[myTTY.channel]; myTTY.channel _ NIL; END; EndOf: ENTRY PROC[self: IO.STREAM] RETURNS [BOOL] = BEGIN RETURN [FALSE]; END; controlStop: CHARACTER = 36C; receiveDeath: CONDITION; END.