-- File: LogDisplayCold.mesa -- Roy Levin May 20, 1980 6:11 PM -- Andrew Birrell 2-Jun-81 15:55:33 -- Mark Johnson May 29, 1981 11:48 AM DIRECTORY FontDefs USING [ CharHeight, CharWidth, CreateFont, FontHandle], ImageDefs USING [ AddCleanupProcedure, BcdTime, CleanupItem, CleanupMask, CleanupProcedure, RemoveCleanupProcedure], InlineDefs USING[ LowHalf ], LogDefs USING [ defaultRefreshInterval, defaultTypescriptLines, DisplayItem, noLimit, Percentage], LogPrivateDefs USING [ BitmapState, bmPointsPerLine, bmWordsPerLine, Cursor, cursorBM, DCB, DCBchainHead, DCBHandle, DCBnil, dcbSeal, Displayer, Even, Face, firstScriptDCB, firstScriptLineDCB, headingDCB, houses, IllegalUseOfLog, interValueSeparatorWidth, intraValueSeparatorWidth, italicSlant, lastScriptDCB, LogDisplayHot, machineFlavor, marginWords, NumberHouseObject, PutStringInBitmap, ScreenPoints, screenPointsPerWord, scriptFont, scriptBMStatePtr, scriptCurrentDCB, spaceAfterHeading, spaceAfterStatus, startUpTime, statsFont, topMargin, typescriptOn, uptimeHouse, Zero], ProcessDefs USING [Abort, Seconds], SegmentDefs USING [ BitmapDS, DataSegmentHandle, DefaultBase, DefaultBase1, DefaultPages, DeleteDataSegment, DeleteFileSegment, FileHandle, FileSegmentHandle, LongDataSegmentAddress, LongVMtoDataSegment, memConfig, NewFile, NewDataSegment, NewFileSegment, OldFileOnly, Read], StringDefs USING [AppendChar, AppendString], Storage USING [Node, String, Free, FreeString], TimeDefs USING [ AppendDayTime, AppendFullDayTime, CurrentDayTime, PackedTime, UnpackDT]; LogDisplayCold: MONITOR IMPORTS FontDefs, ImageDefs, InlineDefs, LogPrivateDefs, ProcessDefs, SegmentDefs, StringDefs, ShortTermHeap: Storage, LongTermHeap: Storage, TimeDefs EXPORTS LogDefs = BEGIN OPEN FontDefs, LogDefs, LogPrivateDefs; -- Types and Related Constants -- RegisteredValueObject: TYPE = --MACHINE DEPENDENT-- RECORD [ link: RegisteredValue, item: DisplayItem, textLine: [0..maxLines), captionLeftX, numberLeftX: ScreenPoints, caption: StringBody]; RegisteredValue: TYPE = POINTER TO RegisteredValueObject; maxLines: CARDINAL = 100; -- a (reasonable) upper bound of the number of displayed text lines -- Global Variables -- firstValue, lastValue: RegisteredValue; nValues: CARDINAL; statisticsOn: BOOLEAN; -- typescriptOn in LogDisplayHot statsPages: CARDINAL; statsFontName: STRING; statsFontFile: SegmentDefs.FileHandle; statsFileSeg: SegmentDefs.FileSegmentHandle; statsBMSegBase: LONG POINTER; firstStatsDCB, lastStatsDCB, statusDCB, firstNumberDCB: DCBHandle; nDCBs: CARDINAL; statusString: STRING; digitWidth, shortNumberWidth, longNumberWidth, percentageWidth: ScreenPoints; displayProcess: PROCESS; statsRefreshInterval: ProcessDefs.Seconds; dcbChainHead: DCBHandle; displayCleanup: ImageDefs.CleanupItem; scriptPages: CARDINAL; scriptLines: CARDINAL; scriptFontName: STRING; scriptFontFile: SegmentDefs.FileHandle; scriptFileSeg: SegmentDefs.FileSegmentHandle; scriptBMSegBase: LONG POINTER; savedCursor: Cursor; -- Miscellaneous Declarations -- noLimit: CARDINAL = LogDefs.noLimit; daytimeLength: CARDINAL = 18; -- length of: 12-Jan-80 14:35:52 fullDaytimeLength: CARDINAL = 22; -- length of: 12-Jan-80 14:35:52 PST elapsedTimeLength: CARDINAL = 13; -- length of: 1234567:35:28 -- Start/Stop Procedures -- StatisticsOn: PUBLIC ENTRY PROCEDURE [heading: STRING] = -- called after all statistics specification procedures (SetStatisticsParameters and DisplayNumber) have been called. 'heading' is an ASCII string that will be displayed at the top of the screen. The 'heading' string need not persist in the client's storage after DisplayOn has returned. StatisticsOn concludes with an implicit ScreenOn. BEGIN OPEN SegmentDefs; statsBMWords: CARDINAL _ 0; headingWords, statusWords: CARDINAL; lineNumber: [0..maxLines) _ 0; lineWidth: DESCRIPTOR FOR ARRAY [0..maxLines) OF CARDINAL _ DESCRIPTOR[ ShortTermHeap.Node[maxLines], maxLines]; lineHeight: ScreenPoints; c: CHARACTER; AssignPositionsForNumbers: PROCEDURE = -- assigns positions for list of RegisteredValues, and computes the bitmap space required -- to display them. It is assumed that at least one value can be placed before hitting the -- client-imposed limit on bitmap space. BEGIN val, prevValue: RegisteredValue; valWidth, numberWidth: ScreenPoints; curX: ScreenPoints _ 0; NewLine: PROCEDURE = BEGIN lineWidth[lineNumber] _ IF curX = 0 THEN 0 ELSE EvenWords[curX - interValueSeparatorWidth]; statsBMWords _ lineWidth[lineNumber] + statsBMWords; lineNumber _ lineNumber + 1; curX _ 0; END; FOR val _ firstValue, val.link UNTIL val = NIL DO numberWidth _ SELECT val.item.format FROM short => shortNumberWidth, long => longNumberWidth, ENDCASE => percentageWidth; valWidth _ ComputeStringWidth[@val.caption, statsFont, plain] + intraValueSeparatorWidth + numberWidth; IF (EvenWords[curX + valWidth] + statsBMWords)/256 = statsPages THEN GO TO NoMore; IF curX + valWidth >= bmPointsPerLine THEN NewLine[]; val.captionLeftX _ curX; val.numberLeftX _ val.captionLeftX + valWidth - numberWidth; val.textLine _ lineNumber; curX _ curX + valWidth + interValueSeparatorWidth; prevValue _ val; REPEAT NoMore => BEGIN v: RegisteredValue; lastValue _ prevValue; UNTIL val = NIL DO v _ val.link; ShortTermHeap.Free[val]; val _ v; nValues _ nValues - 1; ENDLOOP; NewLine[]; END; FINISHED => NewLine[]; ENDLOOP; END; -- AssignPositionsForNumbers SetUpDCBsAndBitmap: PROCEDURE = -- allocates the bitmap and initializes the DCBs. BEGIN dcb: DCBHandle; bm: LONG POINTER; bmSegSize: CARDINAL = lineHeight*(headingWords + statusWords + statsBMWords); bm _ statsBMSegBase _ AllocBitmap[bmSegSize]; firstStatsDCB _ dcb _ Even[LongTermHeap.Node[nDCBs*SIZE[DCB]+1]]; THROUGH [0..nDCBs) DO dcb^ _ DCB[ next: dcb + SIZE[DCB], resolution: high, background: white, indenting: marginWords, width: 0, height: lineHeight/2, longBitmap:]; dcb _ dcb.next; ENDLOOP; lastStatsDCB _ dcb - SIZE[DCB]; lastStatsDCB.next _ DCBnil; -- set up initial spacer firstStatsDCB.height _ topMargin/2; -- set up heading dcb _ headingDCB _ firstStatsDCB.next; InitDCB[dcb, bm]; dcb.width _ headingWords; dcb.indenting _ marginWords + (bmWordsPerLine - headingWords)/2; bm _ bm + headingWords*lineHeight; -- set up spacer after heading dcb _ dcb.next; dcb.height _ spaceAfterHeading; -- set up status dcb _ statusDCB _ dcb.next; InitDCB[dcb, bm]; dcb.width _ statusWords; dcb.indenting _ marginWords + (bmWordsPerLine - statusWords)/2; bm _ bm + statusWords*lineHeight; -- set up spacer after status dcb _ dcb.next; dcb.height _ spaceAfterStatus; -- set up DCBs for statistics proper dcb _ firstNumberDCB _ dcb.next; FOR line: [0..maxLines) IN [0..lineNumber) DO InitDCB[dcb, bm]; dcb.width _ lineWidth[line]; bm _ bm + lineWidth[line]*lineHeight; dcb _ dcb.next; ENDLOOP; END; -- SetUpDCBsAndBitmap BuildStatusString: PROCEDURE = -- sets up the status string and variables required to refresh it. BEGIN OPEN StringDefs, TimeDefs; s1: STRING = "Version of "L; s2: STRING = " Up at "L; s3: STRING = " Uptime: "L; length: CARDINAL = s1.length + daytimeLength + s2.length + fullDaytimeLength + s3.length + elapsedTimeLength; startUpTime _ CurrentDayTime[]; statusString _ LongTermHeap.String[length]; AppendString[statusString, s1]; AppendDayTime[statusString, UnpackDT[ImageDefs.BcdTime[]]]; AppendString[statusString, s2]; AppendFullDayTime[statusString, UnpackDT[startUpTime]]; AppendString[statusString, s3]; uptimeHouse _ NumberHouseObject[ leftX: ComputeStringWidth[statusString, statsFont, plain], width: elapsedTimeLength*digitWidth, -- assumes CharWidth[':, statsFont] shortNumberWidth, long => longNumberWidth, ENDCASE => percentageWidth, dcb: dcb, caption: LongTermHeap.String[firstValue.caption.length], item:]; StringDefs.AppendString[houses[h].caption, @(firstValue.caption)]; WITH val: firstValue.item SELECT FROM short => houses[h].item _ short[ max: FIRST[CARDINAL], min: LAST[CARDINAL], p: val.p]; long => houses[h].item _ long[ max: FIRST[LONG CARDINAL], min: LAST[LONG CARDINAL], p: val.p]; percent => houses[h].item _ percent[ max: FIRST[Percentage], min: LAST[Percentage], p: val.p]; ENDCASE; bmState.x _ firstValue.captionLeftX; PutStringInBitmap[@firstValue.caption, statsFont, plain, @bmState]; val _ firstValue.link; ShortTermHeap.Free[firstValue]; firstValue _ val; ENDLOOP; bmState _ BitmapState[ origin: headingDCB.longBitmap, wordsPerLine: headingDCB.width, x: 0, y: 0]; PutStringInBitmap[heading, statsFont, bold, @bmState]; bmState _ BitmapState[ origin: statusDCB.longBitmap, wordsPerLine: statusDCB.width, x: 0, y: 0]; PutStringInBitmap[statusString, statsFont, plain, @bmState]; uptimeHouse.dcb _ statusDCB; END; -- BuildInitialScreen IF statisticsOn THEN ERROR IllegalUseOfLog; statsFontFile _ NewFile[ IF statsFontName = NIL THEN "SysFont.al"L ELSE statsFontName, Read, OldFileOnly]; IF typescriptOn AND statsFontFile = scriptFontFile THEN BEGIN statsFileSeg _ scriptFileSeg; statsFont _ scriptFont; END ELSE BEGIN statsFileSeg _ NewFileSegment[ statsFontFile, DefaultBase, DefaultPages, Read]; statsFont _ CreateFont[statsFileSeg]; END; [] _ statsFont.lock[statsFont]; IF statsFontName ~= NIL THEN ShortTermHeap.FreeString[statsFontName]; digitWidth _ 0; FOR c IN ['0..'9] DO digitWidth _ MAX[digitWidth, CharWidth[statsFont, c]]; ENDLOOP; shortNumberWidth _ 5*digitWidth; longNumberWidth _ 11*digitWidth; percentageWidth _ 3*digitWidth + CharWidth[statsFont, '%]; AssignPositionsForNumbers[]; BuildStatusString[]; nDCBs _ lineNumber + 5; -- 5 = spacer, heading, spacer, status, spacer headingWords _ EvenWords[ComputeStringWidth[heading, statsFont, bold]]; lineHeight _ CharHeight[statsFont, 'A]; SetUpDCBsAndBitmap[]; ShortTermHeap.Free[BASE[lineWidth]]; BuildInitialScreen[]; statisticsOn _ TRUE; IF typescriptOn THEN lastStatsDCB.next _ firstScriptDCB ELSE ImageDefs.AddCleanupProcedure[@displayCleanup]; dcbChainHead _ firstStatsDCB; TurnScreenOn[]; savedCursor _ cursorBM^; displayProcess _ FORK Displayer[statsRefreshInterval]; END; --DisplayOn TypescriptOn: PUBLIC ENTRY PROCEDURE = -- called after the typescript specification procedure (SetTypescriptParameters) has been called. The typescript is initialized and made ready for calls on WriteChar, WriteString, and related output procedures. TypescriptOn concludes with an implicit ScreenOn. BEGIN OPEN SegmentDefs; bmWordsPerScriptLine: CARDINAL; scriptSegSize: CARDINAL; lineHeight: ScreenPoints; SetUpDCBsAndBitmap: PROCEDURE = -- allocates the bitmap and initializes the DCBs. BEGIN dcb: DCBHandle; bm: LONG POINTER; scriptBMSegBase _ AllocBitmap[scriptSegSize]; bm _ scriptBMSegBase - bmWordsPerScriptLine; firstScriptDCB _ dcb _ Even[ LongTermHeap.Node[(scriptLines+1)*SIZE[DCB]+1]]; THROUGH [0..scriptLines + 1) DO dcb^ _ DCB[ next: dcb + SIZE[DCB], resolution: high, background: white, indenting: marginWords, width: bmWordsPerLine, height: lineHeight/2]; InitDCB[dcb, bm]; dcb _ dcb.next; bm _ bm + bmWordsPerScriptLine; ENDLOOP; lastScriptDCB _ dcb - SIZE[DCB]; lastScriptDCB.next _ DCBnil; firstScriptDCB.height _ topMargin/2; firstScriptDCB.width _ 0; firstScriptLineDCB _ scriptCurrentDCB _ firstScriptDCB.next; scriptBMStatePtr^ _ BitmapState[ origin: scriptCurrentDCB.longBitmap, wordsPerLine: scriptCurrentDCB.width, x: 0, y: 0]; END; -- SetUpDCBsAndBitmap IF typescriptOn THEN ERROR IllegalUseOfLog; scriptFontFile _ NewFile[ IF scriptFontName = NIL THEN "SysFont.al"L ELSE scriptFontName, Read, OldFileOnly]; IF statisticsOn AND scriptFontFile = statsFontFile THEN BEGIN scriptFileSeg _ statsFileSeg; scriptFont _ statsFont; END ELSE BEGIN scriptFileSeg _ NewFileSegment[ scriptFontFile, DefaultBase, DefaultPages, Read]; scriptFont _ CreateFont[scriptFileSeg]; END; [] _ scriptFont.lock[scriptFont]; IF scriptFontName ~= NIL THEN ShortTermHeap.FreeString[scriptFontName]; lineHeight _ CharHeight[scriptFont, 'A]; bmWordsPerScriptLine _ Even[lineHeight*bmWordsPerLine]; scriptSegSize _ (bmWordsPerScriptLine + SIZE[DCB])*scriptLines + SIZE[DCB]; IF Pages[scriptSegSize] > scriptPages THEN BEGIN scriptLines _ scriptPages*256/(bmWordsPerScriptLine + SIZE[DCB]); scriptSegSize _ (bmWordsPerScriptLine + SIZE[DCB])*scriptLines + SIZE[DCB]; END; SetUpDCBsAndBitmap[]; IF statisticsOn THEN lastStatsDCB.next _ firstScriptDCB ELSE dcbChainHead _ firstScriptDCB; typescriptOn _ TRUE; IF ~statisticsOn THEN ImageDefs.AddCleanupProcedure[@displayCleanup]; TurnScreenOn[]; END; --TypescriptOn DisplayOff: PUBLIC ENTRY PROCEDURE = -- DisplayOff first performs an implicit ScreenOff, then causes an orderly cleanup of the display data structures. All information previously supplied via SetStatisticsParameters, DisplayNumber, and SetTypescriptParameters is discarded and all internal data structures are released. BEGIN TurnScreenOff[]; ImageDefs.RemoveCleanupProcedure[@displayCleanup]; IF statisticsOn THEN BEGIN ProcessDefs.Abort[displayProcess]; SegmentDefs.DeleteDataSegment[SegmentDefs.LongVMtoDataSegment[ statsBMSegBase]]; LongTermHeap.Free[firstStatsDCB]; LongTermHeap.Free[BASE[houses]]; statsFont.unlock[statsFont]; statsFont.destroy[statsFont]; SegmentDefs.DeleteFileSegment[statsFileSeg]; cursorBM^ _ savedCursor; END; IF typescriptOn THEN BEGIN SegmentDefs.DeleteDataSegment[SegmentDefs.LongVMtoDataSegment[ scriptBMSegBase]]; LongTermHeap.Free[firstScriptDCB]; scriptFont.unlock[scriptFont]; IF ~(statisticsOn AND statsFontFile = scriptFontFile) THEN BEGIN scriptFont.destroy[scriptFont]; SegmentDefs.DeleteFileSegment[scriptFileSeg]; END; END; Initialize[]; END; --DisplayOff ScreenOff: PUBLIC ENTRY PROCEDURE = -- turns off the display screen without affecting any of the underlying data structures. BEGIN TurnScreenOff[]; END; --ScreenOff ScreenOn: PUBLIC ENTRY PROCEDURE = -- undoes the effect of ScreenOff. BEGIN TurnScreenOn[]; END; --ScreenOn -- Statistics Display Procedures -- SetStatisticsParameters: PUBLIC ENTRY PROCEDURE [ bmPages: CARDINAL _ noLimit, font: STRING _ NIL, refreshInterval: ProcessDefs.Seconds _ defaultRefreshInterval] = -- This procedure alters the defaults for the statistics region of the display. 'bmPages' defines a limit on the number of bitmap pages to be allocated for statistics display. The actual number of pages allocated will depend of the number of DisplayItems registered via DisplayNumber. 'font', if not defaulted, specifies the name of a file to be used as the font for the statistics region (don't forget ".al"!); otherwise, "Sysfont.al" will be used. 'refreshInterval' is the time in seconds between updates of the statistics display. This procedure, if called at all, must be called before StatisticsOn. BEGIN IF statisticsOn THEN ERROR IllegalUseOfLog; statsPages _ bmPages; statsRefreshInterval _ refreshInterval; IF font ~= NIL THEN BEGIN IF statsFontName ~= NIL THEN ShortTermHeap.FreeString[statsFontName]; statsFontName _ ShortTermHeap.String[font.length]; StringDefs.AppendString[statsFontName, font]; END; END; --SetStatisticsParameters DisplayNumber: PUBLIC ENTRY PROCEDURE [caption: STRING, item: DisplayItem] = -- registers a value to be maintained on the display. 'item' defines the main memory location of the value (which must not change) and the format in which it is to be displayed. 'caption' is accompanying ASCII text. The 'caption' string need not persist in the client's storage after DisplayNumber has returned. DisplayNumber must be called before StatisticsOn. BEGIN value: RegisteredValue; IF statisticsOn THEN ERROR IllegalUseOfLog; value _ ShortTermHeap.Node[ SIZE[RegisteredValueObject] + (caption.length + 1 + 1)/2]; value^ _ [link: NIL, item: item, textLine:, captionLeftX:, numberLeftX:, caption: [length: 0, maxlength: caption.length + 1, text:]]; StringDefs.AppendString[@value.caption, caption]; IF caption[caption.length - 1] ~= ': THEN StringDefs.AppendChar[@value.caption, ':]; IF lastValue = NIL THEN firstValue _ value ELSE lastValue.link _ value; lastValue _ value; nValues _ nValues + 1; END; --DisplayNumber -- Typescript Procedures -- SetTypescriptParameters: PUBLIC ENTRY PROCEDURE [ tsPages: CARDINAL _ noLimit, tsLines: CARDINAL _ defaultTypescriptLines, font: STRING _ NIL] = -- This procedure alters the defaults for the typescript region ot the display. Up to 'tsLines' of text will be displayed, subject to the constraint that no more than 'tsPages' of bitmap will be consumed. 'font', if not defaulted, specifies the name of a file to be used as the font for the typescript region (don't forget ".al"!); otherwise, "Sysfont.al" will be used. This procedure, if called at all, must be called before TypescriptOn. BEGIN IF typescriptOn THEN ERROR IllegalUseOfLog; scriptPages _ tsPages; scriptLines _ tsLines; IF font ~= NIL THEN BEGIN scriptFontName _ ShortTermHeap.String[font.length]; StringDefs.AppendString[scriptFontName, font]; END; END; --SetTypescriptParameters -- Internal Procedures -- AllocBitmap: PROC[words: CARDINAL] RETURNS[ptr: LONG POINTER] = BEGIN OPEN SegmentDefs; -- allocate and zero bitmap in appropriate part of machine -- seg: DataSegmentHandle = NewDataSegment[ IF machineFlavor = altoI THEN DefaultBase ELSE DefaultBase1, Pages[words] ]; seg.type _ BitmapDS; ptr _ LongDataSegmentAddress[seg]; Zero[ptr, words]; END; InitDCB: PROC[dcb: DCBHandle, bitmap: LONG POINTER] = BEGIN -- arrange that DCB points to given bitmap, depending on machine -- -- ScreenOn sets bank register for Alto II's -- IF machineFlavor = dMachine THEN { dcb.tag _ long; dcb.shortBitmap _ dcbSeal } ELSE { dcb.tag _ short; dcb.shortBitmap _ InlineDefs.LowHalf[bitmap] }; dcb.longBitmap _ bitmap; END; ComputeStringWidth: PROCEDURE [s: STRING, font: FontHandle, face: Face] RETURNS [width: ScreenPoints] = -- computes the width in ScreenPoints of the string 's' presented in 'font' and 'face'. BEGIN i: CARDINAL; width _ SELECT face FROM plain => 0, bold => s.length, ENDCASE => CharHeight[font, 'A]/italicSlant - 1; FOR i IN [0..s.length) DO width _ CharWidth[font, s[i]] + width; ENDLOOP; END; --ComputeStringWidth EvenWords: PROCEDURE [points: ScreenPoints] RETURNS [CARDINAL] = -- rounds up the argument number of screen points to an even number of words. BEGIN RETURN[Even[(points + screenPointsPerWord - 1)/screenPointsPerWord]] END; --EvenWords Pages: PROCEDURE [words: CARDINAL] RETURNS [CARDINAL] = -- rounds up the argument number of words to a count of pages. BEGIN RETURN[(words + 255)/256] END; --EvenWords DisplayCleanup: ImageDefs.CleanupProcedure = -- deals with the display at appropriate entry/exit. Note: in principle, this should be an ENTRY procedure, but that can cause deadlocks when debugging. Since this procedure isn't called in normal operation, we ignore the problem. BEGIN SELECT why FROM Finish, Abort, OutLd => TurnScreenOff[]; InLd => TurnScreenOn[]; ENDCASE; END; --DisplayCleanup BankReg: TYPE = MACHINE DEPENDENT RECORD[ spare: [0..7777B], normal: [0..3], alt: [0..3] ]; dwtBankReg: POINTER TO BankReg = LOOPHOLE[177740B+11B]; bitmapBank: [0..3] = 1; -- defined by use of DefaultBase1 in AllocBitmap TurnScreenOff: PROCEDURE = BEGIN -- Note: we busy wait instead of WAITing because Mesa insists on disabling scheduling -- during Finish and Abort (ugh), and ScreenOff is called from DisplayCleanup. realTime: POINTER TO CARDINAL = LOOPHOLE[430B]; delayStart: CARDINAL = realTime^; DCBchainHead^ _ DCBnil; UNTIL realTime^ - delayStart > 2 DO ENDLOOP; SELECT machineFlavor FROM xmesa39, altoMesa => dwtBankReg.normal _ 0; ENDCASE => NULL; END; --TurnScreenOff TurnScreenOn: PROCEDURE = -- undoes the effect of ScreenOff. BEGIN SELECT machineFlavor FROM xmesa39, altoMesa => dwtBankReg.normal _ bitmapBank; ENDCASE => NULL; DCBchainHead^ _ dcbChainHead; END; --TurnScreenOn -- Initialization -- Initialize: PROCEDURE = -- initializes all global variables. No initialization should occur in the variable declarations, since Initialize must restore the complete initial state of the global variables and is called from two places (the main body and DisplayOff). BEGIN OPEN ImageDefs; machineFlavor _ SELECT SegmentDefs.memConfig.AltoType FROM AltoIIXM => SELECT SegmentDefs.memConfig.mesaMicrocodeVersion FROM 39 => xmesa39, 41 => altoMesa, ENDCASE => altoI, Dorado, D0 => dMachine, ENDCASE => altoI; firstValue _ lastValue _ NIL; nValues _ 0; statisticsOn _ typescriptOn _ FALSE; statsPages _ noLimit; statsFontName _ NIL; scriptPages _ noLimit; scriptLines _ defaultTypescriptLines; scriptFontName _ NIL; statsRefreshInterval _ defaultRefreshInterval; dcbChainHead _ DCBnil; displayCleanup _ [link:, mask: CleanupMask[Finish] + CleanupMask[Abort] + CleanupMask[OutLd] + CleanupMask[InLd], proc: DisplayCleanup]; END; --Initialize -- Main Body -- START LogDisplayHot; Initialize[]; END.