-- file: InitLaurel.mesa
-- edited by: Schroeder, March 14, 1981 12:47 PM.
-- edited by Brotz, January 20, 1983 1:16 PM
-- edited by Levin, May 4, 1981 12:09 PM
-- edited by Taft, May 27, 1983 5:45 PM

DIRECTORY
AltoDefs USING [PageCount, PageNumber, PageSize],
AltoFileDefs USING [FP, LD, NullFP, TIME, vDA],
Ascii USING [CR, SP],
ControlDefs USING [GlobalFrame, GlobalFrameHandle, Port],
Core USING [DMSUserBlk, InsertInFileCache, Login, LookupInFileCache],
csD: FROM "CoreStreamDefs" USING [Close, EndOfStream, OpenFromName, Read,
StreamHandle],
DiskKD USING [diskKD],
DiskKDDefs USING [CloseDiskKD],
displayCommon USING [bitmapInMDS, bitMapPtr, mcFont],
DMSTimeDefs USING [SetLaurelTime],
drD: FROM "LaurelDriverDefs" USING [ALFont, CapturePupGlitch, Catcher,
CommandLineAction, InstallError],
dsD: FROM "DisplayDefs" USING [CursorBitMap, cursorBM, DCBnil, DCBorg, DCBptr,
Display, lineHeight, machineFlavor],
Editor USING [cancelCode, insertDeletionCode, nextCode],
exD: FROM "ExceptionDefs" USING [InitializeExceptions, SetUpExceptionTable, SysBug],
FrameDefs USING [GlobalFrame, LockCode, UnlockCode],
FrameOps USING [CodeHandle, SetReturnLink],
ImageDefs USING [AddCleanupProcedure, AddFileRequest, CleanupItem, CleanupMask,
CleanupProcedure, FileRequest],
inD: FROM "InteractorDefs" USING [maxBracketStringLength, realTimeClock,
ReportMBXState, SetTime],
Inline USING [BITOR, COPY, HighHalf],
intCommon USING [audioEnabled, cmTextNbr, dmTextNbr, editorType, gvTestingMode,
hardcopyHost, imageFileName, keystream, leafOk, mailcheckPollingInterval,
mailFileBracketsHouse, newMailTune, profileRegistry, profileRetrieve,
remoteFilePath, retrieveHandle, tocTextNbr, user, userBracketsHouse],
KeyDefs USING [ChangeKey, Keyboard],
LaurelFontDefs USING [LaurelFont],
lsD: FROM "LaurelStateDefs" USING [CreateLaurelState, InitializeSegments, PageCount,
PageNumber, ReleaseStateSegment, StateHeader, SwapInStateSegment],
MiscDefs USING [DestroyFakeModule],
NucleusOps USING [DiskKD],
OsStaticDefs USING [OsStatics],
ProcessDefs USING [DisableInterrupts, EnableInterrupts, Yield],
ProtocolDefs USING [SetTestingMode],
PupDefs USING [AdjustBufferParms, CaptureErrors, PupPackageMake],
Region USING [PageStatus],
RetrieveDefs USING [Create, NewUser, SetMTPRetrieveDefault],
SDDefs USING [SD, sUncaughtSignal],
SegmentDefs USING [CopyFileToDataSegment, DataSegmentAddress, DataSegmentHandle,
DefaultBase, DeleteFileSegment, EnumerateFileSegments, FileHandle, FileSegmentAddress,
FileSegmentHandle, HardDown, InsertFile, LockFile, MakeDataSegment, MakeSwappedIn,
memConfig, MemoryConfig, MoveFileSegment, NewFileSegment, PageNumber, Read,
ReadWriteAppend, SegmentHandle, SetFileSegmentDA, SwapIn, Unlock, UnlockFile],
Storage USING [String],
StreamDefs USING [GetCurrentKey, StartKeyHandler],
StringDefs USING [AppendChar, AppendString, BcplToMesaString, StringBoundsFault],
SwapperOps USING [FreePage, memConfig, PageStatus, Status, Update],
vmD: FROM "VirtualMgrDefs" USING [AllocateComposedMessageObject,
AllocateDisplayMessageObject, ComposedMessage, InitComposedMessage],
VMDefs USING [AllocatePage, CantOpen, InitializeVM, Page, Release],
VMSpecial USING [DisableClobberCatcher];

InitLaurel: PROGRAM
IMPORTS Core, csD, DiskKDDefs, disC: displayCommon, DMSTimeDefs, drD, dsD,
exD, FrameDefs, FrameOps, ImageDefs, inD, Inline, intC: intCommon,
KeyDefs, LaurelFontDefs, lsD, MiscDefs, NucleusOps, ProcessDefs, ProtocolDefs,
PupDefs, RetrieveDefs, SegmentDefs, Storage, StreamDefs, StringDefs, SwapperOps,
vmD, VMDefs, VMSpecial
EXPORTS drD, lsD
SHARES DiskKD, lsD = PUBLIC

BEGIN
OPEN drD;

-- variables and constants of the module

DisplayCleanupItem: ImageDefs.CleanupItem ←
[link: , mask: ImageDefs.CleanupMask[InLd]
+ ImageDefs.CleanupMask[OutLd]
+ ImageDefs.CleanupMask[Finish]
+ ImageDefs.CleanupMask[Abort],
proc: DisplayCleanup];

savedDCBptr: dsD.DCBptr; -- used to save DCB chain across debugger calls

enableClobberCatcher: BOOLEAN ← FALSE; -- settable from debugger
-- WARNING: enabling the clobber catcher makes worry-mode debugging impossible.
-- It also provokes a bug in versions of the Dolphin Alto/Mesa microcode
-- earlier than May 27, 1983.

ResumeNub: PORT
[commandInCommandLine: CommandLineAction, installError: InstallError];

-- procedures of the module


DisplayCleanup: ImageDefs.CleanupProcedure =
-- ensures a readable display when going in and out of Laurel.
BEGIN
dwtBankRegister: POINTER = LOOPHOLE[177740B + 11B];

SELECT why FROM
InLd => BEGIN
dsD.DCBorg↑ ← savedDCBptr;
IF ~disC.bitmapInMDS AND dsD.machineFlavor # dmachine
THEN dwtBankRegister↑ ← Inline.HighHalf[disC.bitMapPtr] * 4;
END;
OutLd, Finish, Abort =>
BEGIN
startTime: CARDINAL ← inD.realTimeClock↑;
savedDCBptr ← dsD.DCBorg↑;
dsD.DCBorg↑ ← dsD.DCBnil;
UNTIL inD.realTimeClock↑ - startTime >= 2 DO ENDLOOP;
IF ~disC.bitmapInMDS AND dsD.machineFlavor # dmachine
THEN dwtBankRegister↑ ← 0;
END;
ENDCASE => ERROR;
END; -- of DisplayCleanup --


AdjustForExtraMemory: PROCEDURE =
BEGIN
memConfig: SegmentDefs.MemoryConfig = SegmentDefs.memConfig;

-- The memory configuration is described by three variables, which interact in
-- complicated and subtle ways:
-- 1. memConfig.useXM is TRUE if the machine has extended memory and is
-- capable of executing Mesa code there (some Altos aren’t, because they
-- have the wrong ROMs).
-- 2. bitmapInMDS is TRUE if the display bitmap is in the MDS. This has a
-- large effect on what else can live in the MDS along with it. Storage
-- allocations based on "memory size" should depend on this variable.
-- 3. dsD.machineFlavor specifies details of the machine architecture that
-- control how DCBs and BBTs are parameterized for referencing XM.

dsD.machineFlavor ← SELECT memConfig.AltoType FROM
AltoIIXM => IF memConfig.mesaMicrocodeVersion = 39 THEN xmesa5 ELSE alto,
D0, Dorado => dmachine,
ENDCASE => alto;

-- If the machine is larger than 64K then we put the bitmap in extended memory,
-- regardless of whether or not we are also executing Mesa code in XM.
-- (This is a departure from older Laurels.)
disC.bitmapInMDS ← memConfig.banks=100000B;

ImageDefs.AddCleanupProcedure[@DisplayCleanupItem];
END; -- of AdjustForExtraMemory --


InitializeVM: PROCEDURE =
BEGIN
-- These values of vmPages and numOps for a 64K machine are not picked at random.
-- They are the absolute minimum that will work at all.
vmPagesFor64K: CARDINAL = 6;
vmPages: CARDINAL = IF disC.bitmapInMDS THEN vmPagesFor64K ELSE 50;
numOps: CARDINAL = IF disC.bitmapInMDS THEN 2 ELSE 15;

VMDefs.InitializeVM[min: MIN[vmPages, 10], max: vmPages, numOps: numOps];
IF ~enableClobberCatcher THEN VMSpecial.DisableClobberCatcher[];

-- In a 64K machine, cause all the VM buffers to be allocated now rather than
-- when they are needed, since there are so few of them that we know they will
-- all be needed eventually. This minimizes the likelihood of creating sandbars.
IF disC.bitmapInMDS THEN
BEGIN
pages: ARRAY [0..vmPagesFor64K) OF VMDefs.Page;
FOR i: CARDINAL IN [0..vmPagesFor64K) DO pages[i] ← VMDefs.AllocatePage[]; ENDLOOP;
FOR i: CARDINAL IN [0..vmPagesFor64K) DO VMDefs.Release[pages[i]]; ENDLOOP;
END;
END;


ScanCommandLine: PROCEDURE RETURNS [action: CommandLineAction] =
BEGIN
OPEN StringDefs;
fileName: STRING ← [inD.maxBracketStringLength];
sh: csD.StreamHandle;
char, switch: CHARACTER;
trouble, eof: BOOLEAN ← FALSE;
mailFileBracketsText: STRING = intC.mailFileBracketsHouse.text;

SkipBlanks: PROCEDURE =
BEGIN
IF eof THEN RETURN;
DO
char ← csD.Read[sh ! csD.EndOfStream => {eof ← TRUE; EXIT}];
IF char # Ascii.SP THEN RETURN;
ENDLOOP;
END; -- of SkipBlanks --

IF intC.leafOk AND intC.remoteFilePath # NIL THEN AppendString[fileName, "[]"L];
AppendString[fileName, "Active"L];
mailFileBracketsText.length ← 0;
AppendString[mailFileBracketsText, fileName];

action ← gmfOnly;
sh ← csD.OpenFromName["Com.cm"L, byte, read
! VMDefs.CantOpen => {trouble ← TRUE; CONTINUE}];
IF trouble THEN RETURN;

BEGIN -- for EXITS --
SkipBlanks[];
IF eof THEN GO TO Cleanup;
switch ← Ascii.SP;
DO
SELECT char FROM
’/ => switch ← csD.Read[sh ! csD.EndOfStream => GO TO Cleanup];
Ascii.SP, Ascii.CR => EXIT;
ENDCASE;
char ← csD.Read[sh ! csD.EndOfStream => {eof ← TRUE; EXIT}];
ENDLOOP;
SkipBlanks[];
fileName.length ← 0;
UNTIL eof DO
SELECT char FROM
Ascii.SP, Ascii.CR => EXIT;
ENDCASE =>
StringDefs.AppendChar[fileName, char ! StringDefs.StringBoundsFault => EXIT];
char ← csD.Read[sh ! csD.EndOfStream => {eof ← TRUE; EXIT}];
ENDLOOP;

SELECT switch FROM
’c, ’C => action ← checkOnly;
’n, ’N => action ← gnmAndStay;
’s, ’S => {action ← sendOnly; mailFileBracketsText.length ← 0};
’b, ’B => {action ← sendBug; mailFileBracketsText.length ← 0};
ENDCASE;

IF fileName.length = 0 THEN GO TO Cleanup;
mailFileBracketsText.length ← 0;
AppendString[mailFileBracketsText, fileName];
GO TO Cleanup;

EXITS
Cleanup => csD.Close[sh];
END; -- of EXITS block --
END; -- of ScanCommandLine


-- Pup Package Initialization


PupInitProcess: PROCEDURE =
BEGIN
IF disC.bitmapInMDS
THEN PupDefs.AdjustBufferParms[bufferPoolSize: 17, bufferSize: 64]
ELSE PupDefs.AdjustBufferParms[bufferPoolSize: 18, bufferSize: 140];
PupDefs.PupPackageMake[];
END; -- of PupInitProcess --

-- Font Initialization


SetUpFont: PROCEDURE =
BEGIN
OPEN SegmentDefs;
font: POINTER TO drD.ALFont;
fontFS: FileSegmentHandle;
fontDS: DataSegmentHandle;

[fontFS, ] ← MiscDefs.DestroyFakeModule[LOOPHOLE[LaurelFontDefs.LaurelFont]];
fontDS ← MakeDataSegment[DefaultBase, fontFS.pages, HardDown];
CopyFileToDataSegment[fontFS, fontDS];
font ← DataSegmentAddress[fontDS];
disC.mcFont ← @font.charTable;
IF dsD.lineHeight # font.height THEN exD.SysBug[];
END; -- of SetUpFont --


-- Memory Hacking


CleanUpAfterJim: PROCEDURE =
BEGIN
OPEN ControlDefs, FrameDefs, FrameOps, SegmentDefs;
swapperFrame: GlobalFrameHandle = GlobalFrame[MakeSwappedIn];
residentSeg: FileSegmentHandle = CodeHandle[swapperFrame];
page: AltoDefs.PageNumber;
firstUnlockedSeg: SegmentHandle;
memConfigPtr: POINTER TO SegmentDefs.MemoryConfig;

CheckAndUnlock: PROCEDURE[seg: FileSegmentHandle] RETURNS [BOOLEAN] =
BEGIN
IF seg.class = code AND seg ~= residentSeg AND seg.lock > 0
THEN Unlock[seg];
RETURN[FALSE]
END; -- of CheckAndUnlock --

-- Cleanup #1
[] ← EnumerateFileSegments[CheckAndUnlock];
-- do a dance to allow us to pack the Keyboard module into the resident
LockCode[GlobalFrame[KeyDefs.Keyboard]];
StreamDefs.StartKeyHandler[];
UnlockCode[GlobalFrame[KeyDefs.Keyboard]];
-- Cleanup #2
-- you don’t want to know why this is necessary...
-- (hint: look at the first few lines of MDSRegion.Update)
BEGIN
OPEN SwapperOps;
status: PageStatus;
ProcessDefs.DisableInterrupts[];
[firstUnlockedSeg, status] ←
Status[page ← (residentSeg.VMpage + residentSeg.pages)];
IF status = inuse THEN
{Update[page, 1, FreePage, TRUE]; Update[page, 1, firstUnlockedSeg, TRUE]};
ProcessDefs.EnableInterrupts[];
END;
-- Cleanup #3
memConfigPtr ← @SwapperOps.memConfig;
memConfigPtr.banks ← Inline.BITOR[memConfigPtr.banks, 100000B];
IF memConfigPtr.banks=100000B THEN memConfigPtr.useXM ← FALSE;
-- Cleanup #4
LockFile[LOOPHOLE[NucleusOps.DiskKD, POINTER TO FRAME[DiskKD]].diskKD.file];
END; -- of CleanUpAfterJim --


-- Install checker

GetWrittenTime: PROCEDURE[file: SegmentDefs.FileHandle]
RETURNS [time: AltoFileDefs.TIME] =
BEGIN
OPEN SegmentDefs;
seg: FileSegmentHandle ← NewFileSegment[file, 0, 1, Read];
leader: POINTER TO AltoFileDefs.LD;
SwapIn[seg];
leader ← FileSegmentAddress[seg];
time ← leader.written;
Unlock[seg];
DeleteFileSegment[seg];
END; -- of GetWrittenTime --


FPtoFileHandle: PROCEDURE [fp: AltoFileDefs.FP] RETURNS [SegmentDefs.FileHandle] =
INLINE
{RETURN[IF fp = AltoFileDefs.NullFP THEN NIL ELSE SegmentDefs.InsertFile[@fp]]};


BringInLaurelState: PROCEDURE
[heapDS: SegmentDefs.DataSegmentHandle, believeState: BOOLEAN]
RETURNS [worked: BOOLEAN] =
BEGIN
OPEN SegmentDefs;
stateFile: FileHandle = FPtoFileHandle[Core.LookupInFileCache["Laurel.state"L]];
stateHeaderSeg: FileSegmentHandle;
stateHeader: POINTER TO lsD.StateHeader;
imageFile: FileHandle = FrameOps.CodeHandle[FrameDefs.GlobalFrame[intC]].file;

worked ← FALSE;
IF stateFile = NIL THEN IF believeState THEN exD.SysBug[] ELSE RETURN;
stateHeaderSeg ← NewFileSegment[stateFile, 1, 1, Read];
SwapIn[stateHeaderSeg];
stateHeader ← FileSegmentAddress[stateHeaderSeg];
IF imageFile.fp = stateHeader.imageFP AND
GetWrittenTime[imageFile] = stateHeader.imageTime AND
heapDS.VMpage + heapDS.pages = stateHeader.cachedHeapTop THEN
BEGIN
profileFile: FileHandle = FPtoFileHandle[Core.LookupInFileCache
[IF stateHeader.profileInUserCm THEN "User.cm"L ELSE "Laurel.profile"L]];
fontsWidthsFile: FileHandle = FPtoFileHandle[Core.LookupInFileCache["Fonts.widths"L]];
IF believeState OR
(profileFile ~= NIL AND profileFile.fp = stateHeader.profileFP AND
GetWrittenTime[profileFile] = stateHeader.profileTime AND
fontsWidthsFile ~= NIL AND fontsWidthsFile.fp = stateHeader.fontsWidthsFP AND
GetWrittenTime[fontsWidthsFile] = stateHeader.fontsWidthsTime) THEN
BEGIN
headerPages: AltoDefs.PageCount = stateHeader.firstSegmentPage-1;

BringInHeap: PROCEDURE = INLINE
BEGIN
heapFS: FileSegmentHandle =
NewFileSegment[stateFile, stateHeader.heapSegFirstPage,
stateHeader.heapSegPages, Read];
pagesToFree: AltoDefs.PageCount = heapDS.pages-heapFS.pages;
IF pagesToFree ~= 0 THEN
BEGIN
IF LOOPHOLE[pagesToFree, INTEGER] < 0 THEN exD.SysBug[];
SwapperOps.Update[heapDS.VMpage, pagesToFree, SwapperOps.FreePage,
FALSE];
heapDS.VMpage ← heapDS.VMpage+pagesToFree;
heapDS.pages ← heapFS.pages;
END;
SetFileSegmentDA[heapFS, stateHeader.heapSegDA];
CopyFileToDataSegment[heapFS, heapDS];
DeleteFileSegment[heapFS];
END;
-- of BringInHeap --

FillInCodeSegmentDAs: PROCEDURE = INLINE
BEGIN
imageDAs: DESCRIPTOR FOR ARRAY [-1..0) OF AltoFileDefs.vDA =
DESCRIPTOR[lsD.SwapInStateSegment[stateHeader.imageDATableSeg],
stateHeader.imageDATableSeg.pages*AltoDefs.PageSize];

PlugHint: PROCEDURE[seg: FileSegmentHandle] RETURNS[BOOLEAN] =
BEGIN
IF seg.file = imageFile THEN
SetFileSegmentDA[seg, imageDAs[seg.base]];
RETURN[FALSE]
END; -- of PlugHint --

[] ← EnumerateFileSegments[PlugHint];
lsD.ReleaseStateSegment[stateHeader.imageDATableSeg];
END; -- of FillInCodeSegmentDAs --

bmInMDS: BOOLEAN ← disC.bitmapInMDS; -- preserve misplaced variable
worked ← TRUE;
Unlock[stateHeaderSeg];
MoveFileSegment[stateHeaderSeg, 1, headerPages];
SwapIn[stateHeaderSeg];
stateHeader ← FileSegmentAddress[stateHeaderSeg];
Inline.COPY
[to: @LOOPHOLE[intC, ControlDefs.GlobalFrameHandle].global[0],
from: stateHeader + stateHeader.intCOffset,
nwords: stateHeader.disCOffset - stateHeader.intCOffset];
Inline.COPY
[to: @LOOPHOLE[disC, ControlDefs.GlobalFrameHandle].global[0],
from: stateHeader + stateHeader.disCOffset,
nwords: stateHeader.headerFF - stateHeader.disCOffset];
disC.bitmapInMDS ← bmInMDS;
BringInHeap[];
lsD.InitializeSegments[stateHeader];
FillInCodeSegmentDAs[];
[] ← Core.InsertInFileCache[intC.imageFileName, imageFile.fp, TRUE];
LockFile[imageFile];
END;
END;
Unlock[stateHeaderSeg];
IF worked THEN LockFile[stateFile];
DeleteFileSegment[stateHeaderSeg];
END; -- of BringInLaurelState --


PreStopInitialization: PROCEDURE
RETURNS [commandInCommandLine: CommandLineAction, installError: InstallError] =
BEGIN
lookupIndex: CARDINAL;
heapDS: SegmentDefs.DataSegmentHandle;
heapPages: AltoDefs.PageCount = 8; -- should include a few extra pages in case
-- of long strings in Laurel.profile.
pupInitializer: PROCESS;
hardcopyHostString: STRING;
userNameString: STRING;
userPasswordString: STRING;
userRegistryString: STRING;
bcplStringHeader: TYPE =
MACHINE DEPENDENT RECORD [length: [0 .. 255], char: CHARACTER];
bcplStringPtr: TYPE = POINTER TO bcplStringHeader;

-- Initialization cursor

--iCursor: dsD.CursorBitMap ← ALL[0];
--pCounter: CARDINAL ← 0;

--DisplayInitializationPhase: PROCEDURE =
-- BEGIN
-- iCursor[pCounter MOD 16] ← 177777B;
-- Inline.COPY[@iCursor, 16, dsD.cursorBM];
-- pCounter ← pCounter + 3;
-- RETURN;
-- END;


iCursor: dsD.CursorBitMap ←
[177777B, 177077B, 077776B, 037774B, 017770B, 007760B, 003740B, 001700B,
001100B, 002440B, 004020B, 010410B, 020004B, 040402B, 100001B, 177777B];
sandArray: ARRAY [1 .. 15) OF CARDINAL
← [11, 12, 10, 8, 6, 4, 2, 2, 3, 6, 7, 10, 11, 14];
sandUsed: CARDINAL ← 0;
tick: CARDINAL ← 13;
totalTicks: CARDINAL = 13;
grains: CARDINAL = 53;


DisplayInitializationPhase: PROCEDURE =
BEGIN
incr: INTEGER;
n, m: CARDINAL;
topSlope: CARDINAL = 3;
bottomSlope: CARDINAL = 2;
cursor: POINTER TO PACKED ARRAY [0 .. 16 * 16) OF BOOLEAN ←
LOOPHOLE[@iCursor];

IF (tick ← tick + 1) > totalTicks THEN tick ← 0
ELSE
THROUGH [sandUsed .. MIN[tick * grains / totalTicks, grains]) DO
-- take a grain out of the top non-empty row of sand, favoring the middle.
FOR n DECREASING IN [2 .. 8) DO
IF sandArray[n] >= sandArray[n - 1] + topSlope THEN EXIT;
REPEAT FINISHED => FOR n IN [1 .. 8) DO
IF sandArray[n] # 0 THEN EXIT;
ENDLOOP;
ENDLOOP;
sandArray[n] ← sandArray[n] - 1;
m ← (n * 16) + 7;
incr ← 1;
UNTIL cursor[m] DO
m ← m + incr;
incr ← -incr + (IF incr < 0 THEN 1 ELSE -1);
ENDLOOP;
cursor[m] ← FALSE;

-- put a grain in one of the top non-empty rows of sand, favoring the
-- middle, and using the slope as a determinant of the sand stacking angle.
FOR n IN [8 .. 14) DO
IF sandArray[n] >= sandArray[n + 1] + bottomSlope THEN EXIT;
REPEAT
FINISHED =>
FOR n DECREASING IN [8 .. 15) DO
IF sandArray[n] # 0 THEN EXIT;
ENDLOOP;
ENDLOOP;
sandArray[n] ← sandArray[n] - 1;
m ← (n * 16) + 7;
incr ← 1;
WHILE cursor[m] DO
m ← m + incr;
incr ← -incr + (IF incr < 0 THEN 1 ELSE -1);
ENDLOOP;
cursor[m] ← TRUE;

sandUsed ← sandUsed + 1;
ENDLOOP;
dsD.cursorBM↑ ← iCursor;
END; -- of DisplayInitializationPhase --


AddFileRequests: PROCEDURE =
BEGIN
i: CARDINAL;
FOR i IN [0 .. nLookUps) DO
ImageDefs.AddFileRequest[@fileTable[i]]
ENDLOOP;
END; -- of AddFileRequests --


-- File Cache Pre-loading

-- Note: trailing "." on file names mandatory!

fileTable: ARRAY [0 .. 15) OF ImageDefs.FileRequest ←
[
[link: , file: NIL, access: SegmentDefs.ReadWriteAppend, name: "Laurel.state."L],
[link: , file: NIL, access: SegmentDefs.ReadWriteAppend, name: "DiskDescriptor."L],
[link: , file: NIL, access: SegmentDefs.Read, name: "COM.CM."L],
[link: , file: NIL, access: SegmentDefs.ReadWriteAppend, name: "Laurel.BugReport$."L],
[link: , file: NIL, access: SegmentDefs.Read, name: "Laurel.Profile."L],
[link: , file: NIL, access: SegmentDefs.Read, name: "User.Cm."L],
[link: , file: NIL, access: SegmentDefs.Read, name: "Fonts.widths."L],
[link: , file: NIL, access: SegmentDefs.ReadWriteAppend, name: "REM.CM."L],
[link: , file: NIL, access: SegmentDefs.ReadWriteAppend,
name: "DMS-99.TMP."L],
[link: , file: NIL, access: SegmentDefs.ReadWriteAppend,
name: "DMS-98.TMP."L],
[link: , file: NIL, access: SegmentDefs.ReadWriteAppend,
name: "DMS-97.TMP."L],
[link: , file: NIL, access: SegmentDefs.ReadWriteAppend,
name: "DMS-96.TMP."L],
[link: , file: NIL, access: SegmentDefs.ReadWriteAppend,
name: "Active.mail."L],
[link: , file: NIL, access: SegmentDefs.ReadWriteAppend,
name: "Active.mail-dmsTOC."L],
[link: , file: NIL, access: SegmentDefs.ReadWriteAppend, name: "Swatee."L]
];

nLookUps: CARDINAL = LENGTH[fileTable];
nOpen: CARDINAL = 2;


-- This was needed in order to cause Laurel to take over the interrupts usually
-- handled by the Resident’s InterruptProcess. However, we are now using a
-- special LaurelNucleus that has Laurel’s own InterruptProcess inside it,
-- so no special initialization is required any more.

-- SwitchInterruptProcesses: PROCEDURE =
-- BEGIN OPEN ProcessDefs;
-- save: Priority = GetPriority[];
-- START LOOPHOLE[FrameDefs.GlobalFrame[drD.InterruptProcess], PROGRAM];
-- SetTimeout[@drD.interruptWakeup, 1];
-- SetPriority[drD.interruptPriority];
-- Detach[FORK drD.InterruptProcess];
-- SetPriority[save];
-- ForgotOps.disableInterrupt ← TRUE;
-- END;


-- *** Main body of PreStopInitialization ***

-- Executed before the STOP in LaurelNub

AddFileRequests[];

DisplayInitializationPhase[]; -- 1 line in cursor

CleanUpAfterJim[];

-- Allocate state heap storage before variable length file lookups.
heapDS ← SegmentDefs.MakeDataSegment
[SegmentDefs.DefaultBase, heapPages, SegmentDefs.HardDown];

DisplayInitializationPhase[]; -- 2 lines in cursor

ResumeNub[sendBug, none];
-- Note: parameters are thrown away by LaurelNub

-- In this hiatus, Mesa will look up all files in the fileTable.

-- Executed after the STOP in LaurelNub

DisplayInitializationPhase[]; -- 3 lines in cursor

-- Set up BackStop

SDDefs.SD[SDDefs.sUncaughtSignal] ← Catcher;
PupDefs.CaptureErrors[CapturePupGlitch];

START disC;
START intC;
START dsD.Display;

DisplayInitializationPhase[]; -- 4 lines in cursor

-- Start the Pup package going, but don’t wait for it.

pupInitializer ← FORK PupInitProcess;
ProcessDefs.Yield[]; --let Pup initialization get started

DisplayInitializationPhase[]; -- 5 lines in cursor

AdjustForExtraMemory[];

InitializeVM[];

-- Now tell the file cache (actually the Alto directory cache)
-- about the files already looked-up.

FOR lookupIndex IN [0 .. nLookUps) DO
entry: POINTER TO ImageDefs.FileRequest ← @fileTable[lookupIndex];
IF entry.file = NIL THEN LOOP;
[] ← Core.InsertInFileCache[entry.name, entry.file.fp, lookupIndex < nOpen];
SegmentDefs.UnlockFile[entry.file];
ENDLOOP;

DisplayInitializationPhase[]; -- 6 lines in cursor


-- Now check if state information is current. If so, read it in. If not,
-- recompute and install it.

exD.InitializeExceptions[];

installError ← none;
IF ~BringInLaurelState[heapDS, FALSE] THEN
BEGIN
SetUpFont[];
installError ← lsD.CreateLaurelState[heapDS];

[] ← BringInLaurelState[heapDS, TRUE];
END
ELSE SetUpFont[];

exD.SetUpExceptionTable[];
-- SwitchInterruptProcesses[];
IF intC.editorType = modeless THEN
BEGIN
[] ← KeyDefs.ChangeKey[Spare1,
[FALSE, LOOPHOLE[Editor.cancelCode], LOOPHOLE[Editor.cancelCode]]];
[] ← KeyDefs.ChangeKey[Spare2,
[FALSE, LOOPHOLE[Editor.nextCode], LOOPHOLE[Editor.nextCode]]];
[] ← KeyDefs.ChangeKey[LF,
[FALSE, LOOPHOLE[Editor.insertDeletionCode],
LOOPHOLE[Editor.insertDeletionCode]]];
END;

DisplayInitializationPhase[]; -- 7 lines in cursor

-- Set up user name, registry, and password.

userNameString ← Storage.String
[LOOPHOLE[OsStaticDefs.OsStatics.UserName, bcplStringPtr].length];
StringDefs.BcplToMesaString[OsStaticDefs.OsStatics.UserName, userNameString];
FOR i: CARDINAL DECREASING IN [0 .. userNameString.length) DO
IF userNameString[i] = ’.
THEN BEGIN
userRegistryString ← Storage.String[userNameString.length- i-1];
FOR j: CARDINAL IN (i .. userNameString.length) DO
userRegistryString[j - i - 1] ← userNameString[j];
ENDLOOP;
userRegistryString.length ← MIN[userNameString.length - i - 1, 40];
userNameString.length ← i;
EXIT;
END;
REPEAT
FINISHED =>
BEGIN
userRegistryString ← Storage.String[intC.profileRegistry.length];
StringDefs.AppendString[userRegistryString, intC.profileRegistry];
END;
ENDLOOP;
userNameString.length
← MIN[userNameString.length, inD.maxBracketStringLength-userRegistryString.length - 1];
userPasswordString ← Storage.String
[LOOPHOLE[OsStaticDefs.OsStatics.UserPassword, bcplStringPtr].length];
StringDefs.BcplToMesaString[OsStaticDefs.OsStatics.UserPassword, userPasswordString];
intC.user ← Core.DMSUserBlk[userNameString, userRegistryString, userPasswordString];
Core.Login[@intC.user];
intC.userBracketsHouse.text.length ← 0;
StringDefs.AppendString[intC.userBracketsHouse.text, userNameString];
StringDefs.AppendChar[intC.userBracketsHouse.text, ’.];
StringDefs.AppendString[intC.userBracketsHouse.text, userRegistryString];

-- Set up hardcopy host name. To allow a variable host name, the permanent
-- name is allocated from the heap. The state string used originally for the
-- profile value is lost.

hardcopyHostString ← Storage.String[intC.hardcopyHost.length];
StringDefs.AppendString[hardcopyHostString, intC.hardcopyHost];
intC.hardcopyHost ← hardcopyHostString;

intC.keystream ← StreamDefs.GetCurrentKey[];

intC.tocTextNbr.toc ← NIL;
intC.cmTextNbr.message ← vmD.AllocateComposedMessageObject[];
vmD.InitComposedMessage[vmD.ComposedMessage[intC.cmTextNbr.message], ""L];
intC.cmTextNbr.insertionBuffer ← vmD.AllocateComposedMessageObject[];
vmD.InitComposedMessage[intC.cmTextNbr.insertionBuffer, ""L];
intC.cmTextNbr.deletionBuffer ← vmD.AllocateComposedMessageObject[];
vmD.InitComposedMessage[intC.cmTextNbr.deletionBuffer, ""L];
intC.dmTextNbr.message ← vmD.AllocateDisplayMessageObject[];

DisplayInitializationPhase[]; -- 8 lines in cursor

-- Parse the command line for switches, but don’t act on them yet.

commandInCommandLine ← ScanCommandLine[];
SELECT commandInCommandLine FROM
checkOnly, gnmAndStay => intC.audioEnabled ← FALSE;
ENDCASE => intC.audioEnabled ← (intC.newMailTune # NIL);

DisplayInitializationPhase[]; -- 9 lines in cursor

-- Now synchronize with Pup initialization

JOIN pupInitializer;

DisplayInitializationPhase[]; -- 10 lines in cursor

DMSTimeDefs.SetLaurelTime[];
IF intC.gvTestingMode THEN ProtocolDefs.SetTestingMode[];
IF intC.profileRetrieve # NIL THEN
RetrieveDefs.SetMTPRetrieveDefault[intC.profileRetrieve, intC.profileRegistry];
intC.retrieveHandle ←
RetrieveDefs.Create[intC.mailcheckPollingInterval, inD.ReportMBXState];
RetrieveDefs.NewUser[intC.retrieveHandle, intC.userBracketsHouse.text, userPasswordString];
inD.SetTime[];

DisplayInitializationPhase[]; -- 11 lines in cursor

ProcessDefs.Yield[]; -- to let EtherProbe continue
[] ← DiskKDDefs.CloseDiskKD[]; -- Blow the DiskDescriptor out

DisplayInitializationPhase[]; -- 12 lines in cursor

--dsD.SetCursor[hourGlass];

FrameOps.SetReturnLink[LOOPHOLE[ResumeNub, ControlDefs.Port].dest];

END; -- of PreStopInitialization --


END. -- of InitLaurel --