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: ROPE _ NIL] = { 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: ROPE _ NIL, cm: PrincOps.ControlModule _ PrincOps.NullControl, codeLinks: BOOL _ TRUE, callDebugger: BOOL _ FALSE ]; TryFile: PROC[cmName: ROPE] RETURNS[done: BOOL _ TRUE] = { fileStr: IO.STREAM; loadees: REF Loadee _ NIL; last: REF Loadee _ NIL; loadFailed: BOOL _ FALSE; nextToken: ROPE _ NIL; 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: BOOL _ FALSE; 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: BOOL _ TRUE; 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 BEGIN thisFile: FS.OpenFile; fullFName, attachedTo: ROPE _ NIL; 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 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] = { Rubout: ERROR = CODE; GetID: PROC [default: ROPE, echo: BOOL _ TRUE] RETURNS [id: ROPE] = { OPEN Ascii; firstTime: BOOL _ TRUE; 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 => { alpha: BOOL _ FALSE; 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. ž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. load them start them "GetID" copied from UserCredentialsImpl text to be backed up is of the form ..., the and following are to be removed. Κ *˜codešœ™KšœN™NK™*—K˜KšœC™CK™šΟk ˜ Kšœœœ*œœœœœ˜^Kšœœ ˜Kšœ œ˜"Kšœœ9˜AKšœ œ ˜Kšœœœs˜ƒKšœœ0˜œ ˜WKšœœ˜'Kšœ œ ˜—K˜šΠlnœœ˜&Kšœœ œ9˜oKšœ˜K˜Kšœœœ˜Kšœœœœ˜K˜Kšœœ˜ Kšœœ˜ K˜š Οn œœ œœœœ˜5Kšœ˜ Kšœ˜—K˜šΟbœœ˜šœ˜Kš œœœœœœ˜Kšœ ˜Kšœ˜——Kšœ˜Kšœ˜—Kšœœœ˜@Kšœœœ˜;Kšœœœ˜9šœ)˜0šœ>˜>Kšœ$œ˜8Kšœ6œ ˜GKšœ˜——K˜šœ œœ˜Kšœ&˜&š œœœ!œœ˜?Kšœœœ˜LKšœ˜—Kšœ˜Kšœ˜—Kšœœ˜&Kšœ˜—Kšœ˜—Kšœœ*˜Hšœ ˜ Kšœ<˜@šœ˜š œœœœ˜=Kšœ ™ šœ˜Kšœœ:˜F—Kšœ$œ˜9Kšœ˜K˜Kšœ˜—K˜)Kšœ˜Kšœ˜——Kšœœ˜Kšœ˜—K˜šŸœ˜Kšœœœœœœœœ˜TKšœ'™'Kšœœœ˜šŸœœ œœœœœ˜EKšœ˜ Kšœ œœ˜Kšœœ˜šŸœœ˜šœ˜ Kš œœ œœœœ˜Q—Kšœœ˜ K˜—š Ÿœœœœœœ˜.šœ œ˜šœ˜ Kš œ œ œœœœ˜@Kšœ˜—Kšœ œ˜Kšœ˜—Kšœœœœ˜K˜—K˜ Kšœœ˜"Kšœ˜šœ ˜šœ˜ Kšœœ˜šœ œ˜Kšœœ˜šœ œ˜K˜Kšœœ˜*Kšœ˜Kšœ˜—K˜—šœ˜Kšœ~™~Kšœœœ˜š œœ œœ˜,Kšœœ˜Kšœœœ ˜8Kšœœœœ˜6Kšœœ˜š˜Kšœ œ˜—Kšœ˜—K˜—Kšœ˜Kšœ'œœ˜K—K˜Kšœ˜—Kšœ˜—Kšœœ ˜šœ˜šœ˜šœ˜Kš˜Kšœ˜šœ˜Kšœ"œ˜/K˜9Kšœ˜Kšœ œœœ˜Kš˜—Kšœ˜Kšœ˜—Kšœ œœ˜0—Kšœ8˜?—Kšœ˜Kšœ˜K˜—š Ÿœœ œœœ˜1š˜Kšœ˜šœ˜šœ˜Kšœ˜Kšœœ˜ Kšœ˜—šœ ˜ Kšœ˜Kšœœ˜Kšœ˜—Kšœ8˜?—Kšœ˜—K˜—K˜šœ œ#‘!˜SK˜—šŸœœ˜Kšœ<˜