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];
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: BOOL ← FALSE;
docRange: PrintingP4V3.DocumentSubrange ← [FIRST[CARD16], LAST[CARD16]];
message: ROPE ← NIL;
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: STREAM ← IO.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:
BOOL ←
FALSE]
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: STREAM ← FS.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:
ROPE ←
SELECT class
FROM
Interpress.classMasterError => "Master Error",
Interpress.classMasterWarning => "Master Warning",
Interpress.classAppearanceError => "Appearance Error",
Interpress.classAppearanceWarning => "Appearance Warning",
Interpress.classComment => "Comment",
ENDCASE => "Unknown";
rope: ROPE ← IO.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.ROPE ← NIL;
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:
BOOL ←
FALSE] ~ {
PutArgs:
PROC [ub: Basics.UnsafeBlock] ~
TRUSTED {
t: REF TEXT ← NEW[TEXT[argsByteSize]];
s: IO.STREAM ← IO.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: BOOL ← FALSE,
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;
};