DIRECTORY Buttons USING [Button, ButtonProc, Create], CCTypes USING[CCError, CCErrorCase], CirioButtons USING[ButtonSet, ButtonSize, ChoiceList, CreateButtonSet, CreateViewer, GetButtonSize, InstallCommandButton, InstallLabelButton, InstallSourceLanguageButton, InstallRule, InstallShowFrameButton, InstallSourcePositionButton, InstallWalkStackButton, KillButtonSet, MainActionProc, MoveToX, MoveToY, NewLine, SkipX, ViewerControl], CirioTypes USING[CompilerContext], Commander USING[CommandProc, Register], CommanderOps USING[ParseToList], Containers USING[ChildXBound, Create], Convert USING[CardFromRope, Error, RopeFromAtom, RopeFromCard], DisassembleSPARC, FileNames USING[CurrentWorkingDirectory], IO USING[PutF, PutF1, PutRope, rope, STREAM], Labels USING [Set], NetworkName USING[AddressFromName, Error], Process USING[Detach], RemoteCirio USING[AbortThread, AddSearchDirectory, CloseConnection, Connection, DbxExamineThread, DestroyRemoteWorld, FindThreadsWithProperty, FlushUnknownFileCache, FocusOnThread, FreezeThread, GetDummyStack, GetStackForCurrentThread, GetThreadTitleText, InstallBreakCheckDaemon, KillThread, ListSearchDirectory, OpenConnection, ProceedThread, ResumeRemoteWorld, ResumeRemoteWorldWithOnlyVP0, ShowQuickSummary, StopBreakCheckDaemon, StopRemoteWorld, ThreadIDFromIndex], Rope USING[Cat, Concat, Equal, Find, Length, ROPE], SourceFileOps USING [FormatPosition, GetSelection, OpenSource, noPosition, Position], SystemNames USING[MachineName], StackCirio USING[ClearAllBreakPoints, ClearBreakPoint, Disassemble, FormatPrompt, InterpretTextLine, ListBreakPoints, ResetStack, SetBreakPointAtAddress, SetBreakPointAtPosition, Stack], Termination USING[CallBeforeQuitWorld], TiogaOps USING[FindText, FindWord, SearchDir], WindowSystemInterface USING[GetSelectionContents], ViewerClasses USING[MouseButton, Viewer], ViewerOps USING[BlinkViewer, PaintViewer]; RemoteDriver3: CEDAR MONITOR LOCKS d USING d: MyViewerData IMPORTS Buttons, CCTypes, CirioButtons, Commander, CommanderOps, Containers, Convert, DisassembleSPARC, FileNames, IO, Labels, NetworkName, Process, RemoteCirio, Rope, SourceFileOps, StackCirio, SystemNames, Termination, TiogaOps, WindowSystemInterface, ViewerOps = BEGIN ROPE: TYPE ~ Rope.ROPE; CC: TYPE = CirioTypes.CompilerContext; CCE: ERROR[case: CCTypes.CCErrorCase, msg: Rope.ROPE ฌ NIL] ฌ CCTypes.CCError; MyViewerData: TYPE = REF MyViewerDataBody; MyViewerDataBody: TYPE = MONITORED RECORD[ vc: CirioButtons.ViewerControl ฌ NIL, connection: RemoteCirio.Connection, dummyStack: StackCirio.Stack, serverName: ROPE, portNum: CARD, threadsInfo: REF ThreadsInfo, remoteWorldGone: BOOLEAN ฌ FALSE, runningFlag: BOOLEAN ฌ TRUE, runningLabel: ViewerClasses.Viewer, stopAllFlag: BOOLEAN ฌ FALSE, stopAllLabel: ViewerClasses.Viewer, dbxFlag: BOOLEAN ฌ FALSE, lineH: CARD ฌ 0, worldControlY: INTEGER ฌ 0, worldControlH: INTEGER ฌ 0, worldControlButtonSet: CirioButtons.ButtonSet, threadControlY: INTEGER ฌ 0, threadControlH: INTEGER ฌ 0, threadControlButtonSet: CirioButtons.ButtonSet, threadListControlButtonsInstalled: BOOL ฌ FALSE, rule1Y: INTEGER ฌ 0, threadButtonsY: INTEGER ฌ 0, threadButtonsH: INTEGER ฌ 0, threadButtonsButtonSet: CirioButtons.ButtonSet, activeThread: REF ThreadButtonInfo ฌ NIL, activeThreadRemoteIndex: CARD, currentStack: StackCirio.Stack, rule2Y: INTEGER ฌ 0, stopFlag: REF BOOLEAN ฌ NIL, generalButtonsY: INTEGER ฌ 0, generalButtonsH: INTEGER ฌ 0, generalButtonsButtonSet: CirioButtons.ButtonSet, stackButtonsY: INTEGER ฌ 0, stackButtonsH: INTEGER ฌ 0, stackButtonsButtonSet: CirioButtons.ButtonSet, frameLabel: ViewerClasses.Viewer, rule3Y: INTEGER ฌ 0, findButtonsY: INTEGER ฌ 0, findButtonsH: INTEGER ฌ 0, findButton: ViewerClasses.Viewer, wordButton: ViewerClasses.Viewer, rule4Y: INTEGER ฌ 0, scriptY: INTEGER ฌ 0 ]; ThreadsInfo: TYPE = RECORD[SEQUENCE nThreads: CARDINAL OF REF ThreadButtonInfo]; ThreadButtonInfo: TYPE = RECORD[d: MyViewerData, index: CARD, visible: BOOLEAN, label: ViewerClasses.Viewer]; toolIDInfo: TYPE ~ RECORD [ valid: BOOL ฌ FALSE, localPort: CARD ฌ 0, localName: Rope.ROPE ฌ NIL, localHostIP: Rope.ROPE ฌ NIL ]; thisTool: toolIDInfo ฌ []; GetPortNum: PROC RETURNS[CARD] = TRUSTED MACHINE CODE {"CirioNubLocalGetPort"}; Driver: Commander.CommandProc = { d: MyViewerData ฌ NEW[MyViewerDataBody]; args: LIST OF ROPE; numArgs: NAT; serverName: ROPE; serverNameIP: ROPE; portNum: CARDINAL; wDirs: LIST OF ROPE ฌ NIL; lastWDir: LIST OF ROPE ฌ NIL; cDir: LIST OF ROPE ฌ LIST[FileNames.CurrentWorkingDirectory[]]; [args, numArgs] ฌ CommanderOps.ParseToList[cmd]; { ENABLE { Convert.Error => {GOTO usage}; NetworkName.Error => { errRope: Rope.ROPE ฌ NIL; IO.PutF[cmd.out, "\nProblem(s) occured while looking up host %g (%g", [rope[serverName]], [rope[msg]]]; FOR problems: LIST OF ATOM ฌ codes, problems.rest WHILE problems # NIL DO errRope ฌ Convert.RopeFromAtom[problems.first, FALSE]; IO.PutF1[cmd.out, ", %g", [rope[errRope]]]; ENDLOOP; IO.PutRope[cmd.out, ")\nPlease verify the correct and and try again.\n\n"]; GOTO done; }; }; IF numArgs<1 THEN GOTO usage; serverName ฌ args.first; serverNameIP ฌ NetworkName.AddressFromName[family: $ARPA, name: serverName, portHint: NIL, components: host].addr; portNum ฌ IF numArgs < 2 THEN 4815 ELSE CARDINAL[Convert.CardFromRope[args.rest.first]]; EXITS usage => RETURN [$Failure, "Usage: CirioRemote [ []]"]; done => RETURN; }; wDirs ฌ IF numArgs < 3 THEN NIL ELSE args.rest.rest; IF wDirs # NIL THEN { FOR thisDir: LIST OF ROPE ฌ wDirs, thisDir.rest WHILE thisDir # NIL DO lastWDir ฌ thisDir; ENDLOOP; lastWDir.rest ฌ cDir; } ELSE { wDirs ฌ cDir; }; { localhost: Rope.ROPE ฌ "localhost"; anonMachine: Rope.ROPE ฌ "AnonymousMachine"; IF NOT thisTool.valid THEN { thisTool.localPort ฌ GetPortNum[]; thisTool.localName ฌ SystemNames.MachineName[]; IF (Rope.Equal[thisTool.localName, anonMachine]) THEN { thisTool.localName ฌ localhost; IO.PutRope[cmd.out, "\nSystemNames.MachineName reports AnonymousMachine. Using localhost instead.\n\n"]; }; thisTool.localHostIP ฌ NetworkName.AddressFromName[family: $ARPA, name: thisTool.localName, portHint: NIL, components: host].addr; thisTool.valid ฌ TRUE; }; IF (portNum = thisTool.localPort AND (Rope.Equal[thisTool.localHostIP, serverNameIP] OR Rope.Equal[localhost, serverName])) THEN { IO.PutRope[cmd.out, "\nYou are attempting to connect Cirio to itself.\nPlease verify the correct and and try again.\n\n"]; RETURN; }; }; d.lineH ฌ CirioButtons.GetButtonSize["Sample"].h+1; d.worldControlY ฌ 1; d.worldControlH ฌ d.lineH; d.threadControlY ฌ d.worldControlY+d.worldControlH; d.threadControlH ฌ 2*d.lineH; d.rule1Y ฌ d.threadControlY+d.threadControlH; d.threadButtonsY ฌ d.rule1Y+2; d.threadButtonsH ฌ 6*d.lineH; d.rule2Y ฌ d.threadButtonsY+d.threadButtonsH+1; d.generalButtonsY ฌ d.rule2Y+1; d.generalButtonsH ฌ d.lineH; d.stackButtonsY ฌ d.generalButtonsY+d.generalButtonsH+1; d.stackButtonsH ฌ d.lineH; d.rule3Y ฌ d.stackButtonsY+d.stackButtonsH+1; d.findButtonsY ฌ d.stackButtonsY + d.generalButtonsH + 1; d.findButtonsH ฌ d.lineH; d.rule4Y ฌ d.findButtonsY+d.findButtonsH+1; d.scriptY ฌ d.rule4Y+1; d.vc ฌ CirioButtons.CreateViewer[Rope.Cat["Cirio remote ", serverName, " (", Convert.RopeFromCard[portNum], ")"], d.scriptY, FormatPrompt, InterpretTextLine, ShutDown, d]; d.connection ฌ RemoteCirio.OpenConnection[serverName, portNum, wDirs, d.vc.out]; IF d.connection=NIL THEN { TRUSTED{Process.Detach[FORK CirioButtons.MainActionProc[d.vc]]}; --so delete works RETURN [$Failure, "Debugging session abandoned because couldn't open connection"]}; BEGIN ENABLE UNWIND => {CleanupConnection[d]}; Termination.CallBeforeQuitWorld[CleanupConnection, d]; RemoteCirio.InstallBreakCheckDaemon[d.connection, d.vc.out]; d.dummyStack ฌ RemoteCirio.GetDummyStack[d.connection, d.vc.out]; d.serverName ฌ serverName; d.portNum ฌ portNum; d.stopFlag ฌ NEW[BOOLEANฌFALSE]; InstallRules[d]; InstallWorldControlButtons[d]; InstallFindButtons[d]; TRUSTED{Process.Detach[FORK CirioButtons.MainActionProc[d.vc]]}; SetThreadControlToRunning[d]; END; RETURN}; CleanupConnection: PROC [x: REF] = { d: MyViewerData ฌ NARROW[x]; IF d # NIL AND d.vc.self # NIL THEN RemoteCirio.CloseConnection[d.connection, d.vc.out]; }; FormatPrompt: PROC [counter: INT, clientData: REF ANY] RETURNS [ROPE] ~ { d: MyViewerData ฌ NARROW[clientData]; stack: StackCirio.Stack ฌ IF d.currentStack # NIL THEN d.currentStack ELSE d.dummyStack; IF d.connection=NIL THEN RETURN["broken!"]; RETURN StackCirio.FormatPrompt[stack, counter]}; InterpretTextLine: PROC[line: ROPE, reports: IO.STREAM, clientData: REF ANY] RETURNS[ROPE] = { d: MyViewerData ฌ NARROW[clientData]; stack: StackCirio.Stack ฌ IF d.currentStack # NIL THEN d.currentStack ELSE d.dummyStack; IF d.connection=NIL THEN RETURN["I'm broken, you fool"]; RETURN[StackCirio.InterpretTextLine[stack, line, reports]]; }; InstallFindButtons: PROC[d: MyViewerData] = BEGIN d.findButton ฌ Buttons.Create[info: [wx: 0, wy: d.findButtonsY + 1, ww: 50, wh: d.findButtonsH, name: "Find", parent: d.vc.self, border: FALSE], proc: FindAction, clientData: d.vc.script]; d.wordButton ฌ Buttons.Create[info: [wx: 50, wy: d.findButtonsY + 1, ww: 50, wh: d.findButtonsH, name: "Word", parent: d.vc.self, border: FALSE], proc: WordAction, clientData: d.vc.script]; END; FindAction: Buttons.ButtonProc ~ { script: ViewerClasses.Viewer ฌ NARROW[clientData]; IF ~TiogaOps.FindText[viewer: script, rope: NIL, whichDir: DirFromClick[mouseButton], which: primary, case: ~shift] THEN ViewerOps.BlinkViewer[script, 300]; }; WordAction: Buttons.ButtonProc ~ { script: ViewerClasses.Viewer ฌ NARROW[clientData]; IF ~TiogaOps.FindWord[viewer: script, rope: NIL, whichDir: DirFromClick[mouseButton], which: primary, case: ~shift] THEN ViewerOps.BlinkViewer[script, 300]; }; DirFromClick: PROC[b: ViewerClasses.MouseButton] RETURNS [dir: TiogaOps.SearchDir ฌ forwards] ~ { SELECT b FROM red => dir ฌ forwards; blue => dir ฌ backwards; yellow => dir ฌ anywhere; ENDCASE => ERROR; }; InstallRules: PROC[d: MyViewerData] = BEGIN ruleButtonSet: CirioButtons.ButtonSet ฌ CirioButtons.CreateButtonSet[d.vc.self, d.vc, 0, 0, 0, d.lineH, 0]; CirioButtons.MoveToY[ruleButtonSet, d.rule1Y]; CirioButtons.InstallRule[ruleButtonSet]; CirioButtons.MoveToY[ruleButtonSet, d.rule2Y]; CirioButtons.InstallRule[ruleButtonSet]; CirioButtons.MoveToY[ruleButtonSet, d.rule3Y]; CirioButtons.InstallRule[ruleButtonSet]; CirioButtons.MoveToY[ruleButtonSet, d.rule4Y]; CirioButtons.InstallRule[ruleButtonSet]; END; InstallWorldControlButtons: PROC [d: MyViewerData] = BEGIN worldControlViewer: ViewerClasses.Viewer ฌ Containers.Create[ info: [parent: d.vc.self, border: FALSE, scrollable: FALSE, wx: 0, wy: d.worldControlY, ww: d.vc.self.cw, wh: d.worldControlH] ]; bs: CirioButtons.ButtonSet ฌ d.worldControlButtonSet ฌ CirioButtons.CreateButtonSet[worldControlViewer, d.vc, 0, 0, 0, d.lineH, 0]; Containers.ChildXBound[d.vc.self, worldControlViewer]; [] ฌ CirioButtons.InstallCommandButton[ bs: bs, name: "Flush unknownFileCache", border: TRUE, clientData1: d, proc2: FlushAction]; CirioButtons.SkipX[bs, 5]; d.runningLabel ฌ CirioButtons.InstallLabelButton[bs, "Remote World Running"]; CirioButtons.SkipX[bs, 2]; [] ฌ CirioButtons.InstallCommandButton[ bs: bs, name: "KillRemoteWorld", border: TRUE, guarded: TRUE, clientData1: d, proc2: KillRemoteWorld]; END; BreakCheckDaemonInitialize: PROC [button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] = BEGIN p: PROCESS; d: MyViewerData ฌ NARROW[clientData1]; RemoteCirio.InstallBreakCheckDaemon[connection: d.connection, reports: d.vc.out]; END; FlushAction: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] = BEGIN d: MyViewerData ฌ NARROW[clientData1]; IO.PutRope[d.vc.out, "Flushing unknown file cache ..."]; RemoteCirio.FlushUnknownFileCache[d.connection, d.vc.out]; IO.PutRope[d.vc.out, " done flushing.\n"]; END; KillRemoteWorld: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] = BEGIN d: MyViewerData ฌ NARROW[clientData1]; RemoteCirio.StopBreakCheckDaemon[connection: d.connection, reports: d.vc.out]; IO.PutRope[d.vc.out, "Killing remote world ..."]; CloseThreadInner[d]; RemoveThreadButtons[d]; RemoteCirio.DestroyRemoteWorld[d.connection]; d.connection ฌ NIL; Labels.Set[d.runningLabel, " Remote World Gone"]; d.runningFlag ฌ FALSE; d.remoteWorldGone ฌ TRUE; ViewerOps.PaintViewer[d.vc.self, client]; IO.PutRope[d.vc.out, " killed.\n"]; END; SetThreadControlToRunning: PROC[d: MyViewerData] = BEGIN empty: CirioButtons.ButtonSet ฌ d.threadControlButtonSet ฌ CirioButtons.KillButtonSet[d.threadControlButtonSet, FALSE]; threadControlViewer: ViewerClasses.Viewer ฌ Containers.Create[ info: [parent: d.vc.self, border: FALSE, scrollable: FALSE, wx: 0, wy: d.threadControlY, ww: d.vc.self.cw, wh: d.threadControlH] ]; bs: CirioButtons.ButtonSet ฌ d.threadControlButtonSet ฌ CirioButtons.CreateButtonSet[threadControlViewer, d.vc, 0, 0, 0, d.lineH, 0]; Containers.ChildXBound[d.vc.self, threadControlViewer]; [] ฌ CirioButtons.InstallCommandButton[ bs: bs, name: "StopRemoteWorld", border: TRUE, clientData1: d, proc2: StopRemoteWorld]; END; StopRemoteWorld: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] = BEGIN d: MyViewerData ฌ NARROW[clientData1]; { ENABLE CCTypes.CCError => { IO.PutF1[d.vc.out, " CCTypes.CCError: %g (try again)\n", [rope[msg]]]; GOTO dead; }; IO.PutRope[d.vc.out, "Stopping remote world execution ..."]; BEGIN nThreads: CARD ฌ RemoteCirio.StopRemoteWorld[d.connection, d.vc.out]; d.threadsInfo ฌ NEW[ThreadsInfo[nThreads]]; FOR x: CARDINAL IN [0..d.threadsInfo.nThreads) DO d.threadsInfo[x] ฌ NEW[ThreadButtonInfoฌ[d, x, FALSE, NIL]]; ENDLOOP; Labels.Set[d.runningLabel, "Remote World Stopped"]; d.runningFlag ฌ FALSE; SetThreadControlToStopped[d]; InstallGeneralButtons[d]; IO.PutRope[d.vc.out, " stopped.\n"]; END; EXITS dead => {}; }; END; SetThreadControlToRunningDbx: PROC[d: MyViewerData] = BEGIN empty: CirioButtons.ButtonSet ฌ d.threadControlButtonSet ฌ CirioButtons.KillButtonSet[d.threadControlButtonSet, FALSE]; threadControlViewer: ViewerClasses.Viewer ฌ Containers.Create[ info: [parent: d.vc.self, border: FALSE, scrollable: FALSE, wx: 0, wy: d.threadControlY, ww: d.vc.self.cw, wh: d.threadControlH] ]; bs: CirioButtons.ButtonSet ฌ d.threadControlButtonSet ฌ CirioButtons.CreateButtonSet[threadControlViewer, d.vc, 0, 0, 0, d.lineH, 0]; Containers.ChildXBound[d.vc.self, threadControlViewer]; END; SetThreadControlToStopped: PROC[d: MyViewerData] = BEGIN empty: CirioButtons.ButtonSet ฌ d.threadControlButtonSet ฌ CirioButtons.KillButtonSet[d.threadControlButtonSet, FALSE]; threadControlViewer: ViewerClasses.Viewer ฌ Containers.Create[ info: [parent: d.vc.self, border: FALSE, scrollable: FALSE, wx: 0, wy: d.threadControlY, ww: d.vc.self.cw, wh: d.threadControlH] ]; bs: CirioButtons.ButtonSet ฌ d.threadControlButtonSet ฌ CirioButtons.CreateButtonSet[threadControlViewer, d.vc, 0, 0, 0, d.lineH, 0]; Containers.ChildXBound[d.vc.self, threadControlViewer]; [] ฌ CirioButtons.InstallCommandButton[ bs: bs, name: "ResumeRemoteWorld", border: TRUE, clientData1: d, proc2: ResumeRemoteWorld]; [] ฌ CirioButtons.InstallCommandButton[ bs: bs, name: "VP0", border: TRUE, clientData1: d, proc2: OneVP]; CirioButtons.NewLine[bs]; [] ฌ CirioButtons.InstallLabelButton[bs, "Add threads: "]; [] ฌ CirioButtons.InstallCommandButton[ bs: bs, name: "CallingDebugger", border: TRUE, clientData1: d, proc2: AddCallingDebuggerThreads]; [] ฌ CirioButtons.InstallCommandButton[ bs: bs, name: "Ready", border: TRUE, clientData1: d, proc2: AddReadyThreads]; [] ฌ CirioButtons.InstallCommandButton[ bs: bs, name: "All", border: TRUE, clientData1: d, proc2: AddAllThreads]; END; InstallThreadListButtons: PROC[d: MyViewerData] = { bs: CirioButtons.ButtonSet ฌ d.threadControlButtonSet; IF d.threadsInfo = NIL THEN RETURN; [] ฌ CirioButtons.InstallLabelButton[bs, " Listed threads: "]; [] ฌ CirioButtons.InstallCommandButton[ bs: bs, name: "*", border: TRUE, clientData1: d, choices: LIST[[$FullSummary], [$ShortSummary], [$FreezeThread], [$ProceedThread], [$AbortThread], [$KillThread]], proc2: ThreadListButtonProc]; [] ฌ CirioButtons.InstallCommandButton[ bs: bs, name: "Sum'ry", border: TRUE, clientData1: d, choices: LIST[[$FullSummary], [$ShortSummary]], proc2: ThreadListButtonProc]; [] ฌ CirioButtons.InstallCommandButton[ bs: bs, name: "Frz", border: TRUE, clientData1: d, choices: LIST[[$FreezeThread]], proc2: ThreadListButtonProc]; [] ฌ CirioButtons.InstallCommandButton[ bs: bs, name: "Prcd", border: TRUE, clientData1: d, choices: LIST[[$ProceedThread]], proc2: ThreadListButtonProc]; [] ฌ CirioButtons.InstallCommandButton[ bs: bs, name: "Abrt", border: TRUE, clientData1: d, choices: LIST[[$AbortThread]], proc2: ThreadListButtonProc]; [] ฌ CirioButtons.InstallCommandButton[ bs: bs, name: "Kill", border: TRUE, clientData1: d, choices: LIST[[$KillThread]], proc2: ThreadListButtonProc]; d.threadListControlButtonsInstalled ฌ TRUE; }; ResumeRemoteWorld: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] = { d: MyViewerData ฌ NARROW[clientData1]; { ENABLE CCTypes.CCError => { IO.PutF1[d.vc.out, " CCTypes.CCError: %g (probably worked)\n", [rope[msg]]]; GOTO dead; }; IF NOT d.runningFlag THEN { IO.PutRope[d.vc.out, "Resuming remote world execution ..."]; CloseThreadInner[d]; RemoveGeneralButtons[d]; RemoveThreadButtons[d]; SetThreadControlToRunning[d]; RemoteCirio.ResumeRemoteWorld[d.connection]; d.threadsInfo ฌ NIL; Labels.Set[d.runningLabel, "Remote World Running"]; d.runningFlag ฌ TRUE; ViewerOps.PaintViewer[d.vc.self, client]; IO.PutRope[d.vc.out, " resumed.\n"]; }; EXITS dead => {}; }; }; OneVP: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] = { d: MyViewerData ฌ NARROW[clientData1]; { ENABLE CCTypes.CCError => { IO.PutF1[d.vc.out, " CCTypes.CCError: %g (probably worked)\n", [rope[msg]]]; GOTO dead; }; IF NOT d.runningFlag THEN { IO.PutRope[d.vc.out, "Resuming remote world execution with only VP0 ..."]; CloseThreadInner[d]; RemoveGeneralButtons[d]; RemoveThreadButtons[d]; SetThreadControlToRunning[d]; RemoteCirio.ResumeRemoteWorldWithOnlyVP0[d.connection]; d.threadsInfo ฌ NIL; Labels.Set[d.runningLabel, "Remote World Running (VP0)"]; d.runningFlag ฌ TRUE; ViewerOps.PaintViewer[d.vc.self, client]; IO.PutRope[d.vc.out, " resumed with only VP0.\n"]; }; EXITS dead => {}; }; }; AddCallingDebuggerThreads: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] = BEGIN d: MyViewerData ฌ NARROW[clientData1]; IF NOT d.runningFlag THEN BEGIN IO.PutRope[d.vc.out, "Adding threads calling debugger ..."]; BEGIN someThreads: LIST OF CARD ฌ RemoteCirio.FindThreadsWithProperty[d.connection, [callingDebugger[]], d.vc.out]; RedoThreadButtons[d, someThreads]; IO.PutRope[d.vc.out, " added.\n"]; InstallThreadListButtons[d]; END; END; END; AddReadyThreads: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] = BEGIN d: MyViewerData ฌ NARROW[clientData1]; IF NOT d.runningFlag THEN BEGIN IO.PutRope[d.vc.out, "Adding ready threads (including running) ..."]; BEGIN someThreads: LIST OF CARD ฌ RemoteCirio.FindThreadsWithProperty[d.connection, [ready[]], d.vc.out]; RedoThreadButtons[d, someThreads]; IO.PutRope[d.vc.out, " added.\n"]; InstallThreadListButtons[d]; END; END; END; AddThreadsForContext1: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1: REF ANY] RETURNS[clientData2: REF ANY] = BEGIN rope: ROPE ฌ WindowSystemInterface.GetSelectionContents[]; IF rope = NIL THEN RETURN[NIL] ELSE RETURN[NEW[RopeHolder ฌ rope]]; END; RopeHolder: TYPE = ROPE; AddThreadsForContext2: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] = BEGIN d: MyViewerData ฌ NARROW[clientData1]; IF NOT d.runningFlag THEN BEGIN ropeHolder: REF RopeHolder ฌ NARROW[clientData2]; contextName: ROPE ฌ IF ropeHolder = NIL THEN NIL ELSE ropeHolderญ; IF Rope.Length[contextName] = 0 OR Rope.Find[contextName, "."] >= 0 OR Rope.Find[contextName, "/"] >= 0 THEN IO.PutF1[d.vc.out, "sorry, selection \"%g\" is not a valid context name\N", IO.rope[contextName]] ELSE BEGIN IO.PutF1[d.vc.out, "Adding threads for context %g ...", IO.rope[contextName]]; BEGIN someThreads: LIST OF CARD ฌ RemoteCirio.FindThreadsWithProperty[d.connection, [context[contextName]], d.vc.out]; RedoThreadButtons[d, someThreads]; IO.PutRope[d.vc.out, " added.\n"]; END; END; END; END; AddAllThreads: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] = BEGIN d: MyViewerData ฌ NARROW[clientData1]; IF NOT d.runningFlag THEN { IO.PutRope[d.vc.out, "Adding all threads ..."]; {someThreads: LIST OF CARD ฌ RemoteCirio.FindThreadsWithProperty[d.connection, [any[]], d.vc.out]; RedoThreadButtons[d, someThreads]; }; IO.PutRope[d.vc.out, " added.\n"]; InstallThreadListButtons[d]; }; END; RemoveThreadButtons: PROC[d: MyViewerData] = BEGIN d.threadButtonsButtonSet ฌ CirioButtons.KillButtonSet[d.threadButtonsButtonSet, FALSE]; END; RedoThreadButtons: PROC[d: MyViewerData, someThreads: LIST OF CARD] = BEGIN nNewButtons: CARD ฌ 0; empty: CirioButtons.ButtonSet ฌ d.threadButtonsButtonSet ฌ CirioButtons.KillButtonSet[d.threadButtonsButtonSet, FALSE]; threadButtonsViewer: ViewerClasses.Viewer ฌ Containers.Create[ info: [parent: d.vc.self, border: FALSE, scrollable: TRUE, wx: 0, wy: d.threadButtonsY, ww: d.vc.self.cw, wh: d.threadButtonsH] ]; sample1: CirioButtons.ButtonSize ฌ CirioButtons.GetButtonSize["9999: (10) (Handlee) (frozen) (BadProceedRequest)"]; bs: CirioButtons.ButtonSet ฌ d.threadButtonsButtonSet ฌ CirioButtons.CreateButtonSet[threadButtonsViewer, d.vc, 0, 0, 0, d.lineH-2, 0]; Containers.ChildXBound[d.vc.self, threadButtonsViewer]; FOR st: LIST OF CARD ฌ someThreads, st.rest WHILE st # NIL DO IF NOT d.threadsInfo[st.first].visible THEN nNewButtons ฌ nNewButtons + 1; d.threadsInfo[st.first].visible ฌ TRUE; ENDLOOP; FOR x: CARDINAL IN [0..d.threadsInfo.nThreads) DO IF d.threadsInfo[x].visible THEN BEGIN title: ROPE ฌ RemoteCirio.GetThreadTitleText[d.connection, x]; tbi: REF ThreadButtonInfo ฌ d.threadsInfo[x]; Button: PROC[name: ROPE, proc: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY], choices: CirioButtons.ChoiceList] = BEGIN [] ฌ CirioButtons.InstallCommandButton[bs: bs, name: name, border: TRUE, clientData1: tbi, choices: choices, proc2: proc] END; tbi.label ฌ CirioButtons.InstallLabelButton[bs, title]; CirioButtons.MoveToX[bs, sample1.w]; Button["*", ThreadButtProc, LIST[[$FullSummary], [$ShortSummary], [$ThreadDetails], [$FreezeThread], [$ProceedThread], [$AbortThread], [$KillThread], [$CallDbx]] ]; Button["Sum'ry", ThreadButtProc, LIST[[$FullSummary], [$ShortSummary]] ]; Button["Detailed", ThreadButtProc, LIST[[$ThreadDetails]] ]; Button["Frz", ThreadButtProc, LIST[[$FreezeThread]] ]; Button["Prcd", ThreadButtProc, LIST[[$ProceedThread]] ]; Button["Abrt", ThreadButtProc, LIST[[$AbortThread]] ]; Button["Kill", ThreadButtProc, LIST[[$KillThread]] ]; Button["Dbx", ThreadButtProc, LIST[[$CallDbx]] ]; Containers.ChildXBound[threadButtonsViewer, tbi.label]; CirioButtons.NewLine[bs]; END; ENDLOOP; END; ThreadButtProc: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] = BEGIN tbi: REF ThreadButtonInfo ฌ NARROW[clientData1]; d: MyViewerData ฌ tbi.d; SELECT key FROM $FullSummary, $ShortSummary => { tbi.d.stopFlagญ ฌ FALSE; RemoteCirio.ShowQuickSummary[tbi.d.connection, tbi.index, tbi.d.stopFlag, tbi.d.vc.out, key=$FullSummary]; }; $ThreadDetails => { IF NOT d.remoteWorldGone THEN SwitchToThread[d, tbi]; }; $FreezeThread => { newTitleText: ROPE; IO.PutF1[tbi.d.vc.out, "Freeze %g.\n", [cardinal[RemoteCirio.ThreadIDFromIndex[tbi.index, tbi.d.connection]]]]; newTitleText ฌ RemoteCirio.FreezeThread[tbi.d.connection, tbi.index, tbi.d.vc.out]; Labels.Set[tbi.label, newTitleText]; }; $ProceedThread => { newTitleText: ROPE; IO.PutF1[tbi.d.vc.out, "Proceed %g.\n", [cardinal[RemoteCirio.ThreadIDFromIndex[tbi.index, tbi.d.connection]]]]; newTitleText ฌ RemoteCirio.ProceedThread[tbi.d.connection, tbi.index, tbi.d.vc.out]; Labels.Set[tbi.label, newTitleText]; }; $AbortThread => { newTitleText: ROPE; IO.PutF1[tbi.d.vc.out, "Abort %g.\n", [cardinal[RemoteCirio.ThreadIDFromIndex[tbi.index, tbi.d.connection]]]]; newTitleText ฌ RemoteCirio.AbortThread[tbi.d.connection, tbi.index, tbi.d.vc.out]; Labels.Set[tbi.label, newTitleText]; }; $KillThread => { newTitleText: ROPE; IO.PutF1[tbi.d.vc.out, "Kill %g.\n", [cardinal[RemoteCirio.ThreadIDFromIndex[tbi.index, tbi.d.connection]]]]; newTitleText ฌ RemoteCirio.KillThread[tbi.d.connection, tbi.index, tbi.d.vc.out]; Labels.Set[tbi.label, newTitleText]; }; $CallDbx => IF NOT d.remoteWorldGone AND NOT d.runningFlag THEN BEGIN newNThreads: CARD; IO.PutRope[d.vc.out, "Calling DBX.\n"]; CloseThreadInner[d]; RemoveThreadButtons[d]; SetThreadControlToRunningDbx[d]; -- this is different d.threadsInfo ฌ NIL; Labels.Set[d.runningLabel, " Remote World in Dbx"]; d.dbxFlag ฌ TRUE; IO.PutRope[d.vc.out, " (remote world under Dbx)\n"]; newNThreads ฌ RemoteCirio.DbxExamineThread[tbi.d.connection, tbi.index, tbi.d.vc.out]; d.threadsInfo ฌ NEW[ThreadsInfo[newNThreads]]; FOR x: CARDINAL IN [0..d.threadsInfo.nThreads) DO d.threadsInfo[x] ฌ NEW[ThreadButtonInfoฌ[d, x, FALSE, NIL]]; ENDLOOP; Labels.Set[d.runningLabel, " Remote World Stopped"]; d.runningFlag ฌ FALSE; SetThreadControlToStopped[d]; RedoThreadButtons[d, NIL]; IO.PutRope[d.vc.out, " (Dbx activity stopped)\n"] END; ENDCASE => IO.PutRope[d.vc.out, "\n!Unrecognized action (this can't happen)!\n"]; END; ThreadListButtonProc: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] = { d: MyViewerData ฌ NARROW[clientData1]; IF d.threadsInfo #NIL THEN FOR threadIndex: CARDINAL IN [0..d.threadsInfo.nThreads) DO IF d.threadsInfo[threadIndex].visible THEN ThreadButtProc[button, vc, key, d.threadsInfo[threadIndex], clientData2]; ENDLOOP; }; InstallGeneralButtons: PROC[d: MyViewerData] = BEGIN generalButtonsViewer: ViewerClasses.Viewer ฌ Containers.Create[ info: [parent: d.vc.self, border: FALSE, scrollable: FALSE, wx: 0, wy: d.generalButtonsY, ww: d.vc.self.cw, wh: d.generalButtonsH] ]; bs: CirioButtons.ButtonSet ฌ d.generalButtonsButtonSet ฌ CirioButtons.CreateButtonSet[generalButtonsViewer, d.vc, 0, 0, 0, d.lineH, 0]; Containers.ChildXBound[d.vc.self, generalButtonsViewer]; [] ฌ CirioButtons.InstallCommandButton[ bs: bs, name: "SetBreak", clientData1: d, choices: LIST[[$SetBreakAtPosition, "set breakpoint at selected source position"], [$SetBreakAtAddr, "set breakpoint at selected address"]], proc1: SetBreakAction1, proc2: SetBreakAction2]; [] ฌ CirioButtons.InstallCommandButton[ bs: bs, name: "ListBreaks", clientData1: d, proc2: ListBreaksAction]; [] ฌ CirioButtons.InstallCommandButton[ bs: bs, name: "ClearBreak(s)", clientData1: d, choices: LIST[[$ThisOne, "clear the active break"], [$All, "clear all breaks"], [$All, "clear all breaks"]], proc2: ClearBreakAction]; [] ฌ CirioButtons.InstallCommandButton[ bs: bs, name: "AddDir", clientData1: d, proc1: AddDirAction1, proc2: AddDirAction2]; [] ฌ CirioButtons.InstallCommandButton[ bs: bs, name: "ListDir", clientData1: d, proc2: ListDirAction2]; [] ฌ CirioButtons.InstallCommandButton[ bs: bs, name: "Stop", clientData1: d, proc1: StopAction1, proc2: StopAction2]; [] ฌ CirioButtons.InstallCommandButton[ bs: bs, name: "Disassemble", clientData1: d, proc1: DisassembleAction1, proc2: DisassembleAction2]; [] ฌ CirioButtons.InstallCommandButton[ bs: bs, name: "BreakMode", border: TRUE, clientData1: d, proc2: BreakModeAction]; d.stopAllLabel ฌ CirioButtons.InstallLabelButton[bs, "StopAThread "]; END; SetBreakAction1: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1: REF ANY] RETURNS [clientData2: REF ANY] ~ { SELECT key FROM $SetBreakAtPosition => { pos: SourceFileOps.Position ~ SourceFileOps.GetSelection[].pos; RETURN [NEW[SourceFileOps.Position ฌ pos]]}; $SetBreakAtAddr => { addrope: ROPE ~ WindowSystemInterface.GetSelectionContents[]; RETURN[addrope]}; ENDCASE => ERROR}; SetBreakAction2: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] = { d: MyViewerData ~ NARROW[clientData1]; SELECT key FROM $SetBreakAtPosition => { pos: REF SourceFileOps.Position ~ NARROW[clientData2]; corresp: SourceFileOps.Position ฌ posญ; IO.PutF1[d.vc.out, "Setting break at %g ... ", [rope[SourceFileOps.FormatPosition[posญ]]] ]; corresp ฌ StackCirio.SetBreakPointAtPosition[d.dummyStack, posญ, d.vc.out, d.stopAllFlag]; IF corresp#SourceFileOps.noPosition THEN SourceFileOps.OpenSource["Break set at ", corresp, d.vc.out]; }; $SetBreakAtAddr => { addrope: ROPE ~ NARROW[clientData2]; addr: CARD; TRUSTED {addr ฌ DisassembleSPARC.CardFromRope[addrope !Convert.Error => { d.vc.out.PutF["Syntax error (VAL[%g]) at %g --- selection should be an unsigned number in C or Mesa syntax", [integer[reason.ORD]], [integer[index]] ]; GOTO Bail}]}; d.vc.out.PutF1["Setting break at 0x%08x ...", [cardinal[addr]] ]; StackCirio.SetBreakPointAtAddress[d.dummyStack, addr, d.vc.out, d.stopAllFlag]; EXITS Bail => NULL}; ENDCASE => ERROR; IO.PutRope[d.vc.out, " done.\n"]; }; ListBreaksAction: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] = BEGIN d: MyViewerData ฌ NARROW[clientData1]; IO.PutRope[d.vc.out, "Listing breaks ... "]; StackCirio.ListBreakPoints[d.dummyStack, d.vc.out]; IO.PutRope[d.vc.out, " done.\n"]; END; ClearBreakAction: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] = BEGIN d: MyViewerData ฌ NARROW[clientData1]; clearAll: BOOLEAN ฌ key = $All; IF clearAll THEN BEGIN IO.PutRope[d.vc.out, "Clearing all breaks ... "]; StackCirio.ClearAllBreakPoints[d.dummyStack, d.vc.out]; END ELSE IF d.currentStack # NIL THEN BEGIN IO.PutRope[d.vc.out, "Clearing break ... "]; StackCirio.ClearBreakPoint[d.currentStack, d.vc.out]; END ELSE IO.PutRope[d.vc.out, "can not clear break without a current frame ... "]; IO.PutRope[d.vc.out, " done.\n"]; END; AddDirAction1: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1: REF ANY] RETURNS[clientData2: REF ANY] = BEGIN rope: ROPE ฌ WindowSystemInterface.GetSelectionContents[]; IF rope = NIL THEN RETURN[NIL] ELSE RETURN[NEW[RopeHolder ฌ rope]]; END; AddDirAction2: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] = BEGIN d: MyViewerData ฌ NARROW[clientData1]; ropeHolder: REF RopeHolder ฌ NARROW[clientData2]; dirPath: ROPE ฌ IF ropeHolder = NIL THEN NIL ELSE ropeHolderญ; IO.PutRope[d.vc.out, "Adding search directory ... "]; RemoteCirio.AddSearchDirectory[d.connection, dirPath, d.vc.out]; IO.PutRope[d.vc.out, "Added.\n"]; END; ListDirAction2: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] = BEGIN d: MyViewerData ฌ NARROW[clientData1]; IO.PutRope[d.vc.out, "Listing search directory(s) ... "]; RemoteCirio.ListSearchDirectory[d.connection, d.vc.out]; IO.PutRope[d.vc.out, "Done.\n"]; END; StopAction1: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1: REF ANY] RETURNS[clientData2: REF ANY] = BEGIN d: MyViewerData ฌ NARROW[clientData1]; d.stopFlagญ ฌ TRUE; RETURN[NIL] END; StopAction2: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] = BEGIN END; DisassembleAction1: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1: REF ANY] RETURNS[clientData2: REF ANY] = { addrope: ROPE ~ WindowSystemInterface.GetSelectionContents[]; RETURN[addrope]; }; DisassembleAction2: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] = { d: MyViewerData ~ NARROW[clientData1]; addrRope: ROPE ~ NARROW[clientData2]; IO.PutRope[d.vc.out, "Disassemble ... "]; d.stopFlagญ ฌ FALSE; StackCirio.Disassemble[d.dummyStack, addrRope, d.vc.out, d.stopFlag]; IO.PutRope[d.vc.out, "done.\n"]; }; BreakModeAction: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] = BEGIN d: MyViewerData ~ NARROW[clientData1]; d.stopAllFlag ฌ ~ d.stopAllFlag; IF d.stopAllFlag THEN {Labels.Set[d.stopAllLabel, "StopAllThreads"];} ELSE {Labels.Set[d.stopAllLabel, "StopAThread "];}; END; RemoveGeneralButtons: PROC[d: MyViewerData] = BEGIN d.generalButtonsButtonSet ฌ CirioButtons.KillButtonSet[d.generalButtonsButtonSet, FALSE]; END; SwitchToThread: PROC[d: MyViewerData, tbi: REF ThreadButtonInfo] = BEGIN IO.PutRope[d.vc.out, "switching threads ... "]; RemoveStackDebugButtons[d]; d.activeThread ฌ tbi; d.activeThreadRemoteIndex ฌ RemoteCirio.FocusOnThread[tbi.d.connection, tbi.index, tbi.d.vc.out]; d.currentStack ฌ RemoteCirio.GetStackForCurrentThread[tbi.d.connection, tbi.d.vc.out]; InstallStackDebugButtons[d]; IO.PutRope[d.vc.out, "switched\N"]; END; InstallStackDebugButtons: PROC[d: MyViewerData] = BEGIN stackDebugButtonsViewer: ViewerClasses.Viewer ฌ Containers.Create[ info: [parent: d.vc.self, border: FALSE, scrollable: FALSE, wx: 0, wy: d.stackButtonsY, ww: d.vc.self.cw, wh: d.stackButtonsH] ]; bs: CirioButtons.ButtonSet ฌ d.stackButtonsButtonSet ฌ CirioButtons.CreateButtonSet[stackDebugButtonsViewer, d.vc, 0, 0, 0, d.lineH, 0]; tbi: REF ThreadButtonInfo ฌ d.activeThread; frameIndex: CARD ฌ StackCirio.ResetStack[d.currentStack, tbi.d.vc.out]; threadText: ROPE ฌ Rope.Concat[Convert.RopeFromCard[d.activeThreadRemoteIndex], "."]; Containers.ChildXBound[d.vc.self, stackDebugButtonsViewer]; d.frameLabel ฌ CirioButtons.InstallLabelButton[bs, Rope.Cat["frame: ", threadText, Convert.RopeFromCard[frameIndex], " "]]; CirioButtons.InstallWalkStackButton[bs, d.currentStack, threadText, d.frameLabel]; CirioButtons.InstallShowFrameButton[bs, d.currentStack]; CirioButtons.InstallSourcePositionButton[bs, d.currentStack]; CirioButtons.InstallSourceLanguageButton[bs, d.currentStack]; END; RemoveStackDebugButtons: PROC[d: MyViewerData] = BEGIN d.stackButtonsButtonSet ฌ CirioButtons.KillButtonSet[d.stackButtonsButtonSet, FALSE]; d.frameLabel ฌ NIL; END; CloseThreadInner: PROC[d: MyViewerData] = {RemoveStackDebugButtons[d]; d.currentStack ฌ NIL}; ShutDown: PROC[clientData: REF ANY, reports: IO.STREAM] = BEGIN d: MyViewerData ฌ NARROW[clientData]; IF d.connection # NIL THEN RemoteCirio.CloseConnection[d.connection, reports]; d.connection ฌ NIL; END; Commander.Register["CirioRemote", Driver, "Connect to a world.\n Usage: CirioRemote [ []]"]; END.. พ RemoteDriver3.mesa Copyright ำ 1990, 1991, 1992, 1993 by Xerox Corporation. All rights reserved. Sturgis, April 3, 1990 11:50 am PDT Linda Howe, January 8, 1990 1:19:50 pm PST Last tweaked by Mike Spreitzer on July 24, 1992 5:15 pm PDT Laurie Horton, September 17, 1992 8:54 am PDT Udagawa, February 14, 1991 4:23 pm PST Philip James, March 6, 1992 10:25 am PST Willie-s, March 2, 1993 4:27 pm PST Katsuyuki Komatsu January 23, 1993 4:36 pm PST Viewer related code Stolen from RemoteDriver2.mesa findButtonsButtonSet: CirioButtons.ButtonSet, Get user supplied and default working directories Try to prevent connecting to ourselves. Rope returned by SystemNames.MachineName if yp isn't running. open a block to so that unwind catches can close the connection Cleanup before exiting Interpret Find InstallFindButtons: PROC[d: MyViewerData] = BEGIN findButtonSet: CirioButtons.ButtonSet _ d.findButtonsButtonSet _ CirioButtons.CreateButtonSet[d.vc.self, d.vc, 0, d.findButtonsH, 0, d.lineH, 0]; [] _ CirioButtons.InstallCommandButton[bs: findButtonSet, name: "Find", clientData1: d.vc, choices: LIST[[$Forward], [$Anywhere], [$Backward]], proc2: FindAction]; [] _ CirioButtons.InstallCommandButton[bs: findButtonSet, name: "Word", clientData1: d.vc, choices: LIST[[$Forward], [$Anywhere], [$Backward]], proc2: FindAction]; END; FindAction: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] RETURNS[] ~ { v: ViewerClasses.Viewer _ NARROW[clientData1]; dirAtom: ATOM _ NARROW[key]; IF ~TiogaOps.FindText[viewer: v, rope: NIL, whichDir: DirFromAtom[dirAtom], which: primary, case: TRUE] THEN do something? v _ NIL; }; WordAction: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] ~ { v: ViewerClasses.Viewer _ NARROW[clientData1]; dirAtom: ATOM _ NARROW[key]; IF ~TiogaOps.FindWord[viewer: v, rope: NIL, whichDir: DirFromAtom[dirAtom], which: primary, case: TRUE] THEN do something? v _ NIL; }; DirFromAtom: PROC[a: ATOM] RETURNS [dir: TiogaOps.SearchDir _ forwards] ~ { SELECT a FROM $Forward => dir _ forwards; $Backward => dir _ backwards; $Anywhere => dir _ anywhere; ENDCASE => ERROR; }; Rules because we throw this away, no one will do a KillButtonSet, hence it is alright to use d.vc.self as the container. world control [] _ CirioButtons.InstallCommandButton[ bs: bs, name: "ForkWSDaemon", border: TRUE, guarded: FALSE, clientData1: d, proc2: BreakCheckDaemonInitialize]; ThreadControl [] _ CirioButtons.InstallCommandButton[ bs: bs, name: "for context", border: TRUE, clientData1: d, proc1: AddThreadsForContext1, proc2: AddThreadsForContext2]; Thread Buttons first we have to do more or less what we would do if we were restarting the remote world now we do it now we put the world back. Unfortunately, we don't reconstruct the thread info (we shall code that later). GeneralButtons just a no op to keep CirioButtons happy. Stack debug buttons misc Main code ส$ฎ–"cedarcode" style•NewlineDelimiter ™codešœ™Kšœ ฯeœC™NKšœ#™#K™*K™;K™-K™&K™(K™#K™.—K˜šฯk ˜ Kšœžœ˜+Kšœžœ˜$Kšœ žœร˜ีKšœ žœ˜"Kšœ žœ˜'Kšœ žœ˜ Kšœ žœ˜&Kšœžœ2˜?Kšœ˜Kšœ žœ˜)Kšžœžœžœ˜-Kšœžœ˜Kšœ žœ˜*Kšœžœ ˜Kšœ žœล˜ึKšœžœ#žœ˜3KšœžœB˜UKšœ žœ˜Kšœ žœช˜บKšœ žœ˜'Kšœ žœ ˜.Kšœžœ˜2Kšœžœ˜)Kšœ žœ˜*K˜—šฯn œžœž˜Kšžœžœ˜Kšžœlžœ’˜‡Kšœž˜K˜Kšžœžœžœ˜Kšžœžœ˜&Kšžœžœ&žœžœ˜NK˜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šœ#žœžœ˜0K˜Kšœžœ˜K˜Kšœžœ˜Kšœžœ˜Kšœ/˜/K˜Kšœžœžœ˜)Kšœžœ˜K˜K˜Kšœžœ˜K˜Kšœ žœžœžœ˜Kšœžœ˜Kšœžœ˜Kšœ0˜0K˜Kšœžœ˜Kšœžœ˜Kšœ.˜.K˜!K˜Kšœžœ˜K˜Kšœžœ˜Kšœžœ˜K˜!K˜!Kšœ-™-K˜Kšœžœ˜K˜Kšœ žœ˜K˜K˜Kšœ˜—K˜Kš œ žœžœžœ žœžœžœ˜PK˜Kš œžœžœžœ žœ˜mK˜K˜—šœ žœžœ˜Kšœžœžœ˜Kšœ žœ˜Kšœžœžœ˜Kšœžœž˜K˜K˜—šœ˜K˜—š Ÿ œžœžœžœžœžœž˜5K˜K˜—šŸœ˜!Kšœžœ˜(Kšœžœžœžœ˜Kšœ žœ˜ Kšœ žœ˜Kšœžœ˜Kšœ žœ˜Kš œžœžœžœžœ˜Kš œ žœžœžœžœ˜Kš œžœžœžœžœ&˜?K˜0šœžœ˜ Kšœžœ˜šœ˜Kšœžœžœ˜Kšžœe˜gK˜šžœ žœžœžœžœ žœžœ˜JKšœ/žœ˜6Kšžœ)˜+Kšžœ˜K˜—Kšžœd˜fKšžœ˜ K˜—K˜K˜Kšžœ žœžœ˜K˜KšœVžœ˜rKš œ žœ žœžœžœ(˜XK˜šž˜Kšœ žœZ˜iKšœžœ˜—K˜—K˜K™1Kš œžœ žœžœžœ˜4šžœ žœžœ˜š žœ žœžœžœžœ žœž˜FK˜—Kšžœ˜K˜Kšœ˜—šžœ˜K˜ K˜K˜—K™'šœ˜Kšœžœ˜#K˜Kšœ=™=Kšœžœ˜,K˜—šžœžœžœ˜šœ"˜"Kšœ/˜/šžœ/žœ˜7Kšœ˜Kšžœg˜iK˜—Kšœfžœ˜‚Kšœžœ˜Kšœ˜K˜——šžœžœ1žœ%žœ˜‚Kšžœ˜’Kšžœ˜K˜—K˜K˜K˜3K˜K˜K˜K˜K˜3K˜K˜K˜-K˜K˜K˜K˜K˜/K˜K˜K˜K˜K˜8K˜K˜K˜-K˜K˜9K˜K˜K˜+K˜K˜K˜K˜ฌK˜K˜PK˜šžœžœžœ˜Kšžœžœ&ฯc˜RKšžœM˜S—K˜™?Kšž˜Kšžœžœ˜(K˜Kšœ6˜6K˜Kšœ<˜Kšœ"žœžœI˜ƒ—˜…K˜—Kšœ7˜7K˜˜'Kšœ˜Kšœ!žœ˜&Kšœ˜Kšœ˜—K˜Kšžœ˜—K˜šŸœžœ^žœžœ˜}Kšž˜Kšœžœ˜&˜šžœ˜KšžœD˜FKšžœ˜ K˜—Kšžœ:˜Kšœ"žœžœI˜ƒ—˜…K˜—Kšœ7˜7Kšžœ˜—K˜šŸœžœ˜2Kšž˜Kšœpžœ˜w˜>Kšœ"žœžœI˜ƒ—K˜…Kšœ7˜7K˜˜'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šŸœžœ˜3˜K˜6Kšžœžœžœžœ˜#K˜K˜>˜'Kšœ˜Kšœžœ˜Kšœ˜Kšœ žœd˜qKšœ˜—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šžœJ˜LKšžœ˜ K˜—šžœžœžœ˜Kšžœ:˜Kšœ"žœžœI˜‚—K˜sK˜‡Kšœ7˜7K˜K˜š žœžœžœžœžœžœž˜=Kšžœžœ!žœ˜JKšœ"žœ˜'Kšžœ˜—K˜K˜šžœžœžœž˜1šžœž˜ Kšž˜Kšœžœ3˜>Kšœžœ%˜-K˜š Ÿœžœžœžœ^žœžœ&˜ฎKšž˜KšœCžœ2˜yKšžœ˜K˜—K˜7Kšœ$˜$Kšœžœ„˜คKšœ!žœ$˜IKšœ#žœ˜K˜Kšžœ3˜5Kšœ@˜@Kšžœ˜!Kšžœ˜K˜—šŸœžœ^žœžœ˜|Kšž˜Kšœžœ˜&K˜Kšžœ7˜9Kšœ8˜8Kšžœ˜ Kšžœ˜—K˜šŸ œžœQžœžœžœžœžœ˜ŠKšž˜Kšœžœ˜&Kšœžœ˜Kšžœžœ˜ Kšžœ˜—K˜šŸ œžœ^žœžœ˜yKšž˜K™(Kšžœ˜K˜—šŸœžœQžœžœžœžœžœ˜“Kšœ žœ0˜=Kšžœ ˜Kšœ˜K˜—šŸœžœ^žœžœ˜‚Kšœžœ˜&Kšœ žœžœ˜%Kšžœ'˜)Kšœžœ˜KšœE˜EKšžœ˜ Kšœ˜K˜—šŸœžœ^žœžœ˜}šž˜Kšœžœ˜&K˜ Kšžœžœ0˜EKšžœ0˜4—Kšžœ˜—K˜šŸœžœ˜-Kšž˜KšœRžœ˜YKšžœ˜K˜——™K˜šŸœžœžœ˜BKšž˜Kšžœ-˜/K˜K˜K˜aK˜VK˜Kšžœ!˜#Kšžœ˜K˜—šŸœžœ˜1Kšž˜˜BKšœ"žœžœG˜—K˜ˆKšœžœ#˜+Kšœ žœ7˜GKšœ žœE˜UKšœ;˜;K˜|KšœR˜RKšœ8˜8K˜=Kšœ=˜=Kšžœ˜—K˜K˜šŸœžœ˜0Kšž˜KšœNžœ˜UKšœžœ˜Kšžœ˜—K˜šŸœžœ˜)Kšœ.žœ˜3K˜——˜K˜—™K˜K˜š Ÿœžœ žœžœ žœžœ˜9Kšž˜Kšœžœ ˜%Kšžœžœžœ4˜NKšœžœ˜Kšžœ˜——K™K˜K˜K˜˜K˜—K™K™ ˜Kšœ˜—K˜K˜K™Kšžœ˜K˜——…—Šjบึ