<> <> <> <<>> DIRECTORY Ascii, Booting USING [SwitchDocumentation, Switches, switches], BootSwitches USING [Switch], DebuggerSwap USING [CallDebugger, WorryCallDebugger, teledebug], IO, PrincOps USING [Priority], Process USING [Detach, DisableTimeout, GetPriority, InitializeCondition, Priority, priorityClient3, prioritySwatWatcher, SetPriority], Rope, SimpleTerminal USING [TurnOn, TurnOff], TerminalDefs USING [DownUp, KeyBits], TerminalFace USING [keyboard]; DumbTerminalSupportImpl: CEDAR MONITOR IMPORTS Ascii, Booting, DebuggerSwap, IO, Process, Rope, SimpleTerminal, TerminalFace EXPORTS ~ BEGIN STREAM: TYPE ~ IO.STREAM; ROPE: TYPE ~ Rope.ROPE; GetSwitches: PUBLIC PROC [in, out: STREAM] RETURNS [switches: Booting.Switches] = { Switch: TYPE ~ BootSwitches.Switch; value: ROPE _ NIL; DO end: CHAR; errors: BOOL _ FALSE; FromChar: PROC[c: CHAR] = { SELECT TRUE FROM Ascii.Letter[c] => switches[VAL[Switch.a.ORD+(Ascii.Lower[c]-'a)]] _ TRUE; Ascii.Digit[c] => switches[VAL[Switch.zero.ORD+(c-'0)]] _ TRUE; ENDCASE => { IO.PutRope[out, IF errors THEN ", " ELSE "\nUnrecognized switches: "]; IO.PutChar[out, c]; errors _ TRUE; }; }; ToChar: PROC [sw: Switch] RETURNS [CHAR] = { IF sw IN [zero..nine] THEN RETURN ['0+sw.ORD] ELSE RETURN ['A + (sw.ORD - Switch.a.ORD)] }; IO.PutRope[out, "\nSwitches: "]; IO.PutRope[out, value]; [id: value, c: end] _ GetID[in: in, out: out, default: NIL, init: value]; IF end = '? THEN IO.PutChar[out, end]; switches _ ALL[FALSE]; FOR i: INT IN [0..value.Length[]) DO FromChar[value.Fetch[i]] ENDLOOP; IF end = '? THEN { all: BOOL = value.Length[] = 0; IF all THEN IO.PutRope[out, " Type one or more boot switches."]; IO.PutRope[out, "\nThe boot switches have the following meanings:"]; FOR sw: Switch IN Switch DO doc: ROPE _ Booting.SwitchDocumentation[sw]; IF (all AND doc # NIL) OR switches[sw] THEN { IO.PutRope[out, "\n "]; IO.PutChar[out, ToChar[sw]]; IO.PutRope[out, ": "]; IF doc=NIL THEN doc _ "I don't know any meaning for this switch"; IO.PutRope[out, doc]; }; ENDLOOP; } ELSE { IF NOT errors THEN EXIT }; ENDLOOP; }; Rubout: PUBLIC ERROR = CODE; GetID: PUBLIC PROC [in, out: STREAM, default: ROPE, init: ROPE _ NIL, echo: BOOL _ TRUE] RETURNS [id: ROPE, c: CHAR] = { OPEN Ascii; firstTime: BOOL _ init = NIL; EraseAll: PROC = { IF echo THEN FOR i: INT DECREASING IN [0..id.Length[]) DO out.EraseChar[id.Fetch[i]]; ENDLOOP; id _ NIL; }; Done: PROC [c: CHAR] RETURNS [BOOL] = INLINE { IF firstTime THEN { SELECT c FROM ControlA, BS, ControlQ, ControlW, ControlX, CR, SP, DEL => NULL; ENDCASE => EraseAll[]; firstTime _ FALSE; }; RETURN [c = SP OR c = CR OR c = '?] }; id _ Rope.Concat[init, default]; IF echo THEN IO.PutRope[out, default]; c _ IO.GetChar[in]; UNTIL Done[c] DO SELECT c FROM DEL => ERROR Rubout; ControlA, BS => { len: INT _ id.Length[]; IF len > 0 THEN { len _ len - 1; IF echo THEN out.EraseChar[id.Fetch[len]]; id _ id.Substr[len: len]; }; }; ControlW, ControlQ => { <, the and following are to be removed.>> alpha: BOOL _ FALSE; FOR i: INT DECREASING IN [0..id.Length[]) DO ch: CHAR = id.Fetch[i]; IF Ascii.Letter[ch] OR Ascii.Digit[ch] THEN alpha _ TRUE ELSE IF alpha THEN {id _ id.Substr[len: i + 1]; EXIT}; IF echo THEN out.EraseChar[ch]; REPEAT FINISHED => id _ NIL; ENDLOOP; }; ControlX => EraseAll[]; ENDCASE => { id _ Rope.Concat[id, Rope.FromChar[c]]; IF echo THEN IO.PutChar[out, c]; }; c _ IO.GetChar[in]; ENDLOOP; }; SetBootSwitches: PROC [] = BEGIN in, out: IO.STREAM; [in: in, out: out] _ SimpleTerminal.TurnOn[]; Booting.switches _ GetSwitches[in: in, out: out]; SimpleTerminal.TurnOff[]; END; swatWatcherEnabled: BOOL _ FALSE; interruptWanted: BOOL; interrupter: CONDITION; CheckInterrupt: ENTRY PROC = TRUSTED { interruptState: TerminalDefs.DownUp _ up; keyboard: LONG POINTER TO READONLY TerminalDefs.KeyBits ~ TerminalFace.keyboard; wakeup: CONDITION; Process.InitializeCondition[@wakeup, 1]; DO --FOREVER-- ENABLE ABORTED => CONTINUE; WAIT wakeup; IF keyboard[Menu]=down -- middle button = swat for TTY DLion -- THEN { IF interruptState=up THEN { interruptState _ down; DebuggerSwap.teledebug _ TRUE; IF keyboard[Point] = down OR keyboard[Adjust] = down THEN <> DebuggerSwap.WorryCallDebugger["Keyboard interrupt (worry mode)"L] ELSE { interruptWanted _ TRUE; NOTIFY interrupter }; }; } ELSE interruptState _ up; ENDLOOP; }; InterruptSpawner: PROC = TRUSTED { WaitUntilWanted: ENTRY PROC = TRUSTED { ENABLE UNWIND => NULL; interruptWanted _ FALSE; UNTIL interruptWanted DO WAIT interrupter ENDLOOP; }; DO ENABLE ABORTED => CONTINUE; WaitUntilWanted[]; Process.Detach[FORK Interrupt[]]; ENDLOOP; }; Interrupt: PROC = { DebuggerSwap.CallDebugger["Keyboard interrupt"L]; }; swatWatcherStarted: BOOL _ FALSE; StartSwatWatcher: PUBLIC ENTRY SAFE PROC[enabled: BOOL] = TRUSTED { <> IF NOT swatWatcherStarted THEN { priorityPrev: PrincOps.Priority = Process.GetPriority[]; Process.InitializeCondition[@interrupter, 0]; Process.DisableTimeout[@interrupter]; Process.SetPriority[Process.priorityClient3]; Process.Detach[FORK InterruptSpawner[]]; Process.SetPriority[Process.prioritySwatWatcher]; Process.Detach[FORK CheckInterrupt[]]; Process.SetPriority[priorityPrev]; swatWatcherStarted _ TRUE; }; swatWatcherEnabled _ enabled; }; EnableSwatWatcher: PUBLIC ENTRY SAFE PROCEDURE[enabled: BOOL] = CHECKED{ swatWatcherEnabled _ enabled }; Initialize: PUBLIC PROC = BEGIN swatWatcherStarted _ FALSE; swatWatcherEnabled _ FALSE; StartSwatWatcher[TRUE]; END; Initialize[]; SetBootSwitches[]; END.