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; 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. :SimpleTerminalTTYImpl.mesa Copyright c 1984, 1985 by Xerox Corporation. All rights reserved. Derived from SimpleTTY.mesa last edited by Forrest January 6, 1981 7:28 PM Levin on January 17, 1984 11:13:07 am PST McGregor on April 22, 1982 4:23 pm Birrell, July 7, 1983 3:20 pm MBrown, September 17, 1983 8:18 pm Willie-Sue, June 11, 1985 1:17:50 pm PDT Russ Atkinson (RRA) February 20, 1985 3:38:56 pm PST Doug Wyatt, April 12, 1985 5:38:43 pm PST Tim Diebert: September 11, 1986 5:04:39 pm PDT Terminal USING [Virtual], Constraints to satisfy externally: A statevector is needed at priority 6 for the keyboard watching process, at least until facilities exist to let it allocate one itself. If keyboard watcher is to avoid faults, its code and global frame should be pinned. Global variables protected by "terminalLock" terminal: Terminal.Virtual _ NIL; originalTerminal: Terminal.Virtual; Exported to SimpleTerminal originalTerminal _ Terminal.Current[]; Shutdown was deferred and is still pending. We simply cancel it. [] _ terminal.Select[]; Keyboard Implementation Global variables protected by "keyboardLock" Display Implementation Global variables protected by "screenLock" IO.PutChar[ttyStream, Ascii.BS] IO Streams implementation Initialization terminal _ Terminal.Current[]; terminal.RegisterNotifier[DoShutDown]; Κ ͺ˜codešœ™Kšœ Οmœ7™BKšœL™LKšœ)™)Kšœ"™"Kšœ™Kšœ"™"K™(J™4K™)K™.—K˜šΟk ˜ Kš œžœžœžœžœžœ˜Kšœ žœžœ˜(KšžœžœWžœ˜zKšœžœK˜XKšœžœžœ˜Kšœžœ˜Kšœžœ˜,Kšœ žœ ™Kšœžœ ˜—K˜Kš Πblœž œžœžœžœž ˜FKšžœ žœž˜2Kšžœ˜Kšœž˜˜Kšžœžœžœ˜Kšžœžœž œ˜—K˜šœ"™"Kšœ‡™‡K™S—K˜Kšœžœ-˜8K˜Kšœ,™,K˜Kšœž œ˜K˜Kšœ˜Kšœ ž œ˜&K˜Kšœžœ™!Kšœ žœ˜K˜Kšœ#™#K˜Kšœžœžœ˜"K˜Kšœžœ˜K˜K™Kšœ™K˜šΟnœžœžœžœžœžœžœ žœžœ˜Wš   œžœžœžœžœž œ˜4KšžœžœΟc œ˜-K˜šž˜šžœž˜šœ˜Kšžœžœžœ˜Kšœ&™&Kšœ˜Kšž˜K˜—šœ˜KšœA™AK˜ Kšž˜Kšœ˜—Kšœžœ˜ Kšžœ˜—Kšžœ ˜Kšžœ˜—Kšœ™Kšœžœ˜Kšžœžœž œ ˜0Kšžœ ˜Kšœ˜—š  œžœžœžœžœž œ‘ œ˜EKšœ ˜ Kšž œ ˜Kšœ˜—šžœžœ˜%šžœžœž˜šœ žœ˜-Kšžœ#˜%Kšžœ#˜%Kšžœ#˜%Kšžœ8˜:K˜——Kš žœ žœžœžœ žœ'˜\K˜Kšœžœ˜)Kšœ žœ6žœ˜HKšœ žœ7žœ˜JKšœ˜K˜—Kšžœ˜Kšœ˜—K˜Kšœ žœžœžœ˜K˜š  œžœžœžœžœ˜%š   œžœžœžœžœž œ˜4Kšžœ žœ‘ œ˜)šž˜šžœž˜Kšœžœžœ˜Kšœžœ˜ Kšžœžœ ˜—Kšžœ˜—šžœ)žœžœ˜=Kšœ˜Kšž œ ˜Kšœ˜—K˜—Kšœ!˜!Kšœ˜—K˜Kšœžœž œžœ˜(K˜š  œžœžœžœžœ˜Dš œžœžœžœžœž œžœ˜GKšžœ žœ-˜>Kšžœ1˜5Kšœ˜—K˜$K˜—K˜š  œžœžœžœžœ˜4K˜—Kš  œžœžœžœžœ˜5K™Kšœ™K˜Kšœ,™,K˜Kšœž œ˜K˜Kšœž œ˜K˜Kšœ žœ˜ Kš œžœžœžœžœžœžœ˜5K˜š œžœ˜š œžœžœžœžœž œžœžœžœ˜GKšžœ˜Kšœ˜—š  œžœžœžœžœž œžœžœ˜FKšœžœ˜Kšžœžœžœ ˜(Kšžœžœ˜2Kšœ˜—š œžœžœžœžœž œžœ˜FKšž œ˜Kšœ˜—K˜ K˜.šžœž˜Kšœ žœžœ˜Kšœ žœ˜Kšœ‘˜,Kšœ žœ˜$šžœžœž˜Kšœžœžœ˜#Kšœ!˜!Kšœ$˜$Kšžœ˜—Kšžœ˜—Kšœ˜K˜—K™K™K˜šœ*™*K˜Kšœ ž œ˜K˜Kšœ žœ˜Kšœ žœ˜ K˜—š  œžœžœ˜'Jšžœ!žœ˜>J˜J˜—š  œžœžœžœ˜(šžœž˜ Kšžœžœ žœ/˜GKšœžœžœ%˜4šœžœžœ.˜=Kšžœ žœ˜!—šœžœžœ-ž˜>Kš žœ žœžœžœ0žœ˜UKšžœ˜—Kšžœ žœžœ˜0Kšžœžœ˜—Kšœ˜—K˜š  œžœžœ˜ Kšžœžœ™Kšœ˜—K˜K˜K™K˜š  œžœ˜K˜—K˜š  œžœžœžœžœžœžœžœ˜Jš œžœžœžœžœž œžœžœ˜HKšžœžœ ˜—Kšžœžœ žœžœ˜7Kšœ˜K˜—š œžœžœžœžœžœžœžœžœ˜IK˜—š œžœžœžœžœžœ žœ˜Gš œžœžœžœžœž œžœžœžœ˜JKšžœžœžœ˜šžœ ž˜Kšžœ˜Kšžœ žœžœžœ˜Kšžœ˜—K˜Kšžœžœžœ ˜0Kšžœžœ˜ K˜—Kšžœžœžœžœ˜>Kšœ˜K˜—š  œžœžœžœžœžœ˜9š  œžœžœžœžœž œžœ˜?Kšœ˜Kšœ˜—K˜Kšœ˜K˜—š   œžœžœžœžœžœ˜;š œžœžœžœžœž œžœ˜AKšœ‘!˜3Kšœžœ˜Kšœ˜—K˜Kšœ˜K˜—K˜™K™Kšœžœžœžœ˜(Kšœžœžœžœ˜)K˜š   œžœžœžœžœž œ˜6šœžœ˜%Kšœ+˜+Kšœ˜K˜ K˜K˜—šœžœ˜&Kšœ,˜,K˜K˜K˜—Kšœ™K™&Kšœ˜K˜—K˜K™—Kšžœ˜K˜K˜ K˜K˜KK˜K˜—…—Š)n