-- file: BackStop.Mesa
-- edited by Levin, March 13, 1981 4:44 PM
-- edited by Schroeder, March 15, 1981 2:45 PM
-- edited by Brotz, November 13, 1981 9:27 AM
-- edited by Taft, May 9, 1983 11:58 AM

DIRECTORY
Ascii USING [CR],
ControlDefs USING [ControlLink, FrameHandle, NullFrame],
csD: FROM "CoreStreamDefs" USING [Close, OpenFromName, StreamHandle, Write],
DiskIODefs USING [DiskError],
drD: FROM "LaurelDriverDefs" USING [],
dsD: FROM "DisplayDefs" USING [DCBorg, SetCursor],
Editor USING [RefreshSoThatFirstCharStartsLine],
exD: FROM "exceptionDefs" USING [AppendExceptionString, autoErrorReport,
cannotProceed, ClearExceptionsRegion, DisplayException, DisplayExceptionLine,
DisplayExceptionStringOnLine, FlashExceptionsRegion, GetExceptionString,
maxExceptionStringLength, mustEndSession, noBugReportFile, recursiveTrouble,
SysBugSignal, systemError, tryToContinue],
FrameOps USING [MyLocalFrame],
ImageDefs USING [StopMesa],
inD: FROM "InteractorDefs" USING [CharIndex, MessageTextNbrPtr, SetCaretBlinking,
StopBlinkingCaret, TextSelection],
Inline USING [BITAND, DIVMOD],
intCommon USING [bugReportee, cmTextNbr, editorType, imageFileName,
newTargetSelection, pendingDeleteSetByControl, target, timeMayBeBogus, versionHouse],
ModuleName USING [ControlLinkToModuleName],
opD: FROM "OperationsDefs" USING [FileError],
PupDefs USING [GetPupAddress, PupAddress],
SegmentDefs USING [memConfig],
String USING [AppendString],
TrapDefs USING [ParityError, PhantomParityError],
vmD: FROM "VirtualMgrDefs" USING [CharIndex, ComposedMessage, ComposedMessagePtr,
GetMessageChar, GetMessageSize, InsertFileInMessage],
VMDefs USING [CantReadBackingStore, CantWriteBackingStore, Error];

BackStop: PROGRAM
IMPORTS csD, DiskIODefs, dsD, Editor, exD, FrameOps, ImageDefs, Inline,
intC: intCommon, inD, ModuleName, opD, PupDefs, SegmentDefs, String,
TrapDefs, vmD, VMDefs
EXPORTS drD =

BEGIN
OPEN inD;

recursionDepth: INTEGER ← -1;
oldSignalMessage: STRING ← "Signal lost.";

PupTrouble: ERROR[why: UNSPECIFIED] = CODE;

-- ProcessBugReport is called during initialization if a /b switch is encountered.

ProcessBugReport: PUBLIC PROCEDURE =
BEGIN
state: {initial, firstCR, endOfHeader, secondCR} ← initial;
selectionStart, selectionEnd: CARDINAL;
mnp: inD.MessageTextNbrPtr = intC.cmTextNbr;
message: vmD.ComposedMessagePtr = vmD.ComposedMessage[mnp.message];
modelessEditor: BOOLEAN = (intC.editorType = modeless);
i: CharIndex;
char: CHARACTER;

vmD.InsertFileInMessage
[0, message, "Laurel.BugReport$"L ! opD.FileError => GO TO MalFormedMessage];
FOR i IN [0 .. vmD.GetMessageSize[message]) DO
char ← vmD.GetMessageChar[message, i];
SELECT state FROM
initial => IF char = Ascii.CR THEN state ← firstCR;
firstCR =>
IF char = Ascii.CR THEN {state ← endOfHeader; selectionStart ← i+1}
ELSE state ← initial;
endOfHeader => IF char = Ascii.CR THEN state ← secondCR;
secondCR =>
IF char = Ascii.CR THEN {selectionEnd ← i-1; EXIT} ELSE state ← endOfHeader;
ENDCASE;
REPEAT
FINISHED => GO TO MalFormedMessage;
ENDLOOP;
intC.target ← inD.TextSelection
[mnp: mnp, start: selectionStart, end: selectionEnd, point: selectionStart, key: 0,
mode: char, pendingDelete: intC.editorType = modeless];
intC.newTargetSelection ← TRUE;
intC.pendingDeleteSetByControl ← FALSE;
message.formatStart ← message.formatEnd ← 0;
mnp.haveMessage ← TRUE;
IF modelessEditor THEN inD.StopBlinkingCaret[];
Editor.RefreshSoThatFirstCharStartsLine[firstChar: 0, firstLine: mnp.lines, mnp: mnp];
IF modelessEditor THEN inD.SetCaretBlinking[selectionStart, mnp];
EXITS
MalFormedMessage => exD.DisplayException[exception: exD.noBugReportFile];
END; -- of ProcessBugReport --


CapturePupGlitch: PUBLIC PROCEDURE [why: UNSPECIFIED -- DriverDefs.GlitchType --] =
BEGIN
ERROR PupTrouble[why];
END;
-- of CapturePupGlitch --


out: csD.StreamHandle ← NIL;


WriteString: PROCEDURE [s: STRING] =
BEGIN
FOR i: CARDINAL IN [0 .. s.length) DO csD.Write[out, s[i]]; ENDLOOP;
END; -- of WriteString --


-- Message Formatting Procedures


StuffOctal: PROCEDURE [value: UNSPECIFIED, s: STRING, start: CARDINAL, places: CARDINAL ← 6] =
BEGIN
FOR i: CARDINAL DECREASING IN [start..start+places) DO
digit: CARDINAL;
[value, digit] ← Inline.DIVMOD[value, 8];
s[i] ← LOOPHOLE[digit + 60B, CHARACTER];
ENDLOOP;
END; -- of StuffOctal --


DumpCallStack: PROCEDURE =
BEGIN
OPEN ControlDefs;
moduleName: STRING ← [20];
pcTemplate: STRING ← ", xxxxxx
"L;
localFrame: ControlLink ← FrameOps.MyLocalFrame[].returnlink;
THROUGH [0..100) DO
SELECT localFrame.tag FROM
frame =>
BEGIN
OPEN f:localFrame.frame;
IF @f = NullFrame THEN EXIT;
ModuleName.ControlLinkToModuleName[localFrame, moduleName];
WriteString[moduleName];
StuffOctal[IF f.pc < 0 THEN (-f.pc) * 2 + 1 ELSE f.pc * 2, pcTemplate, 2];
WriteString[pcTemplate];
localFrame ← f.returnlink;
END;
ENDCASE =>
BEGIN
WriteString["Stack end "L];
ModuleName.ControlLinkToModuleName[localFrame, moduleName];
WriteString[moduleName];
csD.Write[out, Ascii.CR];
EXIT;
END;
ENDLOOP;
csD.Write[out, Ascii.CR];
END; -- of DumpCallStack --


WriteGoryDetails: PROCEDURE =
BEGIN
OPEN SegmentDefs;
s: STRING ← " (nnn#nnn#) with "L;
rest: STRING ← "MDS: nn Banks: nnnnnn"L;
ucode: STRING ← " flcode: nnnnnn"L;
me: PupDefs.PupAddress;
WriteString[" "L];
WriteString[ SELECT memConfig.AltoType FROM
AltoI => "Alto I"L,
AltoII => "Alto II"L,
AltoIIXM => "Alto II XM"L,
D0 => "Dolphin"L,
Dorado => "Dorado"L,
ENDCASE => "IBM 360/15"L];
PupDefs.GetPupAddress[@me, "ME"L];
StuffOctal[me.net, s, 2, 3]; StuffOctal[me.host, s, 6, 3];
WriteString[s];
IF memConfig.AltoType < D0 THEN
WriteString[SELECT memConfig.controlStore FROM
Ram0 => "Ram only "L,
RamandRom => "2K Rom "L,
Ram3k => "3K Ram "L,
ENDCASE => "Paper tape "L];
IF memConfig.xmMicroCode THEN WriteString["XMflcode "L];
IF memConfig.useXM THEN WriteString["using XM "L];
StuffOctal[memConfig.mdsBank, rest, 5, 2];
StuffOctal[memConfig.banks, rest, 15];
WriteString[rest];
IF memConfig.AltoType < D0 THEN
{StuffOctal[memConfig.mesaMicrocodeVersion, ucode, 8]; WriteString[ucode]};
END; -- of WriteGoryDetails --


Oops: PROCEDURE =
BEGIN
exD.FlashExceptionsRegion[];
UNTIL UserWants[] = terminate DO ENDLOOP; --
Die[];
END; -- of Oops --


Die: PROCEDURE =
BEGIN
dsD.DCBorg↑ ← LOOPHOLE[0]; -- keep display tidy
ImageDefs.StopMesa[];
END; -- of Die --


UserWants: PROCEDURE RETURNS[{tryIt,terminate}] =
BEGIN
mouseButton: POINTER TO UNSPECIFIED = LOOPHOLE[177030B];
redBlue: UNSPECIFIED = 4+2;
yellow: UNSPECIFIED = 1;
UNTIL Inline.BITAND[mouseButton↑,yellow] = 0 DO
IF Inline.BITAND[mouseButton↑,redBlue] = 0 THEN RETURN[terminate];
ENDLOOP;
RETURN[tryIt];
END; -- of UserWants --


Catcher: PUBLIC PROCEDURE [msg: UNSPECIFIED, signal: SIGNAL[UNSPECIFIED],
frame: ControlDefs.FrameHandle] =
BEGIN
i: CARDINAL;
savedCursor: ARRAY [0 .. 15] OF CARDINAL;
pCursor: POINTER TO ARRAY [0 .. 15] OF CARDINAL = LOOPHOLE[431B];
errorCursor: ARRAY [0 .. 15] OF CARDINAL =
[34034B, 42042B, 101102B, 101202B, 101204B, 42210B, 34160B, 0,
176174B, 101202B, 101200B, 176174B, 100002B, 100202B, 100174B, 0];
moduleName: STRING ← [20];

twoCRs: STRING ← "

"L;

headerPart: STRING ← "Subject: Error Report
To: "L;

bodyPart: STRING ← "Please replace this paragraph with a brief description of what you were doing when Laurel broke, then ""Deliver"" this message. (Be sure to include the last command you invoked.) After the message is delivered, you can continue to use Laurel as usual."L;

parityErrorMessage: STRING ← "Parity error at ??????."L;
-- 28 spaces required after msg↑
signalMessage: STRING ← "Signal xxxxxx in "L;
msgMessage: STRING ← "msg xxxxxx, msg↑ "L;

SELECT (recursionDepth ← recursionDepth+1) FROM
0 => NULL;
1 => BEGIN
exceptionString: STRING ← [exD.maxExceptionStringLength];
pCursor↑ ← errorCursor;
exD.GetExceptionString[exD.recursiveTrouble, exceptionString];
String.AppendString[exceptionString, intC.bugReportee];
exD.AppendExceptionString[exD.mustEndSession, exceptionString];
exD.DisplayExceptionStringOnLine[exceptionString, 1];
exD.DisplayExceptionStringOnLine[oldSignalMessage, 2];
Oops[];
END;
ENDCASE => DO ENDLOOP;

savedCursor ← pCursor↑;
pCursor↑ ← errorCursor;
SELECT signal FROM
LOOPHOLE[TrapDefs.PhantomParityError, SIGNAL[UNSPECIFIED]],
TrapDefs.ParityError =>
BEGIN
IF signal = TrapDefs.ParityError THEN StuffOctal[msg, parityErrorMessage, 16];
exD.DisplayExceptionStringOnLine[parityErrorMessage, 1];
exD.DisplayExceptionLine[exD.tryToContinue, 2];
exD.FlashExceptionsRegion[];
IF UserWants[] = terminate THEN Die[];
pCursor↑ ← savedCursor;
recursionDepth ← -1;
exD.ClearExceptionsRegion[];
intC.timeMayBeBogus ← TRUE;
RETURN; --resume the parity error
END;
exD.SysBugSignal => IF ~LOOPHOLE[msg, BOOLEAN] THEN Oops[];
LOOPHOLE[VMDefs.CantReadBackingStore, SIGNAL [UNSPECIFIED] ],
LOOPHOLE[VMDefs.CantWriteBackingStore, SIGNAL [UNSPECIFIED] ],
LOOPHOLE[VMDefs.Error, SIGNAL [UNSPECIFIED] ],
LOOPHOLE[DiskIODefs.DiskError, SIGNAL [UNSPECIFIED] ] =>
BEGIN
exD.DisplayExceptionStringOnLine["Disk error"L, 1];
exD.DisplayExceptionLine[exD.cannotProceed, 2];
Oops[];
END;
ENDCASE;

--remember this instance of signalMessage for possible recursive error
oldSignalMessage ← signalMessage;

--prepare signal message
StuffOctal[signal, signalMessage, 7];
ModuleName.ControlLinkToModuleName[LOOPHOLE[signal], moduleName];
StuffOctal[msg, msgMessage, 4];
IF LOOPHOLE[msg, CARDINAL] > 1400B THEN
FOR i ← 17, i + 7 WHILE i < 39 DO
StuffOctal[LOOPHOLE[msg + (i - 17) / 7, POINTER]↑, msgMessage, i];
ENDLOOP;

exD.DisplayExceptionLine[exD.systemError, 1];
exD.DisplayExceptionLine[exD.autoErrorReport, 2];
exD.FlashExceptionsRegion[];
IF UserWants[] = terminate THEN Die[];

dsD.SetCursor[hourGlass];

out ← csD.OpenFromName["Laurel.BugReport$"L, byte, overwrite];
WriteString[headerPart]; WriteString[intC.bugReportee]; WriteString[twoCRs];
WriteString[bodyPart]; WriteString[twoCRs];
WriteString[intC.versionHouse.text]; WriteGoryDetails[]; WriteString[twoCRs];
WriteString[signalMessage]; WriteString[moduleName]; csD.Write[out, Ascii.CR];
WriteString[msgMessage]; WriteString[twoCRs];
DumpCallStack[];
csD.Close[out];
IF intC.imageFileName # NIL THEN
BEGIN
out ← csD.OpenFromName["Rem.cm"L, byte, overwrite];
WriteString[intC.imageFileName]; WriteString["/b"L]; csD.Write[out, Ascii.CR];
csD.Close[out];
END;

Die[];
END; -- of Catcher --


END.
-- of BackStop --