XNSPrintServiceImpl.mesa
Copyright Ó 1986, 1987 by Xerox Corporation. All rights reserved.
Tim Diebert: January 9, 1987 1:24:20 pm PST
DIRECTORY
CrRPC USING [BulkDataCheckAbortProc, BulkDataSource, Handle],
FS USING [Delete, Error, StreamOpen],
IO USING [rope, card, Close, Flush, PutF, PutFR1, STREAM, Value],
PrintingP4V3Aux USING [ExposePrintAttributes, ExposePrintOptions, ExposeRequestID],
Rope USING [ROPE],
PrintingP4V3;
XNSPrintServiceImpl: CEDAR MONITOR
IMPORTS FS, IO, PrintingP4V3Aux
EXPORTS PrintingP4V3 ~ {
OPEN PrintingP4V3;
Copied Types
BulkDataSource: TYPE ~ CrRPC.BulkDataSource;
Handle: TYPE ~ CrRPC.Handle;
ROPE: TYPE ~ Rope.ROPE;
Global vars
properties: PrintingP4V3.PrinterProperties;
printerStatus: PrintingP4V3.PrinterStatus;
PrintQueue
State: TYPE = {empty, spooling, spooled, printing, done};
maxQueue: CARDINAL = 10;
QueueIndex: TYPE = [0 .. maxQueue);
nextEmpty: QueueIndex ← 0; -- Next available.
queue: PrintQueue;
queueChanged: CONDITION;
PrintQueue: TYPE = ARRAY QueueIndex OF PrintQueueEntry;
PrintQueueEntry: TYPE = RECORD [
id: PrintingP4V3.RequestID ← [0, 0, 0, 0, 0],
fileName: ROPENIL,
state: State ← empty,
printAttributes: PrintingP4V3.PrintAttributes ← NIL,
printOptions: PrintingP4V3.PrintOptions ← NIL
];
I/O Procs
Logger: ENTRY PROC [format: Rope.ROPENIL, v1, v2, v3, v4, v5: IO.Value ← [null[]]] ~ {
fname: ROPE ~ "///Temp/Printer/Operations.log";
out: IO.STREAMFS.StreamOpen[fname, $append];
IO.PutF[out, format, v1, v2, v3, v4, v5];
IO.Flush[out];
IO.Close[out];
};
Helper PROCs
ConstructPrinterStatus: PROC [spoolerBusy, formatterBusy: BOOL]
RETURNS [printerStatus: PrinterStatus] ~ {
printerStatus ← NEW[ PrinterStatusObject[4] ];
TRUSTED {printerStatus.body[0] ← [spooler[IF spoolerBusy THEN available ELSE busy]]};
TRUSTED {printerStatus.body[1] ← [formatter[IF formatterBusy THEN available ELSE busy]]};
TRUSTED {printerStatus.body[2] ← [printer[busy]]};
TRUSTED {printerStatus.body[3] ← [media[ConstructMedia[]]]};
};
Errors
Busy: PUBLIC ERROR ~ CODE;
ConnectionError: PUBLIC ERROR [problem: ConnectionProblem] ~ CODE;
InsufficientSpoolSpace: PUBLIC ERROR ~ CODE;
InvalidPrintParameters: PUBLIC ERROR ~ CODE;
MasterTooLarge: PUBLIC ERROR ~ CODE;
MediumUnavailable: PUBLIC ERROR ~ CODE;
ServiceUnavailable: PUBLIC ERROR ~ CODE;
SpoolingDisabled: PUBLIC ERROR ~ CODE;
SpoolingQueueFull: PUBLIC ERROR ~ CODE;
SystemError: PUBLIC ERROR ~ CODE;
TooManyClients: PUBLIC ERROR ~ CODE;
TransferError: PUBLIC ERROR [problem: TransferProblem] ~ CODE;
Undefined: PUBLIC ERROR [problem: CARDINAL] ~ CODE;
Active Procs
currentID: PrintingP4V3.RequestID ← [0, 0, 0, 0, 0];
GetNextID: ENTRY PROC [] RETURNS [id: PrintingP4V3.RequestID] = {
ENABLE UNWIND => NULL;
md: MACHINE DEPENDENT RECORD [a, b: CARDINAL]; i: CARD;
md.a ← currentID[0]; md.b ← currentID[1];
i ← LOOPHOLE[md];
i ← i + 1;
md ← LOOPHOLE[i];
currentID[0] ← md.a; currentID[1] ← md.b;
RETURN [currentID];
};
GetPrinterProperties: PUBLIC PROC [h: Handle] RETURNS [properties: PrinterProperties] ~ {
REPORTS [ServiceUnavailable, SystemError, Undefined]
Logger["GetPrinterProperties called:\n"];
RETURN[properties];
};
ConvertToRequestStatus: PROC [s: State] RETURNS [PrintingP4V3.InterpressMasterStatus] = {
RETURN [SELECT s FROM
empty => unknown,
spooled => pending,
printing => inProgress,
done => completed,
ENDCASE => ERROR];
};
GetPrintRequestStatus: PUBLIC PROC [h: Handle, printRequestID: RequestID]
RETURNS [status: RequestStatus] ~ TRUSTED {
REPORTS [ServiceUnavailable, SystemError, Undefined]
Logger["GetPrintRequestStatus called:\n"];
Logger[" printRequestID: %g\n",
IO.rope[PrintingP4V3Aux.ExposeRequestID[printRequestID, 2]]
];
FOR i: QueueIndex IN QueueIndex DO
IF queue[i].id = printRequestID THEN {
status ← NEW[RequestStatusObject[1]];
status.body[0] ← [status[ConvertToRequestStatus[queue[i].state]]];
RETURN [status];
};
ENDLOOP;
status ← NEW[RequestStatusObject[1]];
status.body[0] ← [status[unknown]];
RETURN [status];
};
GetPrinterStatus: PUBLIC PROC [h: Handle] RETURNS [status: PrinterStatus] ~ {
REPORTS [ServiceUnavailable, SystemError, Undefined]
Logger["GetPrinterStatus called:\n"];
RETURN[printerStatus];
};
FindQueueSlot: ENTRY PROC RETURNS [slot: QueueIndex] = {
ENABLE UNWIND => NULL;
FOR i: QueueIndex IN QueueIndex DO
IF queue[i].state = empty OR queue[nextEmpty].state = done THEN {
queue[i].state ← spooling;
RETURN[i];
};
ENDLOOP;
ERROR SpoolingQueueFull;
};
Print: PUBLIC PROC [h: Handle, master: BulkDataSource, printAttributes: PrintAttributes, printOptions: PrintOptions] RETURNS [printRequestID: RequestID] ~ {
REPORTS [Busy, ConnectionError, InsufficientSpoolSpace, InvalidPrintParameters, MasterTooLarge, MediumUnavailable, ServiceUnavailable, SpoolingDisabled, SpoolingQueueFull, SystemError, TooManyClients, TransferError, Undefined]
current: QueueIndex;
MarkQueued: ENTRY PROC = {
ENABLE UNWIND => NULL;
queue[current].state ← spooled;
BROADCAST queueChanged;
};
aborted, sendAbort: BOOLFALSE;
out: IO.STREAMNIL;
CheckAbort: CrRPC.BulkDataCheckAbortProc ~ {abort ← sendAbort};
{ -- for exit
Logger["Print called:\n"];
Logger[" printAttributes: %g\n",
IO.rope[PrintingP4V3Aux.ExposePrintAttributes[printAttributes, 2]]
];
Logger[" printOptions: %g\n",
IO.rope[PrintingP4V3Aux.ExposePrintOptions[printOptions, 2]]
];
printRequestID ← GetNextID[];
current ← FindQueueSlot[];
queue[current].id ← printRequestID;
queue[current].state ← spooling;
queue[current].printAttributes ← printAttributes;
queue[current].printOptions ← printOptions;
FS.Delete[queue[current].fileName ! FS.Error => CONTINUE];
out ← FS.StreamOpen[queue[current].fileName, $create];
aborted ← master[h, out, CheckAbort ! FS.Error => {sendAbort ← TRUE; GOTO Abort}];
IF out # NIL THEN IO.Close[out];
IF aborted THEN GOTO Abort;
MarkQueued[];
EXITS Abort => {
FS.Delete[queue[current].fileName ! FS.Error => CONTINUE];
queue[current].state ← empty;
ERROR TransferError[aborted];
};
}; -- for exit
};
Init Procs
ConstructPrinterProperties: PROC [] RETURNS [properties: PrinterProperties] ~ {
properties ← NEW[ PrinterPropertiesObject[3] ];
TRUSTED { properties.body[0] ← [ppmedia[ConstructMedia[]]] };
TRUSTED { properties.body[1] ← [ppstaple[FALSE]] };
TRUSTED { properties.body[2] ← [pptwoSided[FALSE]] };
};
ConstructMedia: PROC [] RETURNS [media: Media] ~ {
media ← NEW[ MediaObject[1] ];
TRUSTED { media.body[0] ← [paper[paper: [knownSize[usLetter]]]] };
TRUSTED { media.body[n] ← [paper[otherSize[width: mm, length: 0]]] }; -- zero is infinity!
};
SetUpQueue: PROC [] = {
FOR i: QueueIndex IN QueueIndex DO
queue[i].fileName ← IO.PutFR1["///Spool/File%2g.ip", IO.card[i]];
ENDLOOP;
};
Init: ENTRY PROC ~ {
properties ← ConstructPrinterProperties[];
printerStatus ← ConstructPrinterStatus[spoolerBusy: FALSE, formatterBusy: FALSE];
SetUpQueue[];
};
Init[];
}...