MockingbirdTTY.mesa
Derived from MockingbirdTTY.mesa
last edited by Forrest January 6, 1981 7:28 PM
last edited by Levin on 14-Apr-82 18:02:39
last edited by McGregor on April 22, 1982 4:23 pm
last gutted by Maxwell on May 20, 1982 10:02 am
This module also implements non-basic tty features (see end of code).
if these are not needed, String and Format may be left unbound
DIRECTORY
Ascii USING [
BS, ControlA, ControlR, ControlQ, ControlV, ControlW, ControlX, CR, DEL,
ESC, FF, SP, TAB],
BitBlt USING [AlignedBBTable, BBptr, BBTableSpace, BITBLT],
Environment USING [BitAddress],
Format USING [
Date, Decimal, LongDecimal, LongNumber, LongOctal, LongSubStringItem,
Number, Octal, SubString],
Inline USING [BITAND],
Process USING [Detach, SetPriority],
Runtime USING [GetTableBase],
SpecialSpace USING [
MakeGlobalFrameResident, --MakeGlobalFrameSwappable,--
MakeProcedureResident],
String USING [
AppendChar, AppendLongNumber, AppendNumber,
StringToLongNumber, StringToNumber, SubString],
TerminalMultiplex USING [InputController, RegisterInputController, SelectTerminal],
Time USING [Packed],
TTY USING [DateFormat, Handle, LongSubString, NumberFormat],
UserTerminal USING [
Coordinate, cursor, GetBitBltTable, keyboard, mouse, screenHeight,
screenWidth, SetMousePosition, SetState, SetBackground,
WaitForScanLine];
MockingbirdTTY: MONITOR
LOCKS m USING m: POINTER TO MONITORLOCK
IMPORTS
BitBlt, Format, Inline, Process, Runtime, SpecialSpace,
String, TerminalMultiplex, UserTerminal
EXPORTS TTY =
BEGIN OPEN Ascii, BitBlt;
screenLock: MONITORLOCK;
keyboardLock: MONITORLOCK;
shuttingDown: BOOLEANFALSE;
shutDown: CONDITION ← [timeout: 0];
startingUp: BOOLEANFALSE;
startUp: CONDITION ← [timeout: 0];
noTrack: CARDINAL ← 0;
Initialize: PROCEDURE = {
IF ~TerminalMultiplex.SelectTerminal[alternate] THEN ERROR;
TerminalMultiplex.RegisterInputController[InputController];
InputController[enable]};
InputController: TerminalMultiplex.InputController = {
SELECT action FROM
enable => {IF useCount = 0 THEN TurnOnTerminal[]; StartTerminal[]};
disable => TurnOffTerminal[];
ENDCASE};
TurnOnTerminal: PROCEDURE = {
TurnOnInternal: ENTRY PROC [m: POINTER TO MONITORLOCK] = {
IF ~font.newStyle OR font.indexed OR font.min NOT IN [0C..177C]
OR font.max+1 NOT IN [0C..177C] THEN ERROR;
WHILE shuttingDown DO WAIT shutDown ENDLOOP;
SpecialSpace.MakeProcedureResident[ProcessKeyboard];
SpecialSpace.MakeGlobalFrameResident[MockingbirdTTY];
CDTFALSE;
echo ← TRUE;
in ← out ← 0;
[] ← UserTerminal.SetState[on];
[] ← UserTerminal.SetBackground[white];
ClearScreen[]; -- to force init of bbPtr (since may have changed)
Process.Detach[FORK ProcessKeyboard]};
TurnOnInternal[@keyboardLock]};
StartTerminal: PROCEDURE = {
StartInternal: ENTRY PROC [m: POINTER TO MONITORLOCK] = {
startingUp ← TRUE; BROADCAST startUp};
StartInternal[@keyboardLock]};
TurnOffTerminal: PROCEDURE = {
TurnOffInternal: ENTRY PROC [m: POINTER TO MONITORLOCK] = {
shuttingDown ← TRUE;
WHILE shuttingDown DO WAIT shutDown ENDLOOP};
Pilot doesn't do this right: SpecialSpace.MakeGlobalFrameSwappable[MockingbirdTTY];
SpecialSpace.MakeProcedureSwappable[ProcessKeyboard];
[] ← UserTerminal.SetState[disconnected]};
TurnOffInternal[@keyboardLock]};
EnableCursorTracking: PUBLIC PROCEDURE = {
EnableInternal: ENTRY PROC [m: POINTER TO MONITORLOCK] = {
IF (noTrack ← noTrack - 1) = 0 THEN doBlink ← TRUE};
EnableInternal[@keyboardLock]};
DisableCursorTracking: PUBLIC PROCEDURE = {
DisableInternal: ENTRY PROC [m: POINTER TO MONITORLOCK] = {
IF (noTrack ← noTrack + 1) ~= 0 THEN doBlink ← FALSE};
DisableInternal[@keyboardLock]};
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FONT Definitions and variables
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
font: LONG POINTER TO MACHINE DEPENDENT RECORD [
newStyle(0:0..0): BOOLEAN,
indexed(0:1..1): BOOLEAN,
fixed(0:2..2): BOOLEAN,
kerned(0:3..3): BOOLEAN,
pad(0:4..15): [0..7777B],
min(1): CHARACTER, -- limits of chars in font
max(2): CHARACTER, -- limits of chars in font
maxwidth(3): CARDINAL,
length(4): CARDINAL,
ascent(5): CARDINAL,
descent(6): CARDINAL,
xoffset(7): CARDINAL,
raster(8): CARDINAL,
chars(9:0..63): SELECT OVERLAID * FROM
hasBoundingBox => [
boundingBox(9:0..63): RECORD [FontBBox, FontBBoy, FontBBdx, FontBBDy: INTEGER],
BBBitmap(13): ARRAY [0..0) OF WORD],
noBoundingBox => [bitmap(9): ARRAY [0..0) OF WORD],
ENDCASE] = GetFont[];
bitmap: LONG POINTER = IF font.kerned THEN @font.BBBitmap ELSE @font.bitmap;
xInSegment: LONG POINTER TO ARRAY CHARACTER [0C..0C) OF CARDINAL =
bitmap + font.raster*FontHeight[] - (font.min-0C);
height: INTEGER[0..LAST[INTEGER]] = FontHeight[];
CharWidth: PROC [char: CHARACTER] RETURNS [[0..LAST[INTEGER]]] =
INLINE BEGIN
IF char NOT IN [font.min..font.max] THEN char ← font.max+1;
RETURN[xInSegment[char+1] - xInSegment[char]]
END;
FontHeight: PROC RETURNS [[0..LAST[INTEGER]]] = INLINE {RETURN[font.ascent+font.descent]};
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Keyboard Definitions and Constants
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
downUp: TYPE = {down, up};
keycount: CARDINAL = 80; -- must be 0 mod 16
Keyarray: TYPE = MACHINE DEPENDENT RECORD [SELECT OVERLAID * FROM
b => [bits: PACKED ARRAY [0..keycount) OF downUp],
wds => [wds: ARRAY [0..keycount/16) OF WORD],
ENDCASE];
KeyItem: TYPE = RECORD [
Letter: BOOLEAN, ShiftCode: CHARACTER [0C..177C], NormalCode: CHARACTER [0C..377C]];
Keyboard Info
ctrl: CARDINAL = 52;
leftShift: CARDINAL = 57;
shiftLock: CARDINAL = 72;
rightShift: CARDINAL = 76;
spare3: CARDINAL = 77;
KeyTable: ARRAY [16..keycount) OF KeyItem = [
Index [0..15] mouse, etc
Index [16..31]
[FALSE, 45C, 65C], -- %,5
[FALSE, 44C, 64C], -- $,4
[FALSE, 176C, 66C], -- ~,6
[TRUE, 105C, 145C], -- E
[FALSE, 46C, 67C], -- &,7
[TRUE, 104C, 144C], -- D
[TRUE, 125C, 165C], -- U
[TRUE, 126C, 166C], -- V
[FALSE, 51C, 60C], -- ),0
[TRUE, 113C, 153C], -- K
[FALSE, 30C, 55C], -- `,-
[TRUE, 120C, 160C], -- P
[FALSE, 77C, 57C], -- ?,/
[FALSE, 174C, 134C], -- |,\
[FALSE, 12C, 12C], -- LF
[FALSE, 10C, 10C], -- BS
Index [32..47]
[FALSE, 43C, 63C], -- #,3
[FALSE, 100C, 62C], -- @,2
[TRUE, 127C, 167C], -- W
[TRUE, 121C, 161C], -- Q
[TRUE, 123C, 163C], -- S
[TRUE, 101C, 141C], -- A
[FALSE, 50C, 71C], -- (,9
[TRUE, 111C, 151C], -- I
[TRUE, 130C, 170C], -- X
[TRUE, 117C, 157C], -- O
[TRUE, 114C, 154C], -- L
[FALSE, 74C, 54C], -- <,,
[FALSE, 42C, 47C], -- ",'
[FALSE, 175C, 135C], --},]
[FALSE, 0C, 0C], -- SPARE2
[FALSE, 0C, 0C], -- SPARE1
Index [48..63]
[FALSE, 41C, 61C], -- !,1
[FALSE, 33C, 33C], -- ESCAPE
[FALSE, 11C, 11C], -- TAB
[TRUE, 106C, 146C], -- F
[FALSE, 0C, 0C], -- CONTROL
[TRUE, 103C, 143C], -- C
[TRUE, 112C, 152C], -- J
[TRUE, 102C, 142C], -- B
[TRUE, 132C, 172C], -- Z
[FALSE, 0C, 0C], -- SHIFT
[FALSE, 76C, 56C], -- >,.
[FALSE, 72C, 73C], -- :,;
[FALSE, 15C, 15C], -- CR
[FALSE, 136C, 137C], -- ^,←
[FALSE, 177C, 177C], -- DEL
[FALSE, 0C, 0C], -- NOT USED (FL3)
Index [64..79]
[TRUE, 122C, 162C], -- R
[TRUE, 124C, 164C], -- T
[TRUE, 107C, 147C], -- G
[TRUE, 131C, 171C], -- Y
[TRUE, 110C, 150C], -- H
[FALSE, 52C, 70C], -- *,8
[TRUE, 116C, 156C], -- N
[TRUE, 115C, 155C], -- M
[FALSE, 0C, 0C], -- LOCK
[FALSE, 40C, 40C], -- SPACE
[FALSE, 173C, 133C], -- {,[
[FALSE, 53C, 75C], -- +,=
[FALSE, 0C, 0C], -- Shift
[FALSE, 0C, 0C], -- Spare3
[FALSE, 0C, 0C], -- not user (FR4)
[FALSE, 0C, 0C]]; -- not user (FR5)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Simple TTY Procedures
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
useCount: CARDINAL ← 0;
Create: PUBLIC PROC [STRING] RETURNS [TTY.Handle] =
BEGIN
useCount ← useCount + 1;
RETURN[LOOPHOLE[100000B]]
END;
Destroy: PUBLIC PROC [TTY.Handle] =
BEGIN
useCount ← useCount - 1;
END;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Keyboard Implementation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CDT: BOOLEAN;
charactersAvailable: CONDITION;
echo: BOOLEAN;
EXTERNAL PROCEDURES
CtrlChar: PROC [c: CHARACTER] RETURNS [CHARACTER] = INLINE {RETURN[LOOPHOLE[Inline.BITAND[c, 37B]]]};
ENTRY PROCEDURES
ProcessKeyboard: PROC =
BEGIN
old, new: Keyarray;
kp: LONG POINTER TO Keyarray = LOOPHOLE[UserTerminal.keyboard];
blinkCount: CARDINAL ← 33;
GoAway: ENTRY PROC [m: POINTER TO MONITORLOCK] RETURNS [BOOLEAN] = INLINE {
IF shuttingDown
THEN {shuttingDown ← FALSE; BROADCAST shutDown; RETURN[TRUE]}
ELSE RETURN[FALSE]};
WaitStart: ENTRY PROC [m: POINTER TO MONITORLOCK] = INLINE {
WHILE ~startingUp DO WAIT startUp; ENDLOOP};
Process.SetPriority[6];
new ← kp^;
WHILE TRUE DO
Brdcst: ENTRY PROC [m: POINTER TO MONITORLOCK] =
INLINE {BROADCAST charactersAvailable};
charsSeen: BOOLEANFALSE;
IF GoAway[@keyboardLock] THEN WaitStart[@keyboardLock];
startingUp ← FALSE;
old ← new;
UserTerminal.WaitForScanLine[0];
new ← kp^;
TrackCursor[@keyboardLock];
IF (blinkCount𡤋linkCount-1) = 0 THEN {BlinkCursor[]; blinkCount ← 34};
FOR i: CARDINAL IN [1..keycount/16) DO
IF old.wds[i]#new.wds[i] THEN
FOR j: CARDINAL IN [i*16..(i+1)*16) DO
char: CHARACTER;
entry: KeyItem;
IF new.bits[j]=up OR old.bits[j]=down THEN LOOP;
IF (char ← (entry←KeyTable[j]).NormalCode)#0C THEN
BEGIN
SELECT TRUE FROM
new.bits[ctrl]=down =>
IF char=177C THEN {CDTTRUE; LOOP} ELSE char ← CtrlChar[char];
new.bits[leftShift]=down, new.bits[rightShift]=down =>
char ← entry.ShiftCode;
new.bits[shiftLock]=down AND entry.Letter =>
char ← entry.ShiftCode;
ENDCASE;
StuffBuffer[char, @keyboardLock];
charsSeen ← TRUE
END;
ENDLOOP
ENDLOOP;
IF charsSeen THEN Brdcst[@keyboardLock];
ENDLOOP
END;
SetEcho: PUBLIC PROC [h: TTY.Handle, new: BOOLEAN] RETURNS [old: BOOLEAN] =
BEGIN
SetEntry: ENTRY PROC [m: POINTER TO MONITORLOCK] = INLINE {old ← echo; echo ← new};
SetEntry[@keyboardLock]
END;
TrackCursor: ENTRY PROC [m: POINTER TO MONITORLOCK] =
INLINE BEGIN
mouse: UserTerminal.Coordinate ← UserTerminal.mouse^;
IF noTrack > 0 THEN RETURN;
mouse.x ← MIN[MAX[0, mouse.x], UserTerminal.screenWidth];
mouse.y ← MIN[MAX[0, mouse.y], UserTerminal.screenHeight];
UserTerminal.cursor^ ← mouse;
UserTerminal.SetMousePosition[mouse]
END;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Keyboard RingBuffer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
in, out: CARDINAL;
buffer: PACKED ARRAY [0..50) OF CHARACTER;
CharsAvailable: PUBLIC PROC [h: TTY.Handle] RETURNS [CARDINAL] =
BEGIN
P: ENTRY PROC [m: POINTER TO MONITORLOCK] RETURNS [CARDINAL] =
INLINE {RETURN[IF in>=out THEN in-out ELSE in+LENGTH[buffer]-out]};
RETURN[P[@keyboardLock]]
END;
GetChar: PUBLIC PROC [h: TTY.Handle] RETURNS [c: CHARACTER] =
BEGIN
P: ENTRY PROC [m: POINTER TO MONITORLOCK] =
INLINE BEGIN
WHILE in=out DO WAIT charactersAvailable ENDLOOP;
c ← buffer[out];
IF (out←out+1) = LENGTH[buffer] THEN out ← 0;
END;
P[@keyboardLock]
END;
PutBackChar: PUBLIC PROC [h: TTY.Handle, c: CHARACTER] =
BEGIN
P: ENTRY PROC [m: POINTER TO MONITORLOCK] =
INLINE BEGIN
newout: CARDINAL = IF out=0 THEN LENGTH[buffer]-1 ELSE out-1;
IF newout#in THEN {buffer[out ← newout] ← c; BROADCAST charactersAvailable};
END;
P[@keyboardLock]
END;
ResetUserAbort: PUBLIC PROC =
BEGIN
CDResetEntry: ENTRY PROC [m: POINTER TO MONITORLOCK] = INLINE {CDTFALSE};
CDResetEntry[@keyboardLock]
END;
StuffBuffer: ENTRY PROC [c: CHARACTER, m: POINTER TO MONITORLOCK] =
INLINE BEGIN
newin: CARDINAL;
IF (newin←in+1) = LENGTH[buffer] THEN newin ← 0;
IF newin#out THEN {buffer[in] ← c; in ← newin};
END;
perhaps this should be monitored, but since it is a snapshot...
UserAbort: PUBLIC PROC RETURNS [BOOLEAN] = {RETURN[CDT]};
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DISPLAY
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
BBTable: BBTableSpace;
bbPtr: BBptr = AlignedBBTable[@BBTable];
charPos, line, nCharPos, nLines: CARDINAL;
firstLine, thisLine: Environment.BitAddress;
bitsPerTextLine: CARDINAL; -- = screenWidth*font.height
doBlink: BOOLEANFALSE;
EXTERNAL DISPLAY PROCEDURES
GetBitAddress: PROC [p: LONG POINTER, o: CARDINAL] RETURNS [Environment.BitAddress] =
{RETURN[[p+o/16, 0, o MOD 16]]};
PutBlanks: PUBLIC PROC [h: TTY.Handle, n: CARDINAL] =
{THROUGH [0..n) DO PutChar[h, ' ] ENDLOOP};
ENTRY DISPLAY PROCEDURES
BlinkCursor: PUBLIC PROC =
BEGIN
BlinkCursorEntry: ENTRY PROC [m: POINTER TO MONITORLOCK] =
BEGIN
blinker: CARDINAL ← 60000B;
IF doBlink THEN
BEGIN
bbPtr.src ← [@blinker, 0, 0];
bbPtr.srcDesc ← [gray[[0, 0, 0, 0]]];
bbPtr.flags ← [gray: TRUE, dstFunc: xor];
BITBLT[bbPtr];
bbPtr.srcDesc ← [srcBpl[font.raster*16]];
bbPtr.flags ← [];
END;
END;
IF doBlink THEN BlinkCursorEntry[@screenLock];
END;
NewLine: PUBLIC PROC [TTY.Handle] RETURNS [BOOLEAN] = {RETURN[charPos=0]};
PutChar: PUBLIC PROC [h: TTY.Handle, c: CHARACTER] =
BEGIN
PutCharEntry: ENTRY PROC [m: POINTER TO MONITORLOCK] =
INLINE {doBlink ← FALSE; ClearThisChar[]; DisplayChar[c]; doBlink ← TRUE};
PutCharEntry[@screenLock];
END;
PutLongString: PUBLIC PROC [h: TTY.Handle, s: LONG STRING] =
{IF s#NIL THEN FOR i: CARDINAL IN [0..s.length) DO PutChar[h, s[i]] ENDLOOP};
PutString: PUBLIC PROC [h: TTY.Handle, s: STRING] = {PutLongString[h, s]};
INTERNAL DISPLAY PROCEDURES
Backup: INTERNAL PROC =
BEGIN
t: CARDINAL = bbPtr.dst.bit+16-font.maxwidth;
IF charPos=0 THEN RETURN;
charPos ← charPos - 1;
bbPtr.dst.word ← bbPtr.dst.word + t/16 - 1;
bbPtr.dst.bit ← t MOD 16;
END;
ClearScreen: INTERNAL PROC =
BEGIN
zero: CARDINAL ← 0;
bbPtr^ ← UserTerminal.GetBitBltTable[];
bitsPerTextLine ← bbPtr.dstBpl*height;
firstLine ← thisLine ← GetBitAddress[
bbPtr.dst.word, bbPtr.dst.bit+8+8*bbPtr.dstBpl];
charPos ← 0; line ← 1;
nCharPos ← (bbPtr.width-16)/font.maxwidth;
nLines ← (bbPtr.height-16)/height;
bbPtr.src ← [@zero, 0, 0];
bbPtr.srcDesc ← [gray[[0, 0, 0, 0]]];
bbPtr.flags ← [gray: TRUE];
BITBLT[bbPtr];
set up standard arguments for character painting
bbPtr.dst ← firstLine;
bbPtr.dstBpl set
bbPtr.src set when proc called
bbPtr.srcDesc ← [srcBpl[font.raster*16]];
bbPtr.height ← height;
bbPtr.width ← font.maxwidth;
bbPtr.flags ← [];
END;
ClearThisChar: INTERNAL PROC =
BEGIN
zero: CARDINAL ← 0;
bbPtr.src ← [@zero, 0, 0];
bbPtr.srcDesc ← [gray[[0, 0, 0, 0]]];
bbPtr.flags ← [gray: TRUE];
BITBLT[bbPtr];
bbPtr.srcDesc ← [srcBpl[font.raster*16]];
bbPtr.flags ← [];
END;
DisplayChar: INTERNAL PROC [c: CHARACTER] =
BEGIN
SELECT c FROM
IN (SP..'~] =>
BEGIN
IF c NOT IN [font.min..font.max] THEN c ← font.max+1;
bbPtr.src ← GetBitAddress[bitmap, xInSegment[c]];
BitBlt.BITBLT[bbPtr];
END;
SP => NULL;
CR => {Newline[]; RETURN};
BS => {Backup[]; ClearThisChar[]; RETURN};
TAB => {UNTIL (charPos MOD 8)=0 DO DisplayChar[SP] ENDLOOP; RETURN};
FF => {ClearScreen[]; RETURN};
IN [0C..SP) => {DisplayChar['^]; DisplayChar[c+('A-1C)]; RETURN};
ENDCASE => RETURN;
IF (charPos𡤌harPos+1)>=nCharPos THEN Newline[]
ELSE bbPtr.dst ← GetBitAddress[bbPtr.dst.word, bbPtr.dst.bit+font.maxwidth];
END;
Newline: INTERNAL PROC =
BEGIN
IF line<nLines THEN
{thisLine ← GetBitAddress[thisLine.word, thisLine.bit+bitsPerTextLine]; line ← line+1}
ELSE
BEGIN
zero: CARDINAL ← 0;
sBBTable: BBTableSpace;
sbbPtr: BBptr = AlignedBBTable[@sBBTable];
sbbPtr^ ← [
dst: firstLine, dstBpl: bbPtr.dstBpl,
src: GetBitAddress[firstLine.word, firstLine.bit+bitsPerTextLine],
srcDesc: [srcBpl[bbPtr.dstBpl]], flags: [direction: forward],
width: nCharPos*font.maxwidth, height: height*(nLines-1)];
BITBLT[sbbPtr];
sbbPtr^ ← [
dst: thisLine, src: [@zero, 0, 0],
dstBpl: bbPtr.dstBpl, srcDesc: [gray[[0, 0, 0, 0]]],
width: nCharPos*font.maxwidth, height: height,
flags: [gray: TRUE]];
BITBLT[sbbPtr];
END;
bbPtr.dst ← thisLine;
charPos ← 0;
END;
GetFont: PROC RETURNS [LONG POINTER] =
BEGIN
Gacha12Strike: ARRAY [0..1470B) OF WORD = [
-- 0-- 120000B, 0B, 176B, 10B, 1464B, 13B, 3B, 0B,
-- 10-- 61B, 0B, 0B, 0B, 10000B, 0B, 2040B, 0B,
-- 20-- 0B, 0B, 0B, 0B, 0B, 0B, 0B, 0B,
-- 30-- 0B, 0B, 0B, 0B, 0B, 0B, 0B, 0B,
-- 40-- 0B, 0B, 0B, 0B, 0B, 0B, 0B, 74B,
-- 50-- 74B, 0B, 0B, 0B, 0B, 0B, 0B, 0B,
-- 60-- 0B, 0B, 0B, 0B, 0B, 0B, 0B, 7010B,
-- 70-- 70000B, 0B, 0B, 10B, 22012B, 34144B, 14010B, 4020B,
-- 100-- 4000B, 0B, 2B, 36010B, 36074B, 6076B, 36176B, 36074B,
-- 110-- 0B, 2000B, 20074B, 14020B, 74034B, 74176B, 77034B, 41076B,
-- 120-- 17102B, 40306B, 41074B, 76074B, 76074B, 77502B, 40501B, 41101B,
-- 130-- 77040B, 20004B, 0B, 100B, 2B, 14B, 100B, 4004B,
-- 140-- 40070B, 0B, 0B, 0B, 0B, 0B, 0B, 0B,
-- 150-- 10010B, 4000B, 0B, 0B, 10B, 22012B, 52244B, 22010B,
-- 160-- 10010B, 25000B, 0B, 2B, 41030B, 41102B, 6040B, 41002B,
-- 170-- 41102B, 0B, 4000B, 10102B, 22020B, 42042B, 42100B, 40042B,
-- 200-- 41010B, 1104B, 40306B, 61102B, 41102B, 41102B, 4102B, 40511B,
-- 210-- 41101B, 1040B, 20004B, 0B, 100B, 2B, 22B, 100B,
-- 220-- 4004B, 40010B, 0B, 0B, 0B, 20B, 0B, 0B,
-- 230-- 0B, 10010B, 4000B, 0B, 0B, 10B, 22024B, 52250B,
-- 240-- 22010B, 10010B, 16010B, 0B, 4B, 41050B, 41102B, 12040B,
-- 250-- 40002B, 41102B, 0B, 10000B, 4102B, 41050B, 42102B, 41100B,
-- 260-- 40102B, 41010B, 1110B, 40252B, 61102B, 41102B, 41102B, 4102B,
-- 270-- 21111B, 22042B, 2040B, 10004B, 4000B, 100B, 2B, 20B,
-- 300-- 100B, 0B, 40010B, 0B, 0B, 0B, 20B, 0B,
-- 310-- 0B, 0B, 10010B, 4000B, 74000B, 0B, 10B, 22076B,
-- 320-- 50310B, 14010B, 20004B, 25010B, 0B, 4B, 43010B, 1002B,
-- 330-- 12174B, 76004B, 41102B, 4010B, 20000B, 2002B, 47050B, 42100B,
-- 340-- 41100B, 40100B, 41010B, 1120B, 40252B, 51102B, 41102B, 41040B,
-- 350-- 4102B, 21111B, 22042B, 4040B, 10004B, 16020B, 34134B, 36072B,
-- 360-- 36174B, 35134B, 34074B, 42010B,167134B, 36134B, 35054B, 36174B,
-- 370-- 41102B,101104B, 41174B, 10010B, 4062B, 74000B, 0B, 10B,
-- 400-- 24B, 34010B, 10000B, 20004B, 4010B, 176B, 10B, 45010B,
-- 410-- 2034B, 22102B, 41004B, 36102B, 4010B, 40176B, 1004B, 51104B,
-- 420-- 76100B, 41174B, 76100B, 77010B, 1160B, 40252B, 51102B, 41102B,
-- 430-- 76030B, 4102B, 21052B, 14024B, 4040B, 4004B, 25040B, 42142B,
-- 440-- 41106B, 41020B, 43142B, 4004B, 44010B,111142B, 41142B, 43062B,
-- 450-- 41020B, 41102B,101104B, 41004B, 10010B, 4132B, 74000B, 0B,
-- 460-- 10B, 50B, 12020B, 24400B, 20004B, 177B, 0B, 10B,
-- 470-- 51010B, 4002B, 22002B, 41010B, 41102B, 0B, 40000B, 1010B,
-- 500-- 51104B, 41100B, 41100B, 40116B, 41010B, 1110B, 40222B, 45102B,
-- 510-- 76102B, 44004B, 4102B, 12052B, 14024B, 10040B, 4004B, 4177B,
-- 520-- 2102B, 40102B, 41020B, 41102B, 4004B, 50010B,111102B, 41102B,
-- 530-- 41040B, 40020B, 41044B,111050B, 21010B, 60010B, 3114B, 74000B,
-- 540-- 35400B, 10B, 174B, 12023B, 45000B, 20004B, 10B, 0B,
-- 550-- 20B, 61010B, 10002B, 42002B, 41010B, 41076B, 0B, 20176B,
-- 560-- 2010B, 46104B, 41100B, 41100B, 40102B, 41010B, 1104B, 40222B,
-- 570-- 45102B, 40102B, 42002B, 4102B, 12052B, 22010B, 20040B, 2004B,
-- 600-- 4040B, 36102B, 40102B, 77020B, 41102B, 4004B, 70010B,111102B,
-- 610-- 41102B, 41040B, 36020B, 41044B,111020B, 22020B, 10010B, 4000B,
-- 620-- 74000B, 0B, 0B, 50B, 52025B, 42000B, 20004B, 10B,
-- 630-- 0B, 20B, 41010B, 20102B, 77102B, 41020B, 41002B, 0B,
-- 640-- 10000B, 4000B, 40376B, 41102B, 41100B, 40102B, 41010B, 41104B,
-- 650-- 40222B, 43102B, 40102B, 42102B, 4102B, 12024B, 22010B, 20040B,
-- 660-- 2004B, 4020B, 42102B, 40102B, 40020B, 41102B, 4004B, 44010B,
-- 670-- 111102B, 41102B, 41040B, 1020B, 41044B,111050B, 12040B, 10010B,
-- 700-- 4000B, 74000B, 0B, 10B, 120B, 52045B, 42000B, 10010B,
-- 710-- 10B, 14000B, 4040B, 41010B, 40102B, 2102B, 41020B, 41102B,
-- 720-- 4030B, 4000B, 10010B, 21202B, 41042B, 42100B, 40046B, 41010B,
-- 730-- 41102B, 40202B, 43102B, 40102B, 41102B, 4102B, 4024B, 41010B,
-- 740-- 40040B, 1004B, 4000B, 42142B, 41106B, 41020B, 43102B, 4004B,
-- 750-- 42010B,111102B, 41142B, 43040B, 41022B, 43030B,111104B, 14100B,
-- 760-- 10010B, 4000B, 74000B, 0B, 10B, 120B, 34046B, 35400B,
-- 770-- 10010B, 0B, 4000B, 4040B, 36076B, 77074B, 2074B, 36020B,
--1000-- 36074B, 4010B, 2000B, 20010B, 16202B, 76034B, 74176B, 40032B,
--1010-- 41076B, 36102B, 77202B, 41074B, 40074B, 41074B, 4074B, 4024B,
--1020-- 41010B, 77040B, 1004B, 0B, 35134B, 36072B, 36020B, 35102B,
--1030-- 4004B, 41010B,111102B, 36134B, 35040B, 36014B, 35030B, 66104B,
--1040-- 4176B, 10010B, 4000B, 74000B, 0B, 0B, 0B, 10000B,
--1050-- 0B, 4020B, 0B, 4000B, 0B, 0B, 0B, 0B,
--1060-- 0B, 0B, 10B, 0B, 0B, 0B, 0B, 0B,
--1070-- 0B, 0B, 0B, 0B, 0B, 20B, 0B, 0B,
--1100-- 0B, 0B, 40B, 4B, 0B, 0B, 0B, 0B,
--1110-- 1000B, 4B, 0B, 0B, 100B, 1000B, 0B, 0B,
--1120-- 0B, 4000B, 10010B, 4000B, 74000B, 0B, 0B, 0B,
--1130-- 0B, 0B, 2040B, 0B, 10000B, 0B, 0B, 0B,
--1140-- 0B, 0B, 0B, 20B, 0B, 0B, 0B, 0B,
--1150-- 0B, 0B, 0B, 0B, 0B, 0B, 16B, 0B,
--1160-- 0B, 0B, 0B, 74B, 74B, 0B, 0B, 0B,
--1170-- 0B, 41000B, 104B, 0B, 0B, 100B, 1000B, 0B,
--1200-- 0B, 0B, 50000B, 7010B, 70000B, 74000B, 377B, 0B,
--1210-- 0B, 0B, 0B, 0B, 0B, 0B, 0B, 0B,
--1220-- 0B, 0B, 0B, 0B, 0B, 0B, 0B, 0B,
--1230-- 0B, 0B, 0B, 0B, 0B, 0B, 0B, 0B,
--1240-- 0B, 0B, 0B, 0B, 0B, 0B, 0B, 0B,
--1250-- 0B, 0B, 36000B, 70B, 0B, 0B, 100B, 1000B,
--1260-- 0B, 0B, 0B, 20000B, 0B, 0B, 74000B, 0B,
--1270-- 10B, 10B, 10B, 10B, 10B, 10B, 10B, 10B,
--1300-- 10B, 10B, 10B, 10B, 10B, 10B, 10B, 10B,
--1310-- 10B, 10B, 10B, 10B, 10B, 10B, 10B, 10B,
--1320-- 20B, 20B, 20B, 20B, 20B, 20B, 20B, 20B,
--1330-- 30B, 40B, 50B, 60B, 70B, 100B, 110B, 120B,
--1340-- 130B, 140B, 150B, 160B, 170B, 200B, 210B, 220B,
--1350-- 230B, 240B, 250B, 260B, 270B, 300B, 310B, 320B,
--1360-- 330B, 340B, 350B, 360B, 370B, 400B, 410B, 420B,
--1370-- 430B, 440B, 450B, 460B, 470B, 500B, 510B, 520B,
--1400-- 530B, 540B, 550B, 560B, 570B, 600B, 610B, 620B,
--1410-- 630B, 640B, 650B, 660B, 670B, 700B, 710B, 720B,
--1420-- 730B, 740B, 750B, 760B, 770B, 1000B, 1010B, 1020B,
--1430-- 1020B, 1030B, 1040B, 1050B, 1060B, 1070B, 1100B, 1110B,
--1440-- 1120B, 1130B, 1140B, 1150B, 1160B, 1170B, 1200B, 1210B,
--1450-- 1220B, 1230B, 1240B, 1250B, 1260B, 1270B, 1300B, 1310B,
--1460-- 1320B, 1330B, 1340B, 1350B, 1360B, 1370B, 1400B, 1410B];
p: LONG POINTER TO ARRAY [0..1470B) OF WORD ← Runtime.GetTableBase[LOOPHOLE[MockingbirdTTY]];
DO
IF p[0] = Gacha12Strike[0] AND p^ = Gacha12Strike THEN RETURN[p];
p ← p+1;
ENDLOOP;
END;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
non-basic tty features
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
BackingStream: PUBLIC PROC [TTY.Handle] RETURNS [never: UNSPECIFIED] =
{ERROR};
GetDecimal: PUBLIC PROC [h: TTY.Handle] RETURNS [INTEGER] =
BEGIN
s: STRING ← [10];
[] ← GetEditedString[h, s, IsAtom, TRUE];
RETURN[String.StringToNumber[s, 10]]
END;
GetID: PUBLIC PROC [h: TTY.Handle, s: STRING] =
{[] ← GetEditedString[h, s, IsAtom, TRUE]};
GetLine: PUBLIC PROC [h: TTY.Handle, s: STRING] =
{[] ← GetEditedString[h, s, IsCR, TRUE]; PutChar[h, CR]};
GetLongDecimal: PUBLIC PROC [h: TTY.Handle] RETURNS [n: LONG INTEGER] =
BEGIN
s: STRING ← [32];
[] ← GetEditedString[h, s, IsAtom, TRUE];
RETURN[String.StringToLongNumber[s, 10]]
END;
GetLongNumber: PUBLIC PROC [
h: TTY.Handle, default: LONG UNSPECIFIED, radix: CARDINAL]
RETURNS [n: LONG UNSPECIFIED] =
BEGIN
s: STRING ← [32];
IF radix = 10 AND LOOPHOLE[default, LONG INTEGER] < 0 THEN
{s[0] ← '-; s.length ← 1; default ← -default};
String.AppendLongNumber[s, default, radix];
IF radix = 8 THEN String.AppendChar[s, 'B];
[] ← GetEditedString[h, s, IsAtom, TRUE];
RETURN[String.StringToLongNumber[s, radix]];
END;
GetLongOctal: PUBLIC PROC [h: TTY.Handle] RETURNS [n: LONG UNSPECIFIED] =
BEGIN
s: STRING ← [32];
[] ← GetEditedString[h, s, IsAtom, TRUE];
RETURN[String.StringToLongNumber[s, 8]]
END;
GetNumber: PUBLIC PROC [h: TTY.Handle, default: UNSPECIFIED, radix: CARDINAL]
RETURNS [n: UNSPECIFIED] =
BEGIN
s: STRING ← [10];
IF radix = 10 AND LOOPHOLE[default, INTEGER] < 0 THEN
{default ← -default; s[0] ← '-; s.length ← 1};
String.AppendNumber[s, default, radix];
IF radix = 8 THEN String.AppendChar[s, 'B];
[] ← GetEditedString[h, s, IsAtom, TRUE];
RETURN[String.StringToNumber[s, radix]];
END;
GetOctal: PUBLIC PROC [h: TTY.Handle] RETURNS [n: UNSPECIFIED] =
BEGIN
s: STRING ← [10];
[] ← GetEditedString[h, s, IsAtom, TRUE];
RETURN[String.StringToNumber[s, 8]]
END;
GetString: PUBLIC PROC [
h: TTY.Handle, s: STRING, t: PROC [c: CHARACTER] RETURNS [yes: BOOLEAN]] =
{PutChar[h, GetEditedString[h, s, t, TRUE]]};
LineOverflow: PUBLIC SIGNAL [s: STRING] RETURNS [ns: STRING] = CODE;
Rubout: PUBLIC SIGNAL = CODE;
GetEditedString: PUBLIC PROC [
h: TTY.Handle, s: STRING,
t: PROC [c: CHARACTER] RETURNS [yes: BOOLEAN],
newstring: BOOLEAN]
RETURNS [c: CHARACTER] =
BEGIN
c ← GetChar[h];
IF newstring THEN
IF c = ESC THEN {PutString[h, s]; c ← GetChar[h]} ELSE s.length ← 0;
UNTIL t[c] DO
SELECT c FROM
DEL => SIGNAL Rubout;
ControlA, BS => -- backspace
IF s.length > 0 THEN {IF echo THEN PutChar[h, BS]; s.length ← s.length - 1};
ControlW, ControlQ => -- backword
BEGIN
text to be backed up is of the form ...<li><v><ti>, the <v> and <ti> are to
be removed.
state: {ti, v, li} ← ti;
FOR i: CARDINAL DECREASING IN [0..s.length) DO
SELECT s[i] FROM
IN ['A..'Z], IN ['a..'z], IN ['0..'9] => IF state = ti THEN state ← v;
ENDCASE => IF state = v THEN state ← li;
IF state = li THEN GO TO Done;
IF echo THEN PutChar[h, BS];
REPEAT
Done => s.length ← i + 1;
FINISHED => s.length ← 0;
ENDLOOP;
END;
ControlX => -- back everything
BEGIN
IF echo THEN FOR i: CARDINAL IN [0..s.length) DO PutChar[h, BS] ENDLOOP;
s.length ← 0;
END;
ControlR => -- refresh-- IF echo THEN {PutChar[h, CR]; PutString[h, s]};
ControlV => -- dont parse next char
BEGIN
WHILE s.length >= s.maxlength DO s ← SIGNAL LineOverflow[s] ENDLOOP;
s[s.length] ← c ← GetChar[h];
s.length ← s.length + 1;
IF echo THEN PutChar[h, c]
END;
ENDCASE =>
BEGIN
WHILE s.length >= s.maxlength DO s ← SIGNAL LineOverflow[s] ENDLOOP;
s[s.length] ← c;
s.length ← s.length + 1;
IF echo THEN PutChar[h, c];
END;
c ← GetChar[h];
ENDLOOP;
END;
IsAtom: PROC [c: CHARACTER] RETURNS [BOOLEAN] = {RETURN[c = SP OR c = CR]};
IsCR: PROC [c: CHARACTER] RETURNS [BOOLEAN] = {RETURN[c = CR]};
extended output procedures
OutString: PROC [s: STRING] = {PutLongString[LOOPHOLE[0], s]};
PutDate: PUBLIC PROC [h: TTY.Handle, gmt: Time.Packed, format: TTY.DateFormat] =
{Format.Date[gmt, format, OutString]};
PutDecimal: PUBLIC PROC [h: TTY.Handle, n: INTEGER] = {Format.Decimal[n, OutString]};
PutLongDecimal: PUBLIC PROC [h: TTY.Handle, n: LONG INTEGER] =
{Format.LongDecimal[n, OutString]};
PutLongNumber: PUBLIC PROC [h: TTY.Handle, n: LONG UNSPECIFIED, format: TTY.NumberFormat] =
{Format.LongNumber[n, format, OutString]};
PutLongOctal: PUBLIC PROC [h: TTY.Handle, n: LONG UNSPECIFIED] =
{Format.LongOctal[n, OutString]};
PutNumber: PUBLIC PROC [h: TTY.Handle, n: UNSPECIFIED, format: TTY.NumberFormat] =
{Format.Number[n, format, OutString]};
PutOctal: PUBLIC PROC [h: TTY.Handle, n: UNSPECIFIED] = {Format.Octal[n, OutString]};
PutLongSubString: PUBLIC PROC [h: TTY.Handle, ss: TTY.LongSubString] =
{Format.LongSubStringItem[ss, OutString]};
PutSubString: PUBLIC PROC [h: TTY.Handle, ss: String.SubString] =
{Format.SubString[ss, OutString]};
Initialize[];
END.