-- file: InitLaurel.mesa
-- edited by: Schroeder, March 14, 1981 12:47 PM.
-- edited by Brotz, May 4, 1981 1:26 PM
-- edited by Levin, May 4, 1981 12:09 PM

DIRECTORY
AltoDefs,
AltoFileDefs,
Ascii,
ControlDefs,
crD: FROM "CoreDefs",
DiskKD,
DiskKDDefs,
displayCommon: FROM "DisplayCommon",
DMSTimeDefs,
drD: FROM "LaurelDriverDefs",
dsD: FROM "DisplayDefs",
Editor,
exD: FROM "ExceptionDefs",
ForgotOps,
FrameDefs,
FrameOps,
gsD: FROM "GlobalStorageDefs",
ImageDefs,
inD: FROM "InteractorDefs",
Inline,
intCommon: FROM "IntCommon",
KeyDefs,
LaurelFontDefs,
lsD: FROM "LaurelStateDefs",
MiscDefs,
NucleusOps,
OsStaticDefs,
ovD: FROM "OverviewDefs",
ProcessDefs,
ProtocolDefs,
PupDefs,
Region,
RetrieveDefs,
SDDefs,
SegmentDefs,
Storage,
StreamDefs,
StringDefs,
SwapperOps,
tsD: FROM "TOCSelectionDefs",
vmD: FROM "VirtualMgrDefs";

InitLaurel: PROGRAM
IMPORTS crD, DiskKDDefs, disC: displayCommon, DMSTimeDefs, drD, dsD,
exD, ForgotOps, FrameDefs, FrameOps, gsD, ImageDefs, inD, Inline,
intC: intCommon, KeyDefs, LaurelFontDefs, lsD, MiscDefs, NucleusOps, ProcessDefs,
ProtocolDefs, PupDefs, RetrieveDefs, SegmentDefs, Storage, StreamDefs,
StringDefs, SwapperOps, tsD, vmD
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


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

SELECT why FROM
InLd => dsD.DCBorg↑ ← savedDCBptr;
OutLd, Finish, Abort =>
BEGIN
startTime: CARDINAL ← inD.realTimeClock↑;
savedDCBptr ← dsD.DCBorg↑;
dsD.DCBorg↑ ← dsD.DCBnil;
UNTIL inD.realTimeClock↑ - startTime >= 2 DO ENDLOOP;
END;
ENDCASE => ERROR;
END; -- of DisplayCleanup --


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

SELECT memConfig.AltoType FROM
AltoIIXM =>
BEGIN
IF memConfig.banks = 100000B THEN RETURN;
IF memConfig.useXM THEN gsD.DisableFlusher[];
END;
D0, Dorado =>
BEGIN
gsD.DisableFlusher[];
ImageDefs.AddCleanupProcedure[@DisplayCleanupItem];
END;
ENDCASE => RETURN;
END; -- of AdjustForExtraMemory --


ScanCommandLine: PROCEDURE RETURNS[action: CommandLineAction] =
BEGIN
OPEN StringDefs;
error: ovD.ErrorCode;
buffer: gsD.MemoryPagePtr;
bufferS: STRING;
count: CARDINAL;
i: CARDINAL;
fileName: STRING ← [inD.maxBracketStringLength];
fileH: crD.UFileHandle;
switch: CHARACTER;
SP: CHARACTER = ’ ;
CR: CHARACTER = 015C;

SkipBlanks: PROCEDURE =
BEGIN
WHILE i < count DO
IF bufferS[i] # SP THEN RETURN;
i ← i+1;
ENDLOOP;
END; -- of SkipBlanks --

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

action ← gmfOnly;
[error, fileH] ← crD.OpenFile[intC.user, "Com.cm"L, read];
IF error # ovD.ok THEN RETURN;
buffer ← gsD.GetMemoryPages[1];
bufferS ← LOOPHOLE[buffer - 2, STRING];

BEGIN -- inner "block"
[error, count] ← crD.ReadPages[buffer, 512, 0, fileH];
IF error # ovD.ok THEN exD.SysBug[];

BEGIN -- parse and discriminate switch
bufferS[MIN[count, 511]] ← SP;
i ← 0;
SkipBlanks[];
IF i = count THEN GO TO Cleanup;
switch ← SP;
FOR i IN [i .. count) DO
SELECT bufferS[i] FROM
’/ => switch ← bufferS[i+1];
SP, CR => EXIT;
ENDCASE;
ENDLOOP;
SkipBlanks[];
fileName.length ← 0;
WHILE i < count DO
SELECT bufferS[i] FROM
SP, CR => EXIT;
ENDCASE =>
BEGIN
StringDefs.AppendChar[fileName, bufferS[i]
! StringDefs.StringBoundsFault => GO TO Done];
i ← i+1;
END;
REPEAT
Done => NULL;
ENDLOOP;

SELECT switch FROM
’c,’C => action ← checkOnly;
’n,’N => action ← gnmAndStay;
’s,’S => BEGIN action ← sendOnly; GO TO ZapGMFBracketsHouse; END;
’b,’B => BEGIN action ← sendBug; GO TO ZapGMFBracketsHouse; END;
ENDCASE;
EXITS
ZapGMFBracketsHouse => intC.mailFileBracketsHouse.text.length ← 0;
END; -- parse and discriminate switch

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

EXITS
Cleanup => error ← crD.CloseFile[fileH];
END; -- of inner "block"

gsD.ReturnMemoryPages[1, buffer];
END; -- of ScanCommandLine


-- Pup Package Initialization


PupInitProcess: PROCEDURE =
BEGIN
IF SegmentDefs.memConfig.useXM
THEN PupDefs.AdjustBufferParms[bufferPoolSize: 18, bufferSize: 140]
ELSE PupDefs.AdjustBufferParms[bufferPoolSize: 17, bufferSize: 64];
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];
-- 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 --


BringInLaurelState: PROCEDURE
[heapDS: SegmentDefs.DataSegmentHandle, believeState: BOOLEAN]
RETURNS [worked: BOOLEAN] =
BEGIN
OPEN SegmentDefs;
stateFile: FileHandle = crD.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 =
crD.LookupInFileCache[IF stateHeader.profileInUserCm THEN "User.cm"L
ELSE "Laurel.profile"L];
fontsWidthsFile: FileHandle = crD.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 --

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];
BringInHeap[];
lsD.InitializeSegments[stateHeader];
FillInCodeSegmentDAs[];
crD.InsertInFileCache[intC.imageFileName, imageFile];
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

nLookUps: CARDINAL = 15;

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

fileTable: ARRAY [0 .. nLookUps) OF ImageDefs.FileRequest ←
[[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.ReadWriteAppend, name: "Laurel.state."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],
[link: , file: NIL, access: SegmentDefs.Read, name: "SysDir."L]];


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; -- of SwitchInterruptProcesses --


-- *** 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


-- 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;
crD.InsertInFileCache[entry.name, entry.file];
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 ← crD.DMSUser[userNameString, userRegistryString, userPasswordString];
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.cmTextNbr.message ← vmD.AllocateComposeMessageObject[];
vmD.SetBufferPoolSize[intC.cmTextNbr.message, Editor.composedMessagePages];
vmD.InitComposeMessage
[vmD.MapVirtualToComposeMessage[intC.cmTextNbr.message], ""L];
intC.cmTextNbr.insertionBuffer ← vmD.AllocateComposeMessageObject[];
vmD.SetBufferPoolSize[intC.cmTextNbr.insertionBuffer, Editor.insertionBufferPages];
vmD.InitComposeMessage[intC.cmTextNbr.insertionBuffer, ""L];
intC.cmTextNbr.deletionBuffer ← vmD.AllocateComposeMessageObject[];
vmD.SetBufferPoolSize[intC.cmTextNbr.deletionBuffer, Editor.deletionBufferPages];
vmD.InitComposeMessage[intC.cmTextNbr.deletionBuffer, ""L];
intC.dmTextNbr.message ← vmD.AllocateDisplayMessageObject[];

tsD.ResetTOCSelection[];

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

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

DisplayInitializationPhase[]; -- 12 lines in cursor

--dsD.SetCursor[hourGlass];

AdjustForExtraMemory[];

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

END; -- of PreStopInitialization --


END. -- of InitLaurel --