DumbTerminalSupportImpl.mesa
Copyright Ó 1985, 1987 by Xerox Corporation. All rights reserved.
Tim Diebert: March 6, 1987 10:16:25 am PST
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: ROPENIL;
DO
end: CHAR;
errors: BOOLFALSE;
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: ROPENIL, echo: BOOLTRUE] 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 => {
text to be backed up is of the form ...<non-alpha><alpha><non-alpha>, the <alpha> and following <non-alpha> are to be removed.
alpha: BOOLFALSE;
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: BOOLFALSE;
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
left button or right = shift for TTY DLion
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 {
Must not be invoked until KeyboardFace and Process have been initialized.
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.