-- 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: BOOLEAN ← FALSE; shutDown: CONDITION ← [timeout: 0]; startingUp: BOOLEAN ← FALSE; 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]; CDT ← FALSE; 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: BOOLEAN ← FALSE; IF GoAway[@keyboardLock] THEN WaitStart[@keyboardLock]; startingUp ← FALSE; old ← new; UserTerminal.WaitForScanLine[0]; new ← kp↑; TrackCursor[@keyboardLock]; IF (blinkCount←blinkCount-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 {CDT ← TRUE; 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 {CDT ← FALSE}; 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: BOOLEAN ← FALSE; -- 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←charPos+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.