<> <> <> <> <> <> <> <> <> <> <> DIRECTORY Ascii USING [BS, SP, CR, TAB], BasicTime USING [FromPupTime, GMT, Now], IO USING [card, CharsAvail, CreateStream, CreateStreamProcs, GetChar, PutChar, PutFR, PutRope, STREAM, StreamProcs, time], Process USING [DisableTimeout, Pause, priorityRealTime, SetPriority, SetTimeout, Ticks], Rope USING [ROPE], SimpleTerminal USING [], SystemVersion USING [bootFileDate, release], <> TTY USING [Create]; SimpleTerminalTTYImpl: MONITOR LOCKS m USING m: POINTER TO MONITORLOCK IMPORTS BasicTime, IO, Process, SystemVersion, TTY EXPORTS SimpleTerminal = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; <> <> <> State: TYPE = {off, turningOn, on, turningOff, joining}; <> terminalLock: MONITORLOCK; state: State _ off; stateChange: CONDITION _ [timeout: 0]; <> turnOnCount: NAT _ 0; <> inStream, outStream: STREAM _ NIL; keyboardWatcher: PROCESS; <<>> <> TurnOn: PUBLIC SAFE PROC [nameStripe: ROPE _ NIL] RETURNS [in, out: STREAM] = TRUSTED { TurnOnEntryA: ENTRY PROC [m: POINTER TO MONITORLOCK] RETURNS [turnOnNeeded: BOOL] = -- INLINE -- { oldState: State = state; DO SELECT state FROM off => { IF turnOnCount ~= 0 THEN ERROR; <> state _ turningOn; EXIT }; turningOff => { <> state _ on; EXIT }; on => EXIT; ENDCASE; WAIT stateChange; ENDLOOP; <<[] _ terminal.Select[];>> turnOnCount _ turnOnCount.SUCC; IF oldState ~= state THEN BROADCAST stateChange; RETURN[state ~= on] }; TurnOnEntryB: ENTRY PROC [m: POINTER TO MONITORLOCK] = -- INLINE -- { state _ on; BROADCAST stateChange; }; IF TurnOnEntryA[@terminalLock] THEN { IF nameStripe = NIL THEN nameStripe _ IO.PutFR["Cedar %g.%g.%g of %t", IO.card[SystemVersion.release.major], IO.card[SystemVersion.release.minor], IO.card[SystemVersion.release.patch], IO.time[BasicTime.FromPupTime[SystemVersion.bootFileDate]] ]; IF ttyStream = NIL THEN {ttyStream _ TTY.Create[]; IO.PutChar[ttyStream, '\n]; charPos _ 1}; InitScreen[nameStripe]; keyboardWatcher _ FORK ProcessKeyboard[]; inStream _ IO.CreateStream[streamProcs: inStreamProcs, streamData: NIL]; outStream _ IO.CreateStream[streamProcs: outStreamProcs, streamData: NIL]; TurnOnEntryB[@terminalLock]; }; RETURN [inStream, outStream] }; ttyStream: IO.STREAM _ NIL; TurnOff: PUBLIC SAFE PROC = TRUSTED { TurnOffEntry: ENTRY PROC [m: POINTER TO MONITORLOCK] RETURNS [shutdown: BOOL] = -- INLINE -- { DO SELECT state FROM off => RETURN[FALSE]; on => EXIT; ENDCASE => WAIT stateChange; ENDLOOP; IF (shutdown _ ((turnOnCount _ turnOnCount.PRED) = 0)) THEN { state _ turningOff; BROADCAST stateChange; }; }; [] _ TurnOffEntry[@terminalLock]; }; InputTimeout: PUBLIC SAFE SIGNAL = CODE; SetInputTimeout: PUBLIC SAFE PROC [ticks: Process.Ticks] = TRUSTED { SetInputTimeoutEntry: ENTRY PROC [m: POINTER TO MONITORLOCK] = INLINE { IF ticks = 0 THEN Process.DisableTimeout[@charactersAvailable] ELSE Process.SetTimeout[@charactersAvailable, ticks]; }; SetInputTimeoutEntry[@keyboardLock]; }; EnableCursorTracking: PUBLIC SAFE PROC = TRUSTED {}; DisableCursorTracking: PUBLIC SAFE PROC = TRUSTED {}; <<>> <> <> keyboardLock: MONITORLOCK; charactersAvailable: CONDITION; in, out: NAT; buffer: PACKED ARRAY NAT[0..50) OF CHAR _ ALL['\000]; ProcessKeyboard: PROC = { GoAway: ENTRY PROC[m: POINTER TO MONITORLOCK] RETURNS [BOOL] = INLINE { RETURN[state = joining]; }; AddToBuffer: ENTRY PROC[m: POINTER TO MONITORLOCK, c: CHAR] = INLINE { newin: NAT _ in + 1; IF newin = buffer.LENGTH THEN newin _ 0; IF newin ~= out THEN {buffer[in] _ c; in _ newin}; }; NotifyCharsAvailable: ENTRY PROC[m: POINTER TO MONITORLOCK] = INLINE { BROADCAST charactersAvailable; }; in _ out _ 0; Process.SetPriority[Process.priorityRealTime]; UNTIL GoAway[@terminalLock] DO charsSeen: BOOL _ FALSE; numChars: INT _ 0; Process.Pause[1]; -- let the other guys run. numChars _ IO.CharsAvail[ttyStream]; IF numChars # 0 THEN BEGIN char: CHAR _ IO.GetChar[ttyStream]; AddToBuffer[@keyboardLock, char]; NotifyCharsAvailable[@keyboardLock]; END; ENDLOOP; }; <<>> <> <> screenLock: MONITORLOCK; noTrack: CARDINAL _ 0; charPos: NAT; InitScreen: PROC [nameStripe: ROPE] = { IO.PutRope[ttyStream, nameStripe]; IO.PutChar[ttyStream, '\n]; }; DisplayChar: INTERNAL PROC [c: CHAR] = { SELECT c FROM IN [Ascii.SP..'~] => {IO.PutChar[ttyStream, c]; charPos _ charPos + 1}; Ascii.CR => {IO.PutChar[ttyStream, c]; charPos _ 0}; Ascii.BS => {IO.PutChar[ttyStream, c]; charPos _ charPos - 1; IF charPos < 1 THEN charPos _ 1}; Ascii.TAB => {IO.PutChar[ttyStream, c]; charPos _ charPos + 1; UNTIL charPos MOD 8 = 0 DO IO.PutChar[ttyStream, ' ]; charPos _ charPos + 1; ENDLOOP; RETURN}; IN [0C..Ascii.SP) => {IO.PutChar[ttyStream, c]}; ENDCASE => RETURN; }; ClearThisChar: INTERNAL PROC = { <> }; <> CreateStreams: PROC = { }; CharsAvail: SAFE PROC [self: STREAM, wait: BOOL] RETURNS [INT] = TRUSTED { CharsAvailEntry: ENTRY PROC [m: POINTER TO MONITORLOCK] RETURNS [BOOL] = INLINE {RETURN[in ~= out]}; RETURN[IF CharsAvailEntry[@keyboardLock] THEN 1 ELSE 0] }; EndOf: SAFE PROC [self: STREAM] RETURNS [BOOL] = CHECKED {RETURN[FALSE]}; GetChar: SAFE PROC [self: STREAM] RETURNS [c: CHAR _ '\000] = TRUSTED { GetEntry: ENTRY PROC [m: POINTER TO MONITORLOCK] RETURNS [BOOL] = INLINE { ENABLE UNWIND => NULL; WHILE in = out DO WAIT charactersAvailable; IF in = out THEN RETURN[FALSE]; ENDLOOP; c _ buffer[out]; IF (out _ out + 1) = buffer.LENGTH THEN out _ 0; RETURN[TRUE] }; UNTIL GetEntry[@keyboardLock] DO SIGNAL InputTimeout; ENDLOOP; }; PutChar: SAFE PROC [self: STREAM, char: CHAR] = TRUSTED { PutCharEntry: ENTRY PROC [m: POINTER TO MONITORLOCK] = INLINE { DisplayChar[char]; }; PutCharEntry[@screenLock]; }; EraseChar: SAFE PROC [self: STREAM, char: CHAR] = TRUSTED { EraseCharEntry: ENTRY PROC [m: POINTER TO MONITORLOCK] = INLINE { ClearThisChar[]; -- to get rid of possible blinker DisplayChar[Ascii.BS]; }; EraseCharEntry[@screenLock]; }; <> <<>> inStreamProcs: REF IO.StreamProcs _ NIL; outStreamProcs: REF IO.StreamProcs _ NIL; Initialize: ENTRY PROC [m: POINTER TO MONITORLOCK] = { inStreamProcs _ IO.CreateStreamProcs[ variety: $input, class: $SimpleTerminalTTY, getChar: GetChar, endOf: EndOf, charsAvail: CharsAvail ]; outStreamProcs _ IO.CreateStreamProcs[ variety: $output, class: $SimpleTerminalTTY, putChar: PutChar, eraseChar: EraseChar ]; <> <> }; Initialize[@terminalLock]; <<>> END. ChangeLog WSO, July 30, 1984: catch BasicTime.TimeNotKnown in call to BasicTime.Now.