<> <> <> <<>> 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; <<>> <> <<>> BulkDataSource: TYPE ~ CrRPC.BulkDataSource; Handle: TYPE ~ CrRPC.Handle; ROPE: TYPE ~ Rope.ROPE; <> properties: PrintingP4V3.PrinterProperties; printerStatus: PrintingP4V3.PrinterStatus; <> 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: ROPE _ NIL, state: State _ empty, printAttributes: PrintingP4V3.PrintAttributes _ NIL, printOptions: PrintingP4V3.PrintOptions _ NIL ]; <> <<>> Logger: ENTRY PROC [format: Rope.ROPE _ NIL, v1, v2, v3, v4, v5: IO.Value _ [null[]]] ~ { fname: ROPE ~ "///Temp/Printer/Operations.log"; out: IO.STREAM _ FS.StreamOpen[fname, $append]; IO.PutF[out, format, v1, v2, v3, v4, v5]; IO.Flush[out]; IO.Close[out]; }; <> 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[]]]}; }; <> <<>> 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; <<>> <> 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] ~ { <> 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 { <> 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] ~ { <> 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] ~ { <> current: QueueIndex; MarkQueued: ENTRY PROC = { ENABLE UNWIND => NULL; queue[current].state _ spooled; BROADCAST queueChanged; }; aborted, sendAbort: BOOL _ FALSE; out: IO.STREAM _ NIL; 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 }; <> 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]]]] }; <> }; 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[]; }...