BasicLoader.mesa, stolen from McGregor, May 4, 1982 11:09 am
Last Modified By Paul Rovner On June 9, 1982 9:51 am
last modified by Levin on November 23, 1982 2:52 pm
DIRECTORY
Ascii USING [CR],
CedarInitPrivate USING [],
DCSFileTypes USING [tLeaderPage],
Directory USING [Lookup],
File USING [Capability, GetAttributes, Type, nullCapability],
FileStream USING [EndOf, Create],
Heap USING [systemMDSZone],
Loader USING [Instantiate, Start, Error],
LongString USING [AppendString, UpperCase],
PrincOps USING [ControlModule, NullControl],
Runtime USING [CallDebugger],
SpecialTerminal USING [GetProc, PutProc, TurnOff, TurnOn],
Stream USING [Delete, GetChar, Handle];
BasicLoader: PROGRAM
IMPORTS Directory, File, FileStream, Heap, Loader, LongString, Runtime, SpecialTerminal,
Stream
EXPORTS CedarInitPrivate
= BEGIN
getChar: SpecialTerminal.GetProc;
putChar: SpecialTerminal.PutProc;
ttyDisabled: BOOLEANFALSE;
PutChar: PROC [c: CHAR] = {
IF ttyDisabled THEN RETURN;
putChar[c];
};
PutString: PROC [s: LONG STRING] = {
IF ttyDisabled THEN RETURN;
FOR i: CARDINAL IN [0..s.length) DO putChar[s[i]]; ENDLOOP;
};
PutLine: PROC [s: LONG STRING] = {
IF ttyDisabled THEN RETURN;
FOR i: CARDINAL IN [0..s.length) DO putChar[s[i]]; ENDLOOP;
putChar[Ascii.CR];
};
commandFile: Stream.Handle ← NIL;
GetFileAndSwitches: PROC[file: LONG POINTER TO TEXT]
RETURNS [callDebug: BOOLFALSE, links: BOOLTRUE, disableTTY: BOOLFALSE] = {
switchPos: INT;
findString: STRING;
GetToken[file];
IF file.length = 0 THEN RETURN;
findString ← "/"L;
switchPos ← Find[file, LOOPHOLE[LONG[findString]], 0];
IF switchPos >= 0 THEN {
look for "d", "l" and "t" switches; others are ignored.
Bare switch (e.g. " /e" causes termination
findString ← "-d"L;
IF Find[file, LOOPHOLE[LONG[findString]], switchPos] < 0 THEN
{findString ← "d"L;
IF Find[file, LOOPHOLE[LONG[findString]], switchPos] > 0
THEN callDebug ← TRUE};
findString ← "-l"L;
IF Find[file, LOOPHOLE[LONG[findString]], switchPos] < 0 THEN
{findString ← "l"L;
IF Find[file, LOOPHOLE[LONG[findString]], switchPos] > 0
THEN links ← TRUE};
findString ← "-t"L;
IF Find[file, LOOPHOLE[LONG[findString]], switchPos] < 0 THEN
{findString ← "t"L;
IF Find[file, LOOPHOLE[LONG[findString]], switchPos] > 0
THEN disableTTY ← TRUE};
file.length ← switchPos;
};
};
Find returns position in s1 where s2 occurs (starts looking at pos1)
returns -1 if not found. Ignores case.
Find: PROC[s1, s2: LONG POINTER TO TEXT, pos1: INT ← 0] RETURNS[ans: INT ← -1] = {
FOR i: NAT IN [pos1..s1.length) DO
match: BOOLTRUE;
FOR j: NAT IN [0..s2.length) DO
IF (i+j >= s1.length) OR (LongString.UpperCase[s1[i+j]] # LongString.UpperCase[s2[j]])
THEN {match ← FALSE; EXIT};
ENDLOOP;
IF match THEN RETURN[i];
ENDLOOP;
};
GetToken: PROC[token: LONG POINTER TO TEXT] = {
c: CHARACTER ← ' ;
Sep: PROC [c: CHARACTER] RETURNS [BOOL] =
{RETURN[SELECT c FROM ' , ',, 11C, 15C, 0C => TRUE, ENDCASE => FALSE]};
token.length ← 0;
IF FileStream.EndOf[commandFile] THEN RETURN;
WHILE ~FileStream.EndOf[commandFile] AND Sep[c ← Stream.GetChar[commandFile]] DO
ENDLOOP;
token[token.length] ← c; token.length ← token.length + 1;
DO IF FileStream.EndOf[commandFile] THEN EXIT;
IF Sep[c ← Stream.GetChar[commandFile]] THEN EXIT;
token[token.length] ← c; token.length ← token.length + 1;
ENDLOOP;
};
RunTestFiles: PROC = {
callDebug, links, disableTTY: BOOL;
file: STRING = [40];
TryToRun: PROC = {
fcap: File.Capability ← File.nullCapability;
type: File.Type;
prog: PrincOps.ControlModule ← PrincOps.NullControl;
loadFailed: BOOLEANFALSE;
PutString["Looking for "L]; PutLine[file];
fcap ← Directory.Lookup[fileName: file ! ANY => CONTINUE];
IF fcap = File.nullCapability THEN
{PutString["Failed to find file named "L]; PutLine[file]; RETURN}
ELSE {
unboundImports: BOOLEANFALSE;
type ← File.GetAttributes[fcap].type;
PutString["Loading "L]; PutLine[file];
[cm: prog, unboundImports: unboundImports] ← Loader.Instantiate[
fcap, IF type=DCSFileTypes.tLeaderPage THEN 1 ELSE 0, links
! Loader.Error => {
prefix: STRING = "Error loading "L;
code: STRING
SELECT type FROM
invalidBcd => "invalidBcd"L,
fileNotFound => "fileNotFound"L,
versionMismatch => "versionMismatch"L,
loadStateFull => "loadStateFull"L,
insufficientVM => "insufficientVM"L,
ENDCASE => NIL; -- can't happen
msg: STRING ← Heap.systemMDSZone.NEW[StringBody[
prefix.length + file.length + 2 + code.length +
(IF message = NIL THEN 0 ELSE message.length + 2)]];
LongString.AppendString[msg, prefix]; LongString.AppendString[msg, file];
LongString.AppendString[msg, ": "L];
LongString.AppendString[msg, code];
IF message ~= NIL THEN {
LongString.AppendString[msg, ", "L];
LongString.AppendString[msg, LOOPHOLE[message]];
};
Runtime.CallDebugger[msg];
Heap.systemMDSZone.FREE[@msg];
loadFailed ← TRUE;
CONTINUE};
ANY => {loadFailed ← TRUE; CONTINUE}
];
IF NOT loadFailed AND unboundImports THEN
PutLine[" ***there are unbound imports***"L];
};
IF callDebug OR loadFailed THEN {
s: STRING ← [60];
IF loadFailed THEN
LongString.AppendString[s, "BasicLoader just failed to load: "L]
ELSE LongString.AppendString[s, "BasicLoader just loaded: "L];
LongString.AppendString[s, file];
Runtime.CallDebugger[s];
};
IF prog # PrincOps.NullControl THEN
{PutString["Starting "L]; PutLine[file]; Loader.Start[prog]};
};
DO
findString: STRING = ".bcd"L;
[callDebug, links, disableTTY] ← GetFileAndSwitches[LOOPHOLE[LONG[file]]];
IF disableTTY THEN {ttyDisabled ← TRUE; SpecialTerminal.TurnOff[]};
IF ttyDisabled THEN disableTTY ← TRUE;
IF file.length=0 THEN EXIT;
IF Find[LOOPHOLE[LONG[file]], LOOPHOLE[LONG[findString]], 0] < 0 THEN
LongString.AppendString[file, findString];
TryToRun[];
ENDLOOP;
};
DoLoading: PUBLIC PROC = {
commandFileName: STRING = "BasicLoadees.cm"L;
commandFile ←
FileStream.Create[capability: Directory.Lookup[fileName: commandFileName ! ANY => CONTINUE]];
[get: getChar, put: putChar] ← SpecialTerminal.TurnOn[];
IF commandFile = NIL
THEN {
PutString["No "L]; PutLine[commandFileName];
ttyDisabled ← TRUE; -- leave message on screen
}
ELSE {RunTestFiles[]; Stream.Delete[commandFile]};
IF NOT ttyDisabled THEN SpecialTerminal.TurnOff[];
};
END.