DIRECTORY Atom, Basics, BasicTime, Convert, IO, KeySymsKB, KeyTypes, PFS, PFSNames, ProcessProps, RefText, Rope, SimpleFeedback, StandardStreams, SystemNames, TIPLinking, TIPPrivate, TIPPrivateTypes, TIPFastTables, TIPTables, TIPTypes, TIPUser; TIPTableReaderWriterImpl: CEDAR PROGRAM IMPORTS Atom, Basics, Convert, IO, PFS, PFSNames, ProcessProps, RefText, Rope, SimpleFeedback, StandardStreams, SystemNames, TIPPrivate, TIPFastTables EXPORTS TIPLinking, TIPPrivate, TIPPrivateTypes, TIPTypes, TIPUser = BEGIN TIPTableRep: PUBLIC <> TYPE ~ TIPPrivateTypes.TIPTableRep; TIPTableImplRep: PUBLIC <> TYPE ~ TIPTables.TIPTableImplRep; KeyOption: TYPE = TIPPrivate.KeyOption; KeySym: TYPE = KeyTypes.KeySym; ROPE: TYPE = Rope.ROPE; PATH: TYPE = PFSNames.PATH; STREAM: TYPE = IO.STREAM; TIPTableImpl: TYPE ~ REF TIPTableImplRep; TIPChoice: PUBLIC TYPE ~ TIPTables.TIPChoice; TIPChoiceSeries: PUBLIC TYPE ~ TIPTables.TIPChoiceSeries; TIPKeyState: PUBLIC TYPE ~ TIPTables.TIPKeyState; TIPResults: PUBLIC TYPE ~ TIPTables.TIPResults; TIPTable: PUBLIC TYPE ~ TIPTypes.TIPTable; TIPTerm: PUBLIC TYPE ~ TIPTables.TIPTerm; BadTable: ERROR = CODE; debugTipErrors: BOOL ¬ TRUE; FindErrorStream: PROC RETURNS [STREAM] = { WITH ProcessProps.GetProp[$ErrOut] SELECT FROM stream: STREAM => RETURN [stream]; ENDCASE => NULL; WITH ProcessProps.GetProp[$StdOut] SELECT FROM stream: STREAM => RETURN [stream]; ENDCASE => NULL; RETURN [StandardStreams.CreateStandardOutputStream[]]; }; WriteGMT: PROC [f: STREAM, gmt: BasicTime.GMT] = { f.PutFWord[Basics.FFromCard32[LOOPHOLE[gmt]]]; }; ReadGMT: PROC [f: STREAM] RETURNS [gmt: BasicTime.GMT] = { gmt ¬ LOOPHOLE[Basics.Card32FromF[IO.GetFWord[f]]]; }; GetTIPFilePrefix: PUBLIC PROC[hadError: BOOL] RETURNS [ROPE] ~ { IF hadError THEN SetTIPFilePrefix[hadError]; RETURN[tipFilePrefix]; }; InstantiateNewTIPTable: PUBLIC PROC [file: ROPE] RETURNS [table: TIPTable ¬ NIL] = { ENABLE PFS.Error => IF debugTipErrors THEN { reason: ROPE ¬ error.explanation; out: STREAM = FindErrorStream[]; IO.PutF1[out, "PFS.Error (file %g) in TIPTableReaderWriterImpl.InstantiateNewTIPTable: ", [rope[file]] ]; IO.PutRope[out, reason]; IO.PutRope[out, "\n"]; REJECT; }; short: ROPE = ShortName[file]; tipCName: ROPE ¬ Rope.Flatten[Rope.Cat[tipFilePrefix, short, "B"]]; option: KeyOption ¬ none; uniqueID: PFS.UniqueID ¬ PFS.nullUniqueID; tipCreated: BasicTime.GMT ¬ BasicTime.nullGMT; name: ROPE ¬ file; fullName: PATH ¬ NIL; [fullFName: fullName, uniqueID: uniqueID] ¬ PFS.FileInfo[name: PFS.PathFromRope[name]]; tipCreated ¬ uniqueID.egmt.gmt; { { tipCreatedCardRope: Rope.ROPE ¬ NIL; st: STREAM ¬ NIL; tipCreatedCardRope ¬ Convert.RopeFromCard[ from: LOOPHOLE[tipCreated, CARD], base: 10, showRadix: FALSE]; tipCName ¬ Rope.Flatten[Rope.Cat[tipCName, "-", tipCreatedCardRope]]; st ¬ PFS.StreamOpen[PFS.PathFromRope[tipCName], read ! PFS.Error => GO TO noTIPC ]; [table, option] ¬ ReadTIPCFile[st ! BadTable => CONTINUE]; IO.Close[st]; }; IF table # NIL THEN { IF option # none THEN { table.link ¬ TIPPrivate.DefaultTable[option = printKeys]; table.opaque ¬ FALSE; }; RETURN [table]; }; EXITS noTIPC => {}; }; [table, option] ¬ TIPPrivate.BuildNewTIPTable[PFS.RopeFromPath[fullName]]; IF table = NIL THEN RETURN; { first: BOOL ¬ TRUE; st: STREAM; DO st ¬ PFS.StreamOpen[PFS.PathFromRope[tipCName], $create ! PFS.Error => IF first THEN CONTINUE ELSE REJECT]; IF st # NIL THEN EXIT; SetTIPFilePrefix[TRUE]; tipCName ¬ Rope.Flatten[Rope.Cat[tipFilePrefix, short, "B"]]; first ¬ FALSE; ENDLOOP; WriteTIPCFile[table, option, st]; IO.Close[st]; }; { newTable: TIPTable; newKeyOption: KeyOption ¬ none; st: STREAM = PFS.StreamOpen[PFS.PathFromRope[tipCName], $read]; [newTable, newKeyOption] ¬ ReadTIPCFile[st]; IO.Close[st]; IF newKeyOption # option THEN ERROR; EnsureEqualTables[table, newTable]; -- raise an ERROR if tables not equal. }; RETURN [table]; }; Append: PUBLIC PROC [early, late: TIPTable] RETURNS [err: TIPTable] ~ { FOR x: TIPTable ¬ early, x.link UNTIL x=NIL DO FOR y: TIPTable ¬ late, y.link UNTIL y=NIL DO IF x = y THEN RETURN [x]; ENDLOOP; ENDLOOP; FOR x: TIPTable ¬ early, x.link UNTIL x.link=NIL DO REPEAT FINISHED => { early.mouseTicks ¬ MIN[late.mouseTicks, early.mouseTicks]; x.opaque ¬ FALSE; x.link ¬ late; }; ENDLOOP; RETURN[NIL]}; ShortName: PROC [name: ROPE] RETURNS [ROPE] = { RETURN [PFSNames.ComponentRope[PFSNames.ShortName[PFS.PathFromRope[name]]]]; }; ReadTIPCFile: PROC [s: STREAM] RETURNS [table: TIPTable, keyOption: KeyOption ¬ none] = { text: REF TEXT ¬ NEW[TEXT[32]]; -- scratch text for atoms and such opaque, up, down, move: BOOL; where: INT ¬ 0; -- for debugging Text: PROC [len: CARDINAL] = TRUSTED { IF len > 255 THEN ERROR BadTable; IF len > text.maxLength THEN text ¬ NEW[TEXT[len]]; IF (text.length ¬ IO.GetBlock[s,text,0,len]) # len THEN ERROR BadTable; where ¬ where+len; }; Char: PROC RETURNS [CHAR] = INLINE { where ¬ where+1; RETURN [IO.GetChar[s]]; }; Key: PROC RETURNS [k: KeySym] = TRUSTED { k ¬ [Basics.Card32FromF[IO.GetFWord[s]]]; }; GetAtom: PROC RETURNS [ATOM] = { Text[LOOPHOLE[Char[],CARDINAL]]; RETURN [Atom.MakeAtom[Rope.FromRefText[text]]]; }; Bool: PROC RETURNS [BOOL] = { RETURN [SELECT Char[] FROM 'F => FALSE, 'T => TRUE, ENDCASE => ERROR BadTable]; }; StoreFlags: PROC = { impl: TIPTableImpl ~ table.impl; table.opaque ¬ opaque; impl.ignore.up ¬ up; impl.ignore.down ¬ down; impl.ignore.move ¬ move; }; ChoiceItem: PROC RETURNS [key: KeySym, choice: TIPChoice] = { SELECT Char[] FROM ') => RETURN [KeySymsKB.BS, NIL]; '( => NULL; ENDCASE => ERROR BadTable; key ¬ Key[]; choice ¬ Choice[]; IF Char[] # ') THEN ERROR BadTable; }; Choice: PROC [skipPar: BOOL ¬ FALSE] RETURNS [choice: TIPChoice] = { last: TIPChoice; char: CHAR; IF ~skipPar AND Char[] # '( THEN ERROR BadTable; WHILE (char ¬ Char[]) # ') DO term: TIPChoice ¬ Term[char]; IF last=NIL THEN choice ¬ last ¬ term ELSE last ¬ last.rest ¬ term; ENDLOOP; }; ChoiceSeries: PROC RETURNS [series: TIPChoiceSeries] = { last: TIPChoiceSeries; IF Char[] # '( THEN ERROR BadTable; WHILE Char[] # ') DO choices: TIPChoiceSeries ¬ LIST[Choice[TRUE]]; IF last=NIL THEN series ¬ last ¬ choices ELSE last ¬ last.rest ¬ choices; ENDLOOP; }; Term: PROC [char: CHAR] RETURNS [term: TIPChoice] = { SELECT char FROM '1 => { keyTerm: keyTrigger TIPTerm; keyTerm.keyState.keySym ¬ Key[]; keyTerm.keyState.state ¬ SELECT Char[] FROM 'U => up, 'D => down, ENDCASE => ERROR BadTable; RETURN [LIST[keyTerm]] }; '2 => { mouseTerm: mouseTrigger TIPTerm; RETURN [LIST[mouseTerm]] }; 'T => { term: trackballTrigger TIPTerm; RETURN [LIST[term]]; }; 'W => { term: thumbwheelTrigger TIPTerm; RETURN [LIST[term]]; }; '3 => { timeTerm: timeTrigger TIPTerm; msecs: CARDINAL; timeTerm.flavor ¬ SELECT Char[] FROM 'G => gt, 'L => lt, ENDCASE => ERROR BadTable; msecs ¬ LOOPHOLE[Char[],CARDINAL]*256; msecs ¬ msecs + LOOPHOLE[Char[],CARDINAL]; timeTerm.mSecs ¬ msecs; RETURN [LIST[timeTerm]] }; '4 => { keyTerm: keyEnable TIPTerm; keyTerm.keyState ¬ KeyState[]; RETURN [LIST[keyTerm]] }; '5 => { predTerm: predEnable TIPTerm; predTerm.predicate ¬ GetAtom[]; RETURN [LIST[predTerm]] }; '6 => { charTerm: char TIPTerm; charTerm.ch ¬ TIPPrivate.stdChar; RETURN [LIST[charTerm]] }; '7 => { coordsTerm: coords TIPTerm; coordsTerm.xy ¬ TIPPrivate.stdCoords; RETURN [LIST[coordsTerm]] }; 't => { term: trackballChange TIPTerm; term.vec ¬ TIPPrivate.stdTrackballChange; RETURN [LIST[term]]; }; 'w => { term: thumbwheelChange TIPTerm; term.v _ TIPPrivate.stdThumbwheelChange; RETURN [LIST[term]]; }; '8 => { term: nested TIPTerm; term.statement ¬ ChoiceSeries[]; RETURN [LIST[term]] }; '9 => { resultTerm: result TIPTerm; resultTerm.list ¬ Results[]; RETURN [LIST[resultTerm]] }; 'A => { term: key2Enable TIPTerm; term.keyState1 ¬ KeyState[]; term.keyState2 ¬ KeyState[]; RETURN [LIST[term]] }; 'B => { term: keyEnableList TIPTerm; last: LIST OF TIPKeyState; IF Char[] # '( THEN ERROR BadTable; WHILE IO.PeekChar[s] # ') DO keyState: LIST OF TIPKeyState ¬ LIST[KeyState[]]; IF last=NIL THEN term.lst ¬ last ¬ keyState ELSE last ¬ last.rest ¬ keyState; ENDLOOP; IF Char[] # ') THEN ERROR; RETURN [LIST[term]] }; 'C => { timeTerm: time TIPTerm; timeTerm.time ¬ TIPPrivate.stdTime; RETURN [LIST[timeTerm]]; }; ENDCASE => ERROR BadTable; }; KeyState: PROC RETURNS [keyState: TIPKeyState] = { keyState.keySym ¬ Key[]; keyState.state ¬ SELECT Char[] FROM 'U => up, 'D => down, ENDCASE => ERROR BadTable; }; Results: PROC RETURNS [results: TIPResults] = { last: TIPResults ¬ NIL; char: CHAR; IF Char[] # '( THEN ERROR BadTable; WHILE (char ¬ Char[]) # ') DO result: LIST OF REF ANY ¬ LIST[Result[char]]; IF last=NIL THEN results ¬ last ¬ result ELSE last ¬ last.rest ¬ result; ENDLOOP; }; Result: PROC [char: CHAR] RETURNS [REF ANY] = { -- used to parse results clauses SELECT char FROM '1 => RETURN [GetAtom[]]; -- an atom '2 => RETURN [TIPPrivate.stdChar]; -- put a ref to stdChar in the table '3 => { -- put an INT in the table b: bytes Basics.LongNumber; b.hh ¬ LOOPHOLE[Char[]]; b.hl ¬ LOOPHOLE[Char[]]; b.lh ¬ LOOPHOLE[Char[]]; b.ll ¬ LOOPHOLE[Char[]]; RETURN [NEW[INT ¬ LOOPHOLE[b]]]; }; '4 => { -- allocate a new text and put it in the table len: NAT ¬ Char[]-0C; txt: REF TEXT ¬ RefText.New[len]; Text[len]; txt ¬ RefText.Append[to: txt, from: text]; RETURN [txt]; }; '5 => RETURN [TIPPrivate.stdCoords]; '6 => RETURN [TIPPrivate.stdTime]; '7 => RETURN [TIPPrivate.stdTrackballChange]; '8 => RETURN [TIPPrivate.stdThumbwheelChange]; ENDCASE => ERROR BadTable; }; Text[8]; IF ~Rope.Equal["TIPTABLE", RefText.TrustTextAsRope[text]] THEN ERROR BadTable; IF Char[] # TIPPrivate.version THEN ERROR BadTable; opaque ¬ Bool[]; keyOption ¬ SELECT Char[] FROM 'N => none, 'P => printKeys, 'D => defaultKeys, ENDCASE => ERROR BadTable; up ¬ Bool[]; down ¬ Bool[]; move ¬ Bool[]; SELECT Char[] FROM 'S => { small: REF small TIPTableImplRep ¬ NEW[small TIPTableImplRep]; table ¬ NEW[TIPTableRep ¬ [impl: small]]; StoreFlags[]; small.all ¬ ChoiceSeries[]; }; 'F => { fast: REF fast TIPTableImplRep ¬ NEW[fast TIPTableImplRep]; key: KeySym; choice: TIPChoice; fast.keyUp ¬ TIPFastTables.CreateFastTable[]; fast.keyDown ¬ TIPFastTables.CreateFastTable[]; table ¬ NEW[TIPTableRep ¬ [impl: fast]]; StoreFlags[]; fast.mouse ¬ Choice[]; IF Char[] # 'U THEN ERROR BadTable; IF Char[] # '( THEN ERROR BadTable; DO [key, choice] ¬ ChoiceItem[]; IF choice=NIL THEN EXIT; TIPFastTables.StoreInFastTable[fast.keyUp, key, choice]; ENDLOOP; IF Char[] # 'D THEN ERROR BadTable; IF Char[] # '( THEN ERROR BadTable; DO [key,choice] ¬ ChoiceItem[]; IF choice=NIL THEN EXIT; TIPFastTables.StoreInFastTable[fast.keyDown, key, choice]; ENDLOOP; fast.time ¬ Choice[]; }; ENDCASE => ERROR BadTable; }; EnsureEqualTables: PUBLIC PROC [t1, t2: TIPTable] = TRUSTED { impl1: TIPTableImpl ~ t1.impl; impl2: TIPTableImpl ~ t2.impl; IF t1.opaque # t2.opaque THEN ERROR; IF impl1.ignore # impl1.ignore THEN ERROR; WITH x: impl1 SELECT FROM small => WITH y: impl2 SELECT FROM small => EqualChoiceSeries[x.all,y.all]; fast => ERROR; ENDCASE => ERROR; fast => WITH y: impl2 SELECT FROM fast => { DoCompareDownTerms: PROC [k: KeySym, c: TIPChoice] = TRUSTED { yChoice: TIPChoice ¬ TIPFastTables.FetchFromFastTable[y.keyDown, k]; EqualChoices[c, yChoice]; }; DoCompareUpTerms: PROC [k: KeySym, c: TIPChoice] = TRUSTED { yChoice: TIPChoice ¬ TIPFastTables.FetchFromFastTable[y.keyUp, k]; EqualChoices[c, yChoice]; }; EqualChoices[x.mouse,y.mouse]; IF TIPFastTables.GetSizeFastTable[x.keyDown] # TIPFastTables.GetSizeFastTable[y.keyDown] THEN ERROR; TIPFastTables.WalkKeySymsInFastTable[x.keyDown, DoCompareDownTerms]; TIPFastTables.WalkKeySymsInFastTable[x.keyUp, DoCompareUpTerms]; EqualChoices[x.time, y.time]; }; small => ERROR; ENDCASE => ERROR; ENDCASE => ERROR; }; EqualChoiceSeries: PROC [c1, c2: TIPChoiceSeries] = { DO IF c1 = c2 THEN RETURN; IF c1 = NIL OR c2 = NIL THEN ERROR; EqualChoices[c1.first, c2.first]; c1 ¬ c1.rest; c2 ¬ c2.rest; ENDLOOP; }; EqualChoices: PROC [c1, c2: TIPChoice] = TRUSTED { DO IF c1 = c2 THEN RETURN; IF c1 = NIL OR c2 = NIL THEN ERROR; WITH x: c1.first SELECT FROM keyTrigger => WITH y: c2.first SELECT FROM keyTrigger => IF x.keyState # y.keyState THEN ERROR; ENDCASE => ERROR; mouseTrigger => WITH y: c2.first SELECT FROM mouseTrigger => NULL; ENDCASE => ERROR; trackballTrigger => WITH y: c2.first SELECT FROM trackballTrigger => NULL; ENDCASE => ERROR; thumbwheelTrigger => WITH y: c2.first SELECT FROM thumbwheelTrigger => NULL; ENDCASE => ERROR; timeTrigger => WITH y: c2.first SELECT FROM timeTrigger => IF x.flavor # y.flavor OR x.mSecs # y.mSecs THEN ERROR; ENDCASE => ERROR; keyEnable => WITH y: c2.first SELECT FROM keyEnable => IF x.keyState # y.keyState THEN ERROR; ENDCASE => ERROR; key2Enable => WITH y: c2.first SELECT FROM key2Enable => IF x.keyState1 # y.keyState1 OR x.keyState2 # y.keyState2 THEN ERROR; ENDCASE => ERROR; keyEnableList => WITH y: c2.first SELECT FROM keyEnableList => { lst1: LIST OF TIPKeyState ¬ x.lst; lst2: LIST OF TIPKeyState ¬ y.lst; DO IF lst1 = NIL THEN IF lst2 = NIL THEN EXIT ELSE ERROR; IF lst2 = NIL THEN ERROR; IF lst1.first # lst2.first THEN ERROR; lst1 ¬ lst1.rest; lst2 ¬ lst2.rest; ENDLOOP }; ENDCASE => ERROR; predEnable => WITH y: c2.first SELECT FROM predEnable => IF x.predicate # y.predicate THEN ERROR; ENDCASE => ERROR; char => WITH y: c2.first SELECT FROM char => NULL; ENDCASE => ERROR; coords => WITH y: c2.first SELECT FROM coords => NULL; ENDCASE => ERROR; trackballChange => WITH y: c2.first SELECT FROM trackballChange => NULL; ENDCASE => ERROR; thumbwheelChange => WITH y: c2.first SELECT FROM thumbwheelChange => NULL; ENDCASE => ERROR; nested => WITH y: c2.first SELECT FROM nested => EqualChoiceSeries[x.statement, y.statement]; ENDCASE => ERROR; result => WITH y: c2.first SELECT FROM result => { cList1: TIPResults ¬ x.list; cList2: TIPResults ¬ y.list; DO SELECT TRUE FROM cList1 = cList2 => RETURN; cList1=NIL, cList2=NIL => ERROR; cList1.first = cList2.first => {}; cList1.first = TIPPrivate.stdChar, cList2.first = TIPPrivate.stdChar => ERROR; cList1.first = TIPPrivate.stdCoords, cList2.first = TIPPrivate.stdCoords => ERROR; cList1.first = TIPPrivate.stdTrackballChange, cList2.first = TIPPrivate.stdTrackballChange => ERROR; cList1.first = TIPPrivate.stdThumbwheelChange, cList2.first = TIPPrivate.stdThumbwheelChange => ERROR; ENDCASE => WITH cList1.first SELECT FROM x: ATOM => WITH cList2.first SELECT FROM y: ATOM => IF x # y THEN ERROR; ENDCASE => ERROR; x: REF INT => WITH cList2.first SELECT FROM y: REF INT => IF x­ # y­ THEN ERROR; ENDCASE => ERROR; x: REF TEXT => WITH cList2.first SELECT FROM y: REF TEXT => { IF x.length # y.length THEN ERROR; FOR i:NAT IN [0..x.length) DO IF x[i] # y[i] THEN ERROR; ENDLOOP }; ENDCASE => ERROR; ENDCASE => ERROR; cList1 ¬ cList1.rest; cList2 ¬ cList2.rest; ENDLOOP; }; ENDCASE => ERROR; ENDCASE => ERROR; c1 ¬ c1.rest; c2 ¬ c2.rest; ENDLOOP; }; debug: BOOL = FALSE; debugStream: STREAM; WriteTIPCFile: PROC [table: TIPTable, keyOption: KeyOption, s: STREAM] = { impl: TIPTableImpl ~ table.impl; Char: PROC [c: CHAR] = { IO.PutChar[s, c]; IF debug THEN IO.PutChar[debugStream,c]; }; String: PROC [str: REF READONLY TEXT] = { IO.PutBlock[s,str]; IF debug THEN IO.PutBlock[debugStream,str]; }; Text: PROC [txt: REF READONLY TEXT] = { IF txt.length > 255 THEN ERROR; Char[LOOPHOLE[txt.length]]; String[txt]; }; Bool: PROC [flag: BOOL] = { Char[IF flag THEN 'T ELSE 'F] }; Key: PROC [k: KeySym] = { b: Basics.Word32 ~ [card[k]]; Char[LOOPHOLE[b.hh]]; Char[LOOPHOLE[b.hl]]; Char[LOOPHOLE[b.lh]]; Char[LOOPHOLE[b.ll]]; }; Int: PROC [x: INT] = { b: Basics.LongNumber ¬ LOOPHOLE[x]; Char[LOOPHOLE[b.hh]]; Char[LOOPHOLE[b.hl]]; Char[LOOPHOLE[b.lh]]; Char[LOOPHOLE[b.ll]]; }; ChoiceItem: PROC [k: KeySym, c: TIPChoice] = { IF c=NIL THEN RETURN; Char['(]; Key[k]; Choice[c]; Char[')] }; ChoiceSeries: PROC [cs: TIPChoiceSeries] = { Char['(]; FOR x: TIPChoiceSeries ¬ cs, x.rest UNTIL x=NIL DO Choice[x.first]; ENDLOOP; Char[')]; }; Choice: PROC [c: TIPChoice] = { Char['(]; FOR x: TIPChoice ¬ c, x.rest UNTIL x=NIL DO Term[x.first]; ENDLOOP; Char[')]; }; KeyState: PROC [keyState: TIPKeyState] = { Key[keyState.keySym]; Char[SELECT keyState.state FROM up => 'U, down => 'D, ENDCASE => ERROR] }; Term: PROC [t: TIPTerm] = TRUSTED { WITH x: t SELECT FROM keyTrigger => { Char['1]; Key[x.keyState.keySym]; Char[SELECT x.keyState.state FROM up => 'U, down => 'D, ENDCASE => ERROR] }; mouseTrigger => Char['2]; trackballTrigger => Char['T]; thumbwheelTrigger => Char['W]; timeTrigger => { Char['3]; Char[SELECT x.flavor FROM gt => 'G, lt => 'L, ENDCASE => ERROR]; Char[LOOPHOLE[x.mSecs / 256]]; Char[LOOPHOLE[x.mSecs MOD 256]] }; keyEnable => { Char['4]; KeyState[x.keyState] }; predEnable => { Char['5]; Text[LOOPHOLE[Atom.GetPName[x.predicate]]] }; char => Char['6]; coords => Char['7]; trackballChange => Char['t]; thumbwheelChange => Char['w]; nested => { Char['8]; ChoiceSeries[x.statement] }; result => { Char['9]; Results[x.list] }; key2Enable => { Char['A]; KeyState[x.keyState1]; KeyState[x.keyState2] }; keyEnableList => { Char['B]; Char['(]; FOR lst: LIST OF TIPKeyState ¬ x.lst, lst.rest UNTIL lst=NIL DO KeyState[lst.first]; ENDLOOP; Char[')] }; time => Char['C]; ENDCASE => ERROR; }; Results: PROC [c: TIPResults] = { Char['(]; FOR x: TIPResults ¬ c, x.rest UNTIL x=NIL DO Result[x.first]; ENDLOOP; Char[')] }; Result: PROC [r: REF ANY] = TRUSTED { IF r=TIPPrivate.stdCoords THEN Char['5] ELSE IF r=TIPPrivate.stdChar THEN Char['2] ELSE IF r=TIPPrivate.stdTime THEN Char['6] ELSE IF r=TIPPrivate.stdTrackballChange THEN Char['7] ELSE IF r=TIPPrivate.stdThumbwheelChange THEN Char['8] ELSE WITH r SELECT FROM x: ATOM => { Char['1]; Text[LOOPHOLE[Atom.GetPName[x]]] }; x: REF INT => { Char['3]; Int[x­] }; x: REF TEXT => { Char['4]; Text[x] }; ENDCASE => ERROR }; String["TIPTABLE"]; Char[TIPPrivate.version]; Bool[table.opaque]; Char[SELECT keyOption FROM none => 'N, printKeys => 'P, defaultKeys => 'D, ENDCASE => ERROR]; Bool[impl.ignore.up]; Bool[impl.ignore.down]; Bool[impl.ignore.move]; WITH impl SELECT FROM x: REF small TIPTableImplRep => { Char['S]; ChoiceSeries[x.all] }; x: REF fast TIPTableImplRep => { Char['F]; Choice[x.mouse]; Char['U]; Char['(]; TIPFastTables.WalkKeySymsInFastTable[x.keyUp, ChoiceItem]; Char[')]; Char['D]; Char['(]; TIPFastTables.WalkKeySymsInFastTable[x.keyDown, ChoiceItem]; Char[')]; Choice[x.time]; }; ENDCASE => ERROR; }; tipFilePrefix: ROPE; SetTIPFilePrefix: PROC[hadError: BOOL] = { pth: ROPE ¬ IF debug THEN NIL ELSE SystemNames.SimpleHomeDirectory[]; IF (pth.Length[] < 3 ) OR hadError THEN { -- in case "//" returned ???? pth ¬ "/tmp/"; SimpleFeedback.Append[$TIP, oneLiner, $Feedback, "TIP: Home directory not available - using -vux:/tmp/ ..."]; } ELSE pth ¬ SystemNames.UserCedarDir["tipb"]; tipFilePrefix ¬ Rope.Concat["-vux:", pth]; }; SetTIPFilePrefix[FALSE]; END. Β TIPTableReaderWriterImpl.mesa Copyright Σ 1985, 1986, 1989, 1990, 1991, 1992, 1993 by Xerox Corporation. All rights reserved. Doug Wyatt, January 19, 1987 11:35:36 pm PST Russ Atkinson (RRA) April 9, 1990 6:15 pm PDT Tim Diebert: April 20, 1988 12:10:24 pm PDT Michael Plass, November 26, 1991 1:37 pm PST Bier, March 4, 1993 12:42 pm PST Willie-s, June 23, 1993 3:24 pm PDT Kenneth A. Pier, August 5, 1992 6:42 pm PDT Christian Jacobi, March 3, 1992 9:10 am PST Last tweaked by Mike Spreitzer April 15, 1992 7:13 am PDT Contents: Manage TIP files. Reads .tip files. Creates .tipB (compiled Tip files). The actual building of TIP tables is performed in TIPTableBuilderImpl. Try to read the compiled (tipB) version of the tip file. The tipB filename contains the create date of the tip file (as a BasicTime.GMT) so we can determine correspondence between the two. The default table acts as a back stop, translating the printing keys. We will have to make a tipB file, starting from the tip file. Any PFS.Error will propagate from here. Produce the tipB file. Make sure that building a table from the tipB, produces the same result. Gets the file name stripped of directory and version information, but retaining the extension. keytrigger mousetrigger trackballTrigger thumbwheelTrigger timetrigger keyenable predenable char mouse coords Trackball coords Thumbwheel coords choiceseries results key2Enable keyEnableList TIME These calls to Char[] are on separate lines so we don't depend on left-to-right evaluation. small table fast table Make sure the two tables are equivalent. Return an error if not. This routine is TRUSTED because with WITH ... SELECT FROM clauses are unsafe. check each choice on list This routine is TRUSTED because the WITH ... SELECT FROM statement is unsafe. check each term on list check each term on list This routine must be TRUSTED because of the LOOPHOLE IF debug THEN debugStream _ ViewerIO.CreateViewerStreams["TIPTableWriterDebugLog"].out; liberalMode: UnixStat.Mode _ [fmt: dir, owner: [true, true, true], group: [true, true, true], others: [true, true, true]]; IF UnixSysCalls.MkDir[path: UXStrings.Create["/tmp/tip"], mode: liberalMode] = failure THEN { SimpleFeedback.Append[$TIP, oneLiner, $Feedback, "TIP: Using existing /tmp/tip. I hope we have write permission ... "]; } ELSE { SimpleFeedback.Append[$TIP, begin, $Feedback, "TIP: Creating /tmp/tip with permissions 777 ... "]; IF UnixSysCalls.ChMod[path: UXStrings.Create["/tmp/tip"], mode: liberalMode] = failure THEN SimpleFeedback.Append[$TIP, end, $Feedback, "failed."] ELSE SimpleFeedback.Append[$TIP, end, $Feedback, "done."] Use ChMod because UnixSysCalls.MkDir above appears to create with mode 755 no matter what arguments are given. }; ΚΘ•NewlineDelimiter –(cedarcode) style™codešœ™Kšœ ΟeœU™`K™,K™-K™+Kšœ,™,K™ K™#K™+K™+K™9K˜K™›K™—šΟk ˜ Jšœ"žœžœ¬˜κK˜—šΟnœžœž˜'Kšžœžœžœp˜–Kšžœ>ž˜JK˜Kšœ žœžœ˜DKšœžœžœ˜MK˜Kšœ žœ˜'Kšœžœ˜Kšžœžœžœ˜Kšžœžœ žœ˜Kšžœžœžœžœ˜Kšœžœžœ˜)Kšœ žœžœ˜-Kšœžœžœ˜9Kšœ žœžœ˜1Kšœ žœžœ˜/Kšœ žœžœ˜*Kšœ žœžœ˜)—K˜Kšœ žœžœ˜K˜Kšœžœžœ˜K˜šŸœžœžœžœ˜*šžœžœž˜.Kšœžœžœ ˜"Kšžœžœ˜—šžœžœž˜.Kšœžœžœ ˜"Kšžœžœ˜—Kšžœ0˜6K˜K˜—šŸœžœžœžœ˜2Kšœžœ˜.K˜K˜—š Ÿœžœžœžœžœ˜:Kšœžœžœ˜3K˜K˜—š Ÿœžœžœ žœžœžœ˜@Kšžœ žœ˜,Kšžœ˜Kšœ˜K˜—š Ÿœžœžœžœžœžœ˜Tšžœžœ žœžœ˜,Kšœžœ˜!Kšœžœ˜ Kšžœ žœW˜iKšžœ˜Kšžœ˜Kšžœ˜Kšœ˜—Kšœžœ˜Kšœ žœ5˜CK˜Kšœ žœ žœ˜*Kšœžœ˜.Kšœžœ˜Kšœ žœžœ˜Kšœ,žœžœ˜WKšœ˜šœ˜Kšœ½™½˜Kšœžœžœ˜$Kšœžœžœ˜Kšœ1žœ žœžœ˜iKšœE˜Ešœžœ žœ˜4Kšœžœ žœžœ˜Kšœ˜—Kšœ0žœ˜:Kšžœ ˜ K˜—šžœ žœžœ˜šžœžœ˜K™EK˜9Kšœžœ˜Kšœ˜—Kšžœ ˜Kšœ˜—Kšžœ˜Kšœ˜—Kšœf™fKšœ.žœ˜JKšžœ žœžœžœ˜K˜K™˜Kšœžœžœ˜Kšœžœ˜ šž˜Kšœžœ žœ#žœ žœžœžœžœžœ˜kKšžœžœžœžœ˜Kšœžœ˜Kšœ=˜=Kšœžœ˜Kšžœ˜—Kšœ!˜!Kšžœ ˜ K˜—K˜KšœH™H˜K˜K˜Kšœžœžœ žœ ˜?Kšœ,˜,Kšžœ ˜ Kšžœžœžœ˜$Kšœ$Οc&˜JK˜—Kšžœ ˜K˜K˜—šŸœžœžœžœ˜Gšžœžœžœž˜.šžœžœžœž˜-Kšžœžœžœ˜Kšžœ˜—Kšžœ˜—šžœžœžœž˜3šžœžœ˜Kšœžœ$˜:Kšœ žœ˜K˜K˜—Kšžœ˜—Kšžœžœ˜ K˜—š Ÿ œžœžœžœžœ˜/K™^Kšžœ,žœ˜LK˜K˜—šΟb œžœžœžœ3˜YKš œžœžœžœžœ "˜BKšœžœ˜Kšœžœ ˜ šŸœžœžœžœ˜&Kšžœ žœžœ ˜!Kšžœžœžœžœ˜3Kšžœžœž œ ˜GK˜K˜—š Ÿœžœžœžœžœ˜$Kšœ˜Kšžœžœ ˜Kšœ˜—šŸœžœžœžœ˜)Kšœžœ˜)Kšœ˜K˜—šŸœžœžœžœ˜ Kšœžœžœ˜ Kšžœ)˜/Kšœ˜—šŸœžœžœžœ˜Kšžœžœžœžœžœžœžœ ˜OKšœ˜—šŸ œžœ˜K˜ K˜K˜K˜K˜K˜—šŸ œžœžœ%˜=šžœž˜Kšœžœ žœžœ˜!Kšœžœ˜ Kšžœžœ ˜—K˜ K˜Kšžœ žœžœ ˜#Kšœ˜—š Ÿœžœ žœžœžœ˜DK˜Kšœžœ˜ Kšžœ žœ žœžœ ˜0šžœž˜K˜Kšžœžœžœžœ˜CKšžœ˜—Kšœ˜—šŸ œžœžœ˜8K˜Kšžœ žœžœ ˜#šžœ ž˜Kšœžœžœ˜.Kšžœžœžœžœ˜IKšžœ˜—Kšœ˜—šŸœžœžœžœ˜5Kšžœž˜šœ˜Kšœ ™ K˜K˜ šœžœž˜+Kšœžœžœ ˜0—Kšžœžœ ˜—šœ˜Kšœ ™ K˜ Kšžœžœ˜—˜K™K˜Kšžœžœ˜Kšœ˜—˜K™K˜ Kšžœžœ˜Kšœ˜—šœ˜Kšœ ™ K˜Kšœžœ˜šœžœž˜$Kšœžœžœ ˜.—Kšœžœžœ˜&Kšœžœžœ˜*K˜Kšžœžœ˜—šœ˜Kšœ ™ K˜K˜Kšžœžœ ˜—šœ˜Kšœ ™ K˜K˜Kšžœžœ˜—šœ˜Kšœ™K˜Kšœ!˜!Kšžœžœ˜—šœ˜K™ K˜Kšœ%˜%Kšžœžœ˜—˜K™K˜K˜)Kšžœžœ˜Kšœ˜—˜K™K˜K˜(Kšžœžœ˜Kšœ˜—šœ˜Kšœ ™ K˜K˜ Kšžœžœ ˜—šœ˜Kšœ™K˜K˜Kšžœžœ˜—šœ˜Kšœ ™ K˜K˜K˜Kšžœžœ ˜—šœ˜Kšœ ™ K˜Kšœžœžœ ˜Kšžœ žœžœ ˜#šžœžœž˜Kšœ žœžœžœ ˜1Kšžœžœžœžœ˜MKšžœ˜—Kšžœ žœžœ˜Kšžœžœ ˜—šœ˜Kšœ™K˜Kšœ#˜#Kšžœžœ ˜Kšœ˜—Kšžœžœ ˜Kšœ˜—šŸœžœžœ˜2K˜šœžœž˜#Kšœžœžœ ˜0—Kšœ˜—šŸœžœžœ˜/Kšœžœ˜Kšœžœ˜ Kšžœ žœžœ ˜#šžœž˜Kš œžœžœžœžœžœ˜-Kšžœžœžœžœ˜HKšžœ˜—Kšœ˜—š Ÿœžœžœžœžœžœ  ˜Pšžœž˜Kšœžœ  ˜$Kšœžœ $˜Gšœ ˜"šœ˜Kšœ[™[—Kšœžœ ˜Kšœžœ ˜Kšœžœ ˜Kšœžœ ˜Kšžœžœžœžœ˜ K˜—šœ .˜6Kšœžœ ˜Kšœžœžœ˜!Kšœ ˜ Kšœ*˜*Kšžœ˜ Kšœ˜—Kšœžœ˜$Kšœžœ˜"Kšœžœ!˜-Kšœžœ"˜.Kšžœžœ ˜—Kšœ˜K˜—K˜Kšžœ8žœžœ ˜NKšžœžœžœ ˜3K˜šœ žœž˜Kšœ0žœžœ ˜J—K˜*šžœž˜šœ˜Kšœ ™ Kšœžœžœ˜>Kšœžœ˜)K˜ K˜K˜—šœ˜Kšœ ™ Kšœžœžœ˜;K˜ K˜K˜K˜-K˜/Kšœžœ˜(K˜ K˜Kšžœ žœžœ ˜#Kšžœ žœžœ ˜#šžœ˜ Kšžœžœžœžœ˜K˜8Kšžœ˜—Kšžœ žœžœ ˜#Kšžœ žœžœ ˜#šžœ˜Kšžœžœžœžœ˜K˜:Kšžœ˜ —K˜K˜—Kšžœžœ ˜—K˜K˜—šŸœžœžœžœ˜=K™AKšœžœžœžœ™MK˜K˜Kšžœžœžœ˜$Kšžœžœžœ˜*šžœ žœž˜šœ žœ žœž˜"K˜(Kšœžœ˜Kšžœžœ˜—šœžœ žœž˜!˜ šŸœžœžœ˜>K˜DKšœ˜K˜—šŸœžœžœ˜