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: 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 => {
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: 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
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.