SoftcardMarkerImpl.mesa
Copyright Ó 1988 by Xerox Corporation. All rights reserved.
Tim Diebert: November 1, 1988 9:15:34 am PST
Dave Rumph, August 12, 1988 6:43:11 pm PDT
Christian Le Cocq November 16, 1988 10:51:43 am PST
DIRECTORY
Ascii USING [ESC, LF],
Basics,
BasicTime USING [GMT, Now, nullGMT],
Colorize USING [Do],
FS USING [Delete, EnumerateForNames, Error, NameProc, StreamOpen],
Imager USING [Context, Error],
ImagerInterpress USING [Close, Create, DoPage, Ref],
Interpress USING [classAppearanceError, classAppearanceWarning, classComment, classMasterError, classMasterWarning, Close, DoPage, Instructions, LogProc, Master, Open],
IO USING [Close, CreateStreamProcs, CreateStream, EndOfStream, Error, PutFR, PutFR1, PutFWord, PutRope, RopeFromROS, ROS, STREAM, StreamProcs, TIS, TOS, UnsafeGetBlock],
IPInstructions USING [Instructions],
IPMaster USING [Error],
Loader USING [MakeGlobalFrameResident, MakeProcedureResident],
Marker USING [Procs, ProcsRep, RegisterMarkerProcs, Result],
PrincOps USING [PageCount, Priority],
PrintingP4V3 USING [DocumentSubrange, FormatterStatus, MarkingEngineStatus, Option, OptionObject, PrintAttributes, PrintOptions, RequestID],
Process USING [GetPriority, Priority, priorityBackground, SetPriority],
Profiles USING [CreateFromRope, CreateFromSlices, Profile],
PSInstaller USING [InitProc, ps, RegisterInitProc],
Real,
Rope USING [Concat, Equal, Length, ROPE, Substr],
RopeFile USING [FromStream],
RuntimeError,
SafeStorage,
ServicesExec,
SoftcardFSAccess USING [RegisterConsoleStreams],
SoftcardRemoteCall USING [CallRProc],
Spooler USING [State],
VM USING [AddressFault, CantAllocate, WriteProtectFault, PageCount];
SoftcardMarkerImpl: CEDAR MONITOR
IMPORTS Basics, BasicTime, Colorize, FS, IO, Imager, ImagerInterpress, Interpress, IPMaster, Loader, Marker, Process, Profiles, PSInstaller, Real, Rope, RopeFile, RuntimeError, SafeStorage, ServicesExec, SoftcardFSAccess, SoftcardRemoteCall, VM
EXPORTS ExportsList
~ BEGIN
Copied types
ROPE: TYPE ~ Rope.ROPE;
STREAM: TYPE ~ IO.STREAM;
Internal types
Constants
LF: CHAR ~ Ascii.LF;
ESC: CHAR ~ Ascii.ESC;
ps: ATOM ~ PSInstaller.ps;
Globals
printing: BOOLFALSE;
dontCatch: BOOLFALSE;
procs: Marker.Procs;
stopped: BOOLFALSE;
change: CONDITION;
formatting: BOOLFALSE;
in, out, err, scIn, scOut: STREAMNIL;
Marker Procedures
FindStuff: PROC [option: PrintingP4V3.PrintOptions]
RETURNS [copies: CARDINAL, sub: PrintingP4V3.DocumentSubrange, message: ROPE] = {
copies ← 1;
sub ← [FIRST[CARD16], LAST[CARD16]];
message ← NIL;
FOR i: CARDINAL IN [0 .. option.length) DO
localOption: PrintingP4V3.Option ← option.body[i];
WITH localOption SELECT FROM
l: REF PrintingP4V3.OptionObject[copyCount] => copies ← l.copyCount;
l: REF PrintingP4V3.OptionObject[pagesToPrint] => sub ← l.pagesToPrint;
l: REF PrintingP4V3.OptionObject[message] => message ← l.message;
ENDCASE => NULL;
ENDLOOP;
};
currentID: PrintingP4V3.RequestID ← ALL[0];
Mode: TYPE ~ {sun, sunbeam};
mode: Mode ← sunbeam;
controlProfile: Profiles.Profile ~ Profiles.CreateFromRope[LIST[NIL]];
PrintFile: PUBLIC PROC [id: PrintingP4V3.RequestID, fileName: ROPE,
printAttributes: PrintingP4V3.PrintAttributes, printOptions: PrintingP4V3.PrintOptions,
abort: REF BOOL, testPattern: BOOL, copies: CARDINAL,
inst: IPInstructions.Instructions ← NIL] RETURNS [result: Marker.Result] = {
WaitStarted: ENTRY PROC [] = {ENABLE UNWIND => NULL;
UNTIL NOT stopped DO WAIT change ENDLOOP};
old: Process.Priority ← Process.GetPriority[];
aborted: BOOLFALSE;
docRange: PrintingP4V3.DocumentSubrange ← [FIRST[CARD16], LAST[CARD16]];
message: ROPENIL;
IF stopped AND NOT testPattern THEN WaitStarted[]; -- don't wait if it's a test pattern
IF NOT testPattern THEN [--copies--, docRange, message] ← FindStuff[printOptions]; -- go ahead and use copies over since this is not a test pattern
Process.SetPriority[Process.priorityBackground];
{
ENABLE RuntimeError.UNCAUGHT => {
LogMessage["UNCAUGHT Error"];
IF dontCatch THEN REJECT ELSE GOTO Out;
};
{ ENABLE { -- for the 2nd ENABLE. This does most of the catching
FS.Error => {
LogMessage[IO.PutFR1["FS.Error: %g", [rope[error.explanation]]]];
IF dontCatch THEN REJECT ELSE GOTO Out;
};
IO.Error => {
msg2: ROPE ~ SELECT ec FROM
NotImplementedForThisStream => "not implemented",
StreamClosed => "stream closed",
Failure => "failure",
IllegalBackup => "illegal backup",
BufferOverflow => "buffer overflow",
BadIndex => "bad index",
SyntaxError => "syntax error",
Overflow => "overflow",
IN [PFInvalidCode..PFUnprintableValue] => "PF error",
ENDCASE => "unknown error";
LogMessage[IO.PutFR1["IO.Error: %g", [rope[msg2]]]];
IF dontCatch THEN REJECT ELSE GOTO Out;
};
VM.AddressFault => {
LogMessage[IO.PutFR1["AddressFault: %bB", [cardinal[LOOPHOLE[address, CARD]]]]];
IF dontCatch THEN REJECT ELSE GOTO Out;
};
SafeStorage.CantEstablishFinalization => {
LogMessage["SafeStorage.CantEstablishFinalization"];
IF dontCatch THEN REJECT ELSE GOTO Out;
};
SafeStorage.InvalidType => {
LogMessage["SafeStorage.InvalidType"];
IF dontCatch THEN REJECT ELSE GOTO Out;
};
SafeStorage.NarrowFault => {
LogMessage["NarrowFault"];
IF dontCatch THEN REJECT ELSE GOTO Out;
};
SafeStorage.NarrowRefFault => {
LogMessage["NarrowRefFault"];
IF dontCatch THEN REJECT ELSE GOTO Out;
};
SafeStorage.UnsafeProcAssignment => {
LogMessage["SafeStorage.UnsafeProcAssignment"];
IF dontCatch THEN REJECT ELSE GOTO Out;
};
Real.RealError => {
LogMessage["Real.RealError"];
IF dontCatch THEN REJECT ELSE GOTO Out;
};
Real.RealException => TRUSTED {
realFlagsNames: ARRAY Real.Exception OF ROPE = ["fixOverflow", "inexactResult", "invalidOperation", "divisionByZero", "overflow", "underflow"];
msg2: ROPE;
ros: STREAMIO.ROS[];
temp: Real.ExceptionFlags ← flags;
IF temp # Real.NoExceptions THEN
FOR flag: Real.Exception IN Real.Exception DO
IF temp[flag] THEN {
temp[flag] ← FALSE;
IO.PutRope[ros, realFlagsNames[flag]];
IF temp = Real.NoExceptions THEN EXIT;
IO.PutRope[ros, ", "];
};
ENDLOOP;
msg2 ← IO.RopeFromROS[ros];
LogMessage[IO.PutFR1["Real.RealException: {%g}", [rope[msg2]]]];
IF dontCatch THEN REJECT ELSE GOTO Out;
};
RuntimeError.BoundsFault => {
LogMessage["BoundsFault"];
IF dontCatch THEN REJECT ELSE GOTO Out;
};
RuntimeError.ControlFault => {
LogMessage["ControlFault"];
IF dontCatch THEN REJECT ELSE GOTO Out;
};
RuntimeError.DivideCheck => {
LogMessage["DivideCheck"];
IF dontCatch THEN REJECT ELSE GOTO Out;
};
RuntimeError.PointerFault => {
LogMessage["PointerFault"];
IF dontCatch THEN REJECT ELSE GOTO Out;
};
RuntimeError.StartFault => {
LogMessage["StartFault"];
IF dontCatch THEN REJECT ELSE GOTO Out;
};
RuntimeError.StackError => {
LogMessage["StackError"];
IF dontCatch THEN REJECT ELSE GOTO Out;
};
RuntimeError.UnboundProcedure => {
LogMessage["UnboundProcedure"];
IF dontCatch THEN REJECT ELSE GOTO Out;
};
RuntimeError.ZeroDivisor => {
LogMessage["ZeroDivisor"];
IF dontCatch THEN REJECT ELSE GOTO Out;
};
VM.CantAllocate => {
LogMessage[IO.PutFR1["VM.CantAllocate", [integer[bestInterval.count]]]];
IF dontCatch THEN REJECT ELSE GOTO Out;
};
VM.WriteProtectFault => {
LogMessage[IO.PutFR1["WriteProtectFault: %bB", [cardinal[LOOPHOLE[address, CARD]]]]];
IF dontCatch THEN REJECT ELSE GOTO Out;
};
}; -- 2nd ENABLE
currentID ← id; -- set up for the monitor stuff
formatting ← TRUE;
IF NOT testPattern THEN ColorizeIP[id, fileName, message];
aborted ← PrintInterpressFile[id, fileName, docRange, copies, abort, inst, printAttributes, printOptions, testPattern];
IF aborted THEN GOTO Out;
IF NOT testPattern THEN DeleteFile[fileName]; -- don't kill the test patterns
EXITS Out => {IF NOT testPattern THEN DeleteFile[fileName]; -- don't kill the test pattern
Process.SetPriority[old];
jobs ← jobs + 1;
currentID ← ALL[0];
RETURN[aborted]};
};
EXITS Out => {IF NOT testPattern THEN DeleteFile[fileName]; -- don't kill the test pattern
Process.SetPriority[old];
jobs ← jobs + 1;
currentID ← ALL[0];
RETURN[aborted]};
};
Process.SetPriority[old];
jobs ← jobs + 1;
currentID ← ALL[0];
RETURN [IF aborted THEN aborted ELSE complete];
};
DeleteFile: PROC [name: ROPE] = {
Proc: FS.NameProc = -- [fullFName: ROPE] RETURNS [continue: BOOL] -- {
FS.Delete[fullFName ! FS.Error => CONTINUE];
RETURN[TRUE];
};
pattern: ROPE ~ Rope.Concat[base: name, rest: "!*"];
FS.EnumerateForNames[pattern: pattern, proc: Proc ! FS.Error => CONTINUE];
};
PrintInterpressFile: PROC [id: PrintingP4V3.RequestID, fileName: ROPE,
sub: PrintingP4V3.DocumentSubrange, copies: CARDINAL, abort: REF BOOL,
inst: IPInstructions.Instructions ← NIL, printAttributes: PrintingP4V3.PrintAttributes, printOptions: PrintingP4V3.PrintOptions, testPattern: BOOLFALSE]
RETURNS [aborted: BOOL] = {
first: CARDINAL ← MAX[1, sub.beginningPageNumber];
last: CARDINAL ← sub.endingPageNumber;
pg: INT ← 1; cpy: INT ← 1;
formatting ← TRUE;
aborted ← FALSE; -- so we can clean up after ourselves
aborted ← PrintOnSoftcard[file: fileName, copies: copies, first: first, last: last];
formatting ← FALSE;
RETURN[aborted];
};
ColorizeIP: PROC [id: PrintingP4V3.RequestID, fileName, message: ROPE] = {
{ -- for stream protection
ip3Header: ROPE ~ "Interpress/Xerox/3.0";
ip3HeaderLen: INT ~ Rope.Length[base: ip3Header];
stream: STREAMFS.StreamOpen[fileName: fileName, accessOptions: read];
masterRope: ROPE ← RopeFile.FromStream[stream: stream];
IF Rope.Length[base: masterRope] < ip3HeaderLen THEN {IO.Close[stream]; RETURN}; -- not interpress
IF Rope.Equal[s1: Rope.Substr[base: masterRope, start: 0, len: ip3HeaderLen], s2: ip3Header, case: FALSE] THEN {IO.Close[stream]; RETURN};
IO.Close[stream];
}; -- for stream protection
{ -- for colorization
master: Interpress.Master ← NIL;
new: ImagerInterpress.Ref ← NIL;
profile: Profiles.Profile ← Profiles.CreateFromSlices[slices: LIST[[file["///7.0/Palettes/DefaultPalette.data"]], [rope[message]]]];
{ -- for enable
ENABLE {
UNWIND => {IF master # NIL THEN Interpress.Close[master]; master ← NIL;
IF new # NIL THEN ImagerInterpress.Close[self: new]; new ← NIL};
Imager.Error => {LogMessage[error.explanation]; ERROR ABORTED};
IPMaster.Error => {
error = [code: ATOM, explanation: ROPE, index: INT ← 0]
LogMessage[Rope.Concat[base: "Master error: ", rest: error.explanation]];
ERROR ABORTED};
IO.EndOfStream, IO.Error => {LogMessage["Unknown IO Error"];
ERROR ABORTED};
};
LogProc: Interpress.LogProc = {
LogProc: TYPE ~ PROC [class: INT, code: ATOM, explanation: ROPE];
classRope: ROPESELECT class FROM
Interpress.classMasterError => "Master Error",
Interpress.classMasterWarning => "Master Warning",
Interpress.classAppearanceError => "Appearance Error",
Interpress.classAppearanceWarning => "Appearance Warning",
Interpress.classComment => "Comment",
ENDCASE => "Unknown";
rope: ROPEIO.PutFR["Colorizer %g %g", [rope[classRope]], [rope[explanation]]];
LogMessage[rope];
};
master ← Interpress.Open[fileName: fileName, log: LogProc];
new ← ImagerInterpress.Create[fileName: fileName];
FOR page: INT IN [1..master.pages] DO
CheckSetting: PROC [key: ROPE] RETURNS [value: BOOL] ~ {RETURN[TRUE]};
ImagePage: PROC [context: Imager.Context] ~ {
WithAmbushedContext: PROC [context: Imager.Context] ~ {
Interpress.DoPage[master: master, page: page, context: context, log: LogProc];
};
Colorize.Do[context: context, proc: WithAmbushedContext, control: controlProfile, color: profile, checkSystemSetting: CheckSetting];
};
ImagerInterpress.DoPage[self: new, action: ImagePage];
ENDLOOP;
IF new # NIL THEN ImagerInterpress.Close[self: new];
IF master # NIL THEN Interpress.Close[master];
}; -- for enable
}; -- for colorization
};
MarkerStatus: PROC [] RETURNS [PrintingP4V3.MarkingEngineStatus] = {
IF stopped THEN RETURN[disabled];
RETURN[available];
};
FormatterStatus: PROC [] RETURNS [PrintingP4V3.FormatterStatus] =
{RETURN[IF formatting THEN busy ELSE available]};
Start: ENTRY PROC [] = {stopped ← FALSE; BROADCAST change};
Stop: ENTRY PROC [] = {stopped ← TRUE; BROADCAST change};
jobs: INT ← 0;
pages: INT ← 0;
booted: BasicTime.GMT ← BasicTime.nullGMT;
Statistics: PROC [] RETURNS [LIST OF Rope.ROPE] = {
l: LIST OF Rope.ROPENIL;
rope: ROPE ~ SELECT mode FROM
sun => "Sun4", sunbeam => "Sunbeam",
ENDCASE => "Guess";
l ← CONS[IO.PutFR1["Maker is a: %g", [rope[rope]]], l];
l ← CONS[IO.PutFR1["Pages printed: %g", [integer[pages]]], l];
l ← CONS[IO.PutFR1["Jobs printed: %g", [integer[jobs]]], l];
l ← CONS[IO.PutFR1["Booted at %t", [time[booted]]], l];
RETURN [l];
};
JobState: PROC [id: PrintingP4V3.RequestID] RETURNS [Spooler.State] = {
IF id = currentID THEN RETURN[printing] ELSE RETURN[unknown];
};
LogMessage: PROC [msg: ROPE] = {
data: ServicesExec.ServiceData ~ ServicesExec.GetServiceData[ps];
message: ROPE ~ Rope.Concat[base: " PS ", rest: msg];
ServicesExec.BroadcastMessage[message: msg, serviceData: data, showTime: FALSE];
};
InitMarker: PSInstaller.InitProc = {
[in: STREAM ← NIL, out: STREAM ← NIL, info: ServicesExec.UserInfo ← NIL]
procs ← NEW[Marker.ProcsRep ← [
print: PrintFile,
markerStatus: MarkerStatus,
formatterStatus: FormatterStatus,
jobState: JobState,
start: Start,
stop: Stop,
statistics: Statistics]];
jobs ← 0; pages ← 0;
booted ← BasicTime.Now[];
InitSoftcard[out];
Marker.RegisterMarkerProcs[procs, "Softcard", printer];
LogMessage["Marker ready to print."];
};
Printer Procedures
PrintArgsRec: TYPE ~ RECORD[copies, first, last: Basics.FWORD, fileName: PACKED SEQUENCE COMPUTED CARD16 OF CHAR];
PrintOnSoftcard: PROC [file: ROPE, copies: CARD, first: CARD, last: CARD]
RETURNS [aborted: BOOLFALSE] ~ {
PutArgs: PROC [ub: Basics.UnsafeBlock] ~ TRUSTED {
t: REF TEXTNEW[TEXT[argsByteSize]];
s: IO.STREAMIO.TOS[text: t];
IO.PutFWord[s, Basics.FFromCard32[copies]];
IO.PutFWord[s, Basics.FFromCard32[first]];
IO.PutFWord[s, Basics.FFromCard32[last]];
IO.PutRope[s, file];
IO.Close[s];
IF t.length#argsByteSize THEN ERROR;
s ← IO.TIS[t];
[] ← IO.UnsafeGetBlock[s, ub];
};
argsByteSize: CARD32 ← Rope.Length[file]+3*BYTES[CARD];
[] ← SoftcardRemoteCall.CallRProc[$VersacolorPrint, argsByteSize, PutArgs]
};
InitSoftcard: PROC [outStream: STREAM] = {
out ← outStream;
err ← outStream;
[scIn, scOut] ← GetIOStreams[];
SoftcardFSAccess.RegisterConsoleStreams[scIn, out, err];
};
StreamData: TYPE ~ REF StreamDataRep;
StreamDataRep: TYPE ~ RECORD [
buffer: CHAR,
haveOne: BOOLFALSE,
in, out: CONDITION
];
GetIOStreams: PROC [] RETURNS [ioIn, ioOut: STREAM] ~ {
inProcs: REF IO.StreamProcs ~ IO.CreateStreamProcs[variety: input,
class: $BufferedForSoftcard,
getChar: GetChar
];
outProcs: REF IO.StreamProcs ~ IO.CreateStreamProcs[variety: output,
class: $BufferedForSoftcard,
putChar: PutChar
];
data: StreamData ~ NEW[StreamDataRep];
ioIn ← IO.CreateStream[streamProcs: inProcs, streamData: data];
ioOut ← IO.CreateStream[streamProcs: outProcs, streamData: data];
};
GetChar: ENTRY PROC [self: STREAM] RETURNS [c: CHAR] = {
ENABLE UNWIND => NULL;
data: StreamData ~ NARROW [self.streamData];
UNTIL data.haveOne DO
WAIT data.in;
ENDLOOP;
c ← data.buffer;
data.haveOne ← FALSE;
NOTIFY data.out;
};
PutChar: ENTRY PROC [self: STREAM, char: CHAR] = {
ENABLE UNWIND => NULL;
data: StreamData ~ NARROW [self.streamData];
UNTIL NOT data.haveOne DO
WAIT data.out;
ENDLOOP;
data.buffer ← char;
data.haveOne ← TRUE;
NOTIFY data.in;
};
Start Trap Stuff
InitAll: PROC [] = {
Loader.MakeGlobalFrameResident[InitAll];
Loader.MakeProcedureResident[InitAll];
PSInstaller.RegisterInitProc[InitMarker];
};
InitAll[];
END...