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