PrinterLoaderDriverImpl.mesa
Copyright Ó 1984, 1985, 1986, 1987 by Xerox Corporation. All rights reserved.
Tim Diebert: March 6, 1987 10:58:26 am PST
Loader driver for running programs on top of the printer boot file.
DIRECTORY
Ascii USING [BS, ControlA, ControlQ, ControlW, ControlX, CR, DEL, Digit, Letter, LF, SP, TAB],
Booting USING [switches],
DebuggerSwap USING [CallDebugger],
FS USING [Error, ErrorDesc, GetInfo, Open, OpenFile, StreamOpen],
FSExtras USING [DoInWDir],
IO USING [STREAM, BreakProc, Close, EndOfStream, EraseChar, GetChar, GetTokenRope, PutChar, PutF, PutF1, PutRope, int, rope, time],
Loader USING [Error, ErrorType, Instantiate, IRItem, Start],
PrincOps USING [ControlModule, NullControl],
PrinterNames USING [DefaultNames, Get],
Rope USING [Cat, Concat, Equal, Fetch, Find, FromChar, IsEmpty, Length, ROPE, Substr ],
SimpleTerminal USING [TurnOff, TurnOn],
SystemNames USING [LocalDir];
PrinterLoaderDriverImpl: CEDAR PROGRAM
IMPORTS Ascii, Booting, DebuggerSwap, FS, FSExtras, IO, Loader, PrinterNames, Rope, SimpleTerminal, SystemNames
= BEGIN
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
in: STREAM;
out: STREAM;
GetFileStr: PROC[cmName: ROPE] RETURNS[IO.STREAM] = {
RETURN[ FS.StreamOpen[cmName] ];
};
MyBreak: IO.BreakProc = {
SELECT char FROM
Ascii.SP, Ascii.CR, Ascii.TAB, Ascii.LF, ', => RETURN[sepr];
'/ => RETURN[break];
ENDCASE => RETURN[other];
};
GetToken: PROC [stream: IO.STREAM] RETURNS[token: ROPENIL] = {
token ← IO.GetTokenRope[stream, MyBreak !IO.EndOfStream => CONTINUE].token;
};
PutFSError: PROC [out: STREAM, error: FS.ErrorDesc] = {
IF error.code=$unknownFile THEN out.PutRope[" not found"]
ELSE out.PutF[" failed\n FS.Error: %g", IO.rope[error.explanation]];
};
RequiredRope: TYPE ~ ROPE
RopeFromErrorTypeArray: TYPE ~ ARRAY Loader.ErrorType OF RequiredRope;
ropeFromErrorType: REF RopeFromErrorTypeArray ~ NEW[RopeFromErrorTypeArray ← [
invalidBcd: "invalidBcd",
fileNotFound: "fileNotFound",
versionMismatch: "versionMismatch",
loadStateFull: "loadStateFull",
insufficientVM: "insufficientVM"
]];
PutLoaderError: PROC [out: STREAM, type: Loader.ErrorType, message: ROPE] = {
out.PutF1[" failed\n Loader.Error[%g", IO.rope[ropeFromErrorType[type]]];
IF Rope.IsEmpty[message] THEN out.PutRope["]"]
ELSE out.PutF1[", \"%g\"]", IO.rope[message]];
};
Loadee: TYPE = RECORD [
rest: REF Loadee ← NIL,
name: ROPENIL,
cm: PrincOps.ControlModule ← PrincOps.NullControl,
codeLinks: BOOLTRUE,
callDebugger: BOOLFALSE
];
TryFile: PROC[cmName: ROPE] RETURNS[done: BOOLTRUE] = {
fileStr: IO.STREAM;
loadees: REF Loadee ← NIL;
last: REF Loadee ← NIL;
loadFailed: BOOLFALSE;
nextToken: ROPENIL;
out.PutF1["\nTrying \"%g\" ...", IO.rope[cmName]];
fileStr ← GetFileStr[cmName ! FS.Error => { PutFSError[out, error]; GOTO failed }];
out.PutRope[" ok\nParsing the command file ..."];
DO -- parse input for each loadee
this: REF Loadee ← NEW[Loadee ← [] ];
end: BOOLFALSE;
swSep: ROPE = "/";
IF nextToken = NIL THEN IF (nextToken ← GetToken[fileStr]) = NIL THEN EXIT;
IF nextToken.Equal[swSep]
THEN end ← TRUE
ELSE {
IF last = NIL THEN loadees ← this ELSE last.rest ← this;
last ← this;
this.name ← nextToken;
IF this.name.Find["."] < 0 THEN this.name ← this.name.Cat[".bcd"];
nextToken ← GetToken[fileStr];
};
IF nextToken.Equal[swSep] THEN {
positive: BOOLTRUE;
nextToken ← GetToken[fileStr];
FOR i: NAT IN NAT[0..nextToken.Length[]) DO
SELECT nextToken.Fetch[i] FROM
'-, '~ => { positive ← FALSE; LOOP };
'l, 'L => this.codeLinks ← positive;
'd, 'D => this.callDebugger ← positive;
'e, 'E => end ← positive;
ENDCASE => NULL;
positive ← TRUE
ENDLOOP;
nextToken ← NIL;
};
IF end THEN EXIT;
ENDLOOP;
out.PutRope[" ok"];
IO.Close[fileStr];
FOR this: REF Loadee ← loadees, this.rest UNTIL this = NIL DO
load them
BEGIN
thisFile: FS.OpenFile;
fullFName, attachedTo: ROPENIL;
unbound: LIST OF Loader.IRItem;
DO
out.PutF1["\nLoading %g ...", IO.rope[this.name]];
thisFile ← FS.Open[this.name
! FS.Error => {
PutFSError[out, error];
IF Confirm["\n Should this file be tried again? "] THEN LOOP;
GOTO thisFailed;
} ];
EXIT;
ENDLOOP;
THROUGH [Rope.Length[this.name]..64) DO out.PutChar['.] ENDLOOP;
out.PutF[" %u ...", IO.time[FS.GetInfo[thisFile].created]];
IF NOT this.codeLinks THEN out.PutRope[" (frame links)"];
TRUSTED{[cm: this.cm, unboundImports: unbound] ←
Loader.Instantiate[file: thisFile, codeLinks: this.codeLinks !
FS.Error => { PutFSError[out, error]; GOTO thisFailed };
Loader.Error => { PutLoaderError[out, type, message]; GOTO thisFailed }
]};
out.PutRope[" ok"];
IF unbound # NIL THEN {
out.PutRope["\n (Unbound imports: "];
FOR l: LIST OF Loader.IRItem ← unbound, l.rest UNTIL l = NIL DO
out.PutF["[%g,%g] ", IO.rope[l.first.interfaceName], IO.int[l.first.index]];
ENDLOOP;
out.PutRope[")"];
};
EXITS thisFailed => loadFailed ← TRUE;
END;
ENDLOOP;
IF Booting.switches[five] THEN DebuggerSwap.CallDebugger["Key stop 5"L];
IF loadFailed
THEN out.PutRope["\nThere were loading errors. I'm giving up."]
ELSE {
FOR this: REF Loadee ← loadees, this.rest UNTIL this = NIL DO
start them
IF this.callDebugger
THEN TRUSTED{DebuggerSwap.CallDebugger["/d switch in basic loadees"]};
out.PutF1["\nStarting \"%g\" ... ", IO.rope[this.name] ];
TRUSTED{Loader.Start[this.cm]};
out.PutRope["ok"];
ENDLOOP;
out.PutRope["\nEnd of the command file"];
SimpleTerminal.TurnOff[];
};
EXITS failed => done ← FALSE;
};
OptionalCommand: PROC
[condition, prompt, default: ROPE, work: PROC[ROPE] RETURNS[BOOL]] RETURNS[BOOL] = {
"GetID" copied from UserCredentialsImpl
Rubout: ERROR = CODE;
GetID: PROC [default: ROPE, echo: BOOLTRUE] RETURNS [id: ROPE] = {
OPEN Ascii;
firstTime: BOOLTRUE;
c: CHAR;
EraseAll: PROC = {
IF echo THEN
FOR i: INT DECREASING IN [0..id.Length[]) DO out.EraseChar[id.Fetch[i]]; ENDLOOP;
id ← NIL;
};
Done: PROC [c: CHAR] RETURNS [BOOL] = INLINE {
IF firstTime THEN {
SELECT c FROM
ControlA, BS, ControlQ, ControlW, ControlX, CR, SP, DEL => NULL;
ENDCASE => EraseAll[];
firstTime ← FALSE;
};
RETURN[c = SP OR c = CR]
};
id ← default;
IF echo THEN out.PutRope[default];
c ← in.GetChar[];
UNTIL Done[c] DO
SELECT c FROM
DEL => ERROR Rubout;
ControlA, BS => {
len: INT ← id.Length[];
IF len > 0 THEN {
len ← len - 1;
IF echo THEN out.EraseChar[id.Fetch[len]];
id ← id.Substr[len: len];
};
};
ControlW, ControlQ => {
text to be backed up is of the form ...<non-alpha><alpha><non-alpha>, the <alpha> and following <non-alpha> are to be removed.
alpha: BOOLFALSE;
FOR i: INT DECREASING IN [0..id.Length[]) DO
ch: CHAR = id.Fetch[i];
IF Ascii.Letter[ch] OR Ascii.Digit[ch] THEN alpha ← TRUE
ELSE IF alpha THEN {id ← id.Substr[len: i + 1]; EXIT};
IF echo THEN out.EraseChar[ch];
REPEAT
FINISHED => id ← NIL;
ENDLOOP;
};
ControlX => EraseAll[];
ENDCASE => {id ← id.Concat[Rope.FromChar[c]]; IF echo THEN out.PutChar[c]};
c ← in.GetChar[];
ENDLOOP;
};
arg: ROPE ← default;
DO out.PutRope[condition];
SELECT in.GetChar[] FROM
'y, 'Y, '\n =>
BEGIN
out.PutRope[" yes"];
DO BEGIN
ENABLE Rubout => { out.PutRope[" XXX"]; EXIT };
out.PutChar['\n]; out.PutRope[prompt]; out.PutRope[": "];
arg ← GetID[arg];
IF work[arg] THEN RETURN[TRUE];
END
ENDLOOP;
END;
'n, 'N => { out.PutRope[" no"]; RETURN[FALSE] };
ENDCASE => out.PutRope["\nPlease respond with \"Y\" or \"N\""];
ENDLOOP;
};
Confirm: PROC [question: ROPE] RETURNS [BOOL] = {
DO
out.PutRope[question];
SELECT in.GetChar[] FROM
'y, 'Y, '\n => {
out.PutRope[" yes"];
RETURN[TRUE];
};
'n, 'N => {
out.PutRope[" no"];
RETURN[FALSE];
};
ENDCASE => out.PutRope["\nPlease respond with \"Y\" or \"N\""];
ENDLOOP;
};
systemDir: ROPE ~ SystemNames.LocalDir["System"]; -- for example, "[]<>7.0>System>"
Main: PROC = {
remoteNames: PrinterNames.DefaultNames = PrinterNames.Get[];
loadees: ROPE = Rope.Concat[remoteNames.printerType, "Printer.loadees"];
IF Booting.switches[l] AND OptionalCommand[
"\nDo you want to specify an explicit \"Loadees\" command file? ",
"Command file name", systemDir.Concat[loadees], TryFile]
THEN NULL
ELSE {
out.PutF1["\nLooking for a \"%g\" command file.", IO.rope[loadees]];
IF TryFile[Rope.Cat[remoteNames.currentSystem, loadees]]
THEN NULL
ELSE out.PutRope["\nCan't find any command file."];
};
};
[in: in, out: out] ← SimpleTerminal.TurnOn[];
out.PutRope["\nThis is the Printer boot file.\n"];
FSExtras.DoInWDir[systemDir, Main];
END.