<> <> <> DIRECTORY AMModel USING [ParentSection, Section, SectionClass, SectionName, SectionSource, Source, SourceObj], AMModelLocation USING [CodeLocation, EntryLocations], AMViewerOps USING [ReportProc, SectionFromSelection, ViewerFromSection], BackStop USING [Call], BasicTime USING [GetClockPulses, Pulses, PulsesToMicroseconds], Commander USING [CommandProc, Register], FastBreak USING [ClearFastBreak, FastBreakId, SetFastBreak], IO USING [PutFR], Menus USING [AppendMenuEntry, CreateEntry, CreateMenu, Menu, MenuProc], MessageWindow USING [Append], NumberLabels USING [CreateNumber, NumberLabel, NumberLabelUpdate], PrincOps USING [BytePC, FrameCodeBase], Process USING [Detach, Milliseconds, MsecToTicks, SetTimeout], Rope USING [Cat, ROPE], ViewerOps USING [ChangeColumn, ComputeColumn, PaintViewer, SetMenu, SetOpenHeight], VTables USING [Create, ExchangeRows, GetTableEntry, Install, NullBorder, SetRowsAndColumns, SetTableEntry, VTable]; Celtics: CEDAR MONITOR IMPORTS AMModel, AMModelLocation, AMViewerOps, BackStop, BasicTime, Commander, FastBreak, IO, Menus, MessageWindow, NumberLabels, Process, Rope, ViewerOps, VTables = BEGIN <> BytePC: TYPE = PrincOps.BytePC; CARD: TYPE = LONG CARDINAL; CodeLocation: TYPE = AMModelLocation.CodeLocation; CodeLocationList: TYPE = LIST OF CodeLocation; FrameCodeBase: TYPE = PrincOps.FrameCodeBase; ROPE: TYPE = Rope.ROPE; Section: TYPE = AMModel.Section; Source: TYPE = AMModel.Source; SourceObj: TYPE = AMModel.SourceObj; BaseData: TYPE = REF BaseDataRep; BaseDataRep: TYPE = RECORD [ vtab: VTables.VTable _ NIL, head: EachData _ NIL, changeCond: CONDITION, timeCond: CONDITION, locked: BOOL _ FALSE, rows: NAT _ 0, cols: NAT _ limitCol]; EachData: TYPE = REF EachDataRep; EachDataRep: TYPE = RECORD [ next: EachData _ NIL, isTotal: BOOL _ FALSE, lastCount: INT _ 0, -- last count displayed id: FastBreak.FastBreakId _ NIL]; setCol: NAT = 0; clearCol: NAT = 1; countCol: NAT = 2; codeCol: NAT = 3; pcCol: NAT = 4; posCol: NAT = 5; nameCol: NAT = 6; limitCol: NAT = 7; UpdateDisplayProcess: PROC = TRUSTED { vtab: VTables.VTable _ VTables.Create[rows: 1, columns: limitCol, name: "Celtics", x: 0, y: 2]; data: BaseData _ NEW[BaseDataRep]; pulses: BasicTime.Pulses _ BasicTime.GetClockPulses[]; menu: Menus.Menu _ Menus.CreateMenu[]; inner: PROC [data: BaseData] = TRUSTED { newPulses: BasicTime.Pulses _ BasicTime.GetClockPulses[]; inverseSecs: REAL; deltaMicros: CARD _ BasicTime.PulsesToMicroseconds[newPulses] - BasicTime.PulsesToMicroseconds[pulses]; each: EachData _ data.head; lag: EachData _ NIL; index: NAT _ 1; changed: BOOL _ FALSE; newRows: NAT _ data.rows; subTotal, grandTotal: INT _ 0; IF deltaMicros < 100 THEN RETURN; inverseSecs _ 1E6 / deltaMicros; pulses _ newPulses; WHILE NOT vtab.destroyed AND each # NIL DO id: FastBreak.FastBreakId _ each.id; next: EachData _ each.next; SELECT TRUE FROM each.isTotal => { <> nl: NumberLabels.NumberLabel _ VTables.GetTableEntry[vtab, index, countCol]; current: INT _ subTotal; last: INT _ each.lastCount; index _ index + 1; lag _ each; IF nl # NIL AND current # last THEN { <> each.lastCount _ current; NumberLabels.NumberLabelUpdate[nl, each.lastCount]; }; subTotal _ 0; }; id = NIL => { <> changed _ TRUE; FOR i: NAT IN [index+1..data.rows) DO VTables.ExchangeRows[vtab, i, i-1]; ENDLOOP; IF lag = NIL THEN data.head _ next ELSE lag.next _ next; }; ENDCASE => { <> nl: NumberLabels.NumberLabel _ VTables.GetTableEntry[vtab, index, countCol]; current: INT _ id^; last: INT _ each.lastCount; index _ index + 1; lag _ each; subTotal _ subTotal + current; grandTotal _ grandTotal + current; IF nl # NIL AND current # last THEN { <> each.lastCount _ current; NumberLabels.NumberLabelUpdate[nl, each.lastCount]; }; }; each _ next; ENDLOOP; IF NOT vtab.parent.iconic THEN NumberLabels.NumberLabelUpdate[VTables.GetTableEntry[vtab, 0, countCol], grandTotal]; IF changed THEN InstallNewRows[data, index]; }; data.vtab _ vtab; Menus.AppendMenuEntry[menu, Menus.CreateEntry[ name: "Set", proc: SetFastBreak, clientData: data]]; Menus.AppendMenuEntry[menu, Menus.CreateEntry[ name: "Clear *", proc: ClearAll, clientData: data]]; Menus.AppendMenuEntry[menu, Menus.CreateEntry[ name: "Reset *", proc: ResetAllCounts, clientData: data]]; Menus.AppendMenuEntry[menu, Menus.CreateEntry[ name: "AddSubTotal", proc: AddSubTotal, clientData: data]]; VTables.SetTableEntry[ table: vtab, row: 0, column: countCol, flavor: $Viewer, clientData: NumberLabels.CreateNumber[info: [parent: vtab], chars: 9, paint: FALSE], useMaxSize: TRUE]; ViewerOps.ChangeColumn[vtab.parent, left]; ViewerOps.SetMenu[vtab.parent, menu, FALSE]; InstallNewRows[data, 1]; SetPause[data]; UNTIL WaitForChange[data] DO ENABLE ABORTED => EXIT; DoUnderLock[data, inner]; ENDLOOP; DoUnderLock[data, innerClearAll]; InstallNewRows[data, 0]; }; AddSubTotal: Menus.MenuProc = TRUSTED { <> <> DoUnderLock[clientData, innerAddSubTotal]; }; innerAddSubTotal: PROC [data: BaseData] = { vtab: VTables.VTable = data.vtab; eachData: EachData _ NEW[EachDataRep]; row: NAT = data.rows; eachData.isTotal _ TRUE; IF data.head = NIL THEN data.head _ eachData ELSE FOR each: EachData _ data.head, each.next DO IF each.next = NIL THEN {each.next _ eachData; EXIT}; ENDLOOP; InstallNewRows[data, row + 1]; VTables.SetTableEntry[ table: vtab, row: row, column: clearCol, name: "clear", proc: ClearBreak, clientData: eachData, useMaxSize: TRUE]; VTables.SetTableEntry[ table: vtab, row: row, column: countCol, flavor: $Viewer, clientData: NumberLabels.CreateNumber[info: [parent: vtab], chars: 9, paint: FALSE], useMaxSize: TRUE]; VTables.SetTableEntry[ table: vtab, row: row, column: nameCol, flavor: $Text, name: "subTotal", proc: NIL, clientData: eachData, useMaxSize: TRUE]; VTables.Install[vtab]; }; ClarkKent: AMViewerOps.ReportProc = { <<[msg: ROPE, severity: Severity]>> MessageWindow.Append[msg, TRUE]; }; SetFastBreak: Menus.MenuProc = { <> <> DoUnderLock[clientData, innerSetFastBreak]; }; innerSetFastBreak: PROC [data: BaseData] = { stage: ROPE _ "Can't do it, "; inner: PROC = TRUSTED { section: Section _ NIL; source: Source _ NIL; locationList: CodeLocationList _ NIL; vtab: VTables.VTable = data.vtab; row: NAT _ data.rows; pos: INT; parent: Section; parentName: ROPE; section _ AMViewerOps.SectionFromSelection[].section; parent _ section; IF AMModel.SectionClass[section] = statement THEN parent _ AMModel.ParentSection[section]; parentName _ AMModel.SectionName[parent]; IF AMModel.SectionClass[parent] = proc THEN { <> DO parent _ AMModel.ParentSection[parent]; IF AMModel.SectionClass[parent] # proc THEN EXIT; ENDLOOP; parentName _ Rope.Cat[AMModel.SectionName[parent], ".", parentName]; }; source _ AMModel.SectionSource[section]; WITH source SELECT FROM entire: REF SourceObj[entire] => pos _ -1; field: REF SourceObj[field] => { pos _ field.firstCharIndex; [] _ AMViewerOps.ViewerFromSection[section, ClarkKent]; }; ENDCASE; locationList _ AMModelLocation.EntryLocations[section].list; IF locationList = NIL THEN { MessageWindow.Append["No such locations found!", TRUE]; RETURN; }; FOR locList: CodeLocationList _ locationList, locList.rest UNTIL locList = NIL DO loc: CodeLocation = locList.first; code: FrameCodeBase _ loc.codeBase; pc: BytePC = loc.pc; eachData: EachData; code.out _ FALSE; -- Because nobody expects the Spanish Inquisition! eachData _ NEW[EachDataRep _ [id: FastBreak.SetFastBreak[code.longbase, pc]]]; IF data.head = NIL THEN data.head _ eachData ELSE FOR each: EachData _ data.head, each.next DO IF each.next = NIL THEN {each.next _ eachData; EXIT}; ENDLOOP; MessageWindow.Append["Counting break set in ", TRUE]; MessageWindow.Append[parentName]; InstallNewRows[data, row + 1]; VTables.SetTableEntry[ table: vtab, row: row, column: setCol, name: "reset", proc: ResetCount, clientData: eachData, useMaxSize: TRUE]; VTables.SetTableEntry[ table: vtab, row: row, column: clearCol, name: "clear", proc: ClearBreak, clientData: eachData, useMaxSize: TRUE]; VTables.SetTableEntry[ table: vtab, row: row, column: countCol, flavor: $Viewer, clientData: NumberLabels.CreateNumber[info: [parent: vtab], chars: 9, paint: FALSE], useMaxSize: TRUE]; VTables.SetTableEntry[ table: vtab, row: row, column: codeCol, flavor: $Text, name: IO.PutFR["%bB", [cardinal[LOOPHOLE[code]]]], useMaxSize: TRUE]; VTables.SetTableEntry[ table: vtab, row: row, column: pcCol, flavor: $Text, name: IO.PutFR["%bB", [cardinal[pc]]], useMaxSize: TRUE]; VTables.SetTableEntry[ table: vtab, row: row, column: posCol, flavor: $Text, name: IO.PutFR["%d", [integer[pos]]], useMaxSize: TRUE]; VTables.SetTableEntry[ table: vtab, row: row, column: nameCol, flavor: $Text, name: parentName, useMaxSize: TRUE]; row _ row + 1; ENDLOOP; VTables.Install[vtab]; }; msg: ROPE _ BackStop.Call[inner]; IF msg # NIL THEN { MessageWindow.Append[stage, TRUE]; MessageWindow.Append[msg]; MessageWindow.Append["."]; }; }; ClearAll: Menus.MenuProc = { <> <> DoUnderLock[clientData, innerClearAll]; }; innerClearAll: PROC [data: BaseData] = { vtab: VTables.VTable = data.vtab; FOR each: EachData _ data.head, each.next WHILE each # NIL DO IF each.id # NIL THEN TRUSTED { [] _ FastBreak.ClearFastBreak[each.id]; each.id _ NIL; }; each.isTotal _ FALSE; ENDLOOP; }; ClearBreak: Menus.MenuProc = { <> <> WITH clientData SELECT FROM each: EachData => TRUSTED { id: FastBreak.FastBreakId = each.id; IF id # NIL THEN {each.id _ NIL; [] _ FastBreak.ClearFastBreak[id]}; each.isTotal _ FALSE; }; ENDCASE; }; ResetCount: Menus.MenuProc = TRUSTED { <> <> WITH clientData SELECT FROM each: EachData => { id: FastBreak.FastBreakId = each.id; IF id # NIL THEN id^ _ 0; }; ENDCASE; }; ResetAllCounts: Menus.MenuProc = { <> <> DoUnderLock[clientData, innerResetAllCounts]; }; innerResetAllCounts: PROC [data: BaseData] = TRUSTED { vtab: VTables.VTable = data.vtab; FOR each: EachData _ data.head, each.next WHILE each # NIL DO IF each.id # NIL THEN each.id^ _ 0; ENDLOOP; }; fudge: NAT _ 20; InstallNewRows: PROC [data: BaseData, rows: NAT] = TRUSTED { IF data # NIL THEN { vtab: VTables.VTable _ data.vtab; IF vtab # NIL AND NOT vtab.destroyed AND rows # data.rows THEN { parent: VTables.VTable _ vtab.parent; smaller: BOOL _ rows < data.rows; IF rows = 0 THEN data.cols _ 0; VTables.SetRowsAndColumns[vtab, data.rows _ rows, data.cols]; SELECT rows FROM 0 => {}; 1 => { VTables.SetTableEntry[ table: vtab, column: codeCol, name: NIL, border: VTables.NullBorder]; VTables.SetTableEntry[ table: vtab, column: pcCol, name: NIL, border: VTables.NullBorder]; VTables.SetTableEntry[ table: vtab, column: posCol, name: NIL, border: VTables.NullBorder]; VTables.SetTableEntry[ table: vtab, column: nameCol, name: NIL, border: VTables.NullBorder]; }; 2 => { VTables.SetTableEntry[ table: vtab, column: codeCol, name: "code", border: VTables.NullBorder]; VTables.SetTableEntry[ table: vtab, column: pcCol, name: "pc", border: VTables.NullBorder]; VTables.SetTableEntry[ table: vtab, column: posCol, name: "pos", border: VTables.NullBorder]; VTables.SetTableEntry[ table: vtab, column: nameCol, name: "name", border: VTables.NullBorder]; }; ENDCASE; VTables.Install[vtab, FALSE]; ViewerOps.SetOpenHeight[parent, vtab.wh + fudge]; IF NOT parent.iconic THEN { ViewerOps.ComputeColumn[parent.column]; IF smaller THEN ViewerOps.PaintViewer[parent, all, TRUE, NIL]; }; }}; }; WaitForChange: ENTRY PROC [data: BaseData] RETURNS [quit: BOOL] = TRUSTED { <> ENABLE UNWIND => NULL; vtab: VTables.VTable = data.vtab; WAIT data.timeCond; RETURN [vtab.destroyed]; }; SetPause: PROC [data: BaseData, pause: Process.Milliseconds _ 1000] = TRUSTED { ENABLE UNWIND => NULL; Process.SetTimeout[@data.timeCond, Process.MsecToTicks[pause]]; }; AcquireLock: ENTRY PROC [data: BaseData] = TRUSTED { ENABLE UNWIND => NULL; WHILE data.locked DO WAIT data.changeCond; ENDLOOP; data.locked _ TRUE; }; ReleaseLock: ENTRY PROC [data: BaseData] = TRUSTED { ENABLE UNWIND => NULL; data.locked _ FALSE; BROADCAST data.changeCond; }; DoUnderLock: PROC [ref: REF, inner: PROC [data: BaseData]] = TRUSTED { WITH ref SELECT FROM data: BaseData => { ENABLE UNWIND => ReleaseLock[data]; AcquireLock[data]; inner[data]; ReleaseLock[data]; }; ENDCASE; }; StartCeltics: Commander.CommandProc = TRUSTED { Process.Detach[FORK UpdateDisplayProcess[]]; }; Commander.Register["Celtics", StartCeltics, "is a tool to take counts of fast breaks."]; END.