DIRECTORY BasicTime USING [Now], CrRPC USING [BulkDataCheckAbortProc, BulkDataSource, Handle], FS USING [Delete, Error, StreamOpen], IO USING [rope, card, Close, PutF, PutFR1, RopeFromROS, ROS, STREAM, Value], PrintingP4V3Aux USING [ExposePrintAttributes, ExposePrintOptions], Process USING [Detach], Rope USING [ROPE], PrintingP4V3, XNSPSMessages USING [LogMessage], XNSPSPrint USING [PrintFile], XNSPSSpooler; XNSPSSpoolerImpl: CEDAR MONITOR IMPORTS BasicTime, FS, IO, PrintingP4V3Aux, Process, XNSPSMessages, XNSPSPrint EXPORTS XNSPSSpooler, PrintingP4V3 ~ { OPEN PrintingP4V3; BulkDataSource: TYPE ~ CrRPC.BulkDataSource; Handle: TYPE ~ CrRPC.Handle; ROPE: TYPE ~ Rope.ROPE; properties: PrintingP4V3.PrinterProperties; spoolerBusy, formatterBusy, printerBusy: BOOL _ FALSE; State: TYPE = {empty, spooling, spooled, printing, done, aborted}; maxQueue: CARDINAL = 10; QueueIndex: TYPE = [0 .. maxQueue); nextEmpty: QueueIndex _ 0; -- Next available. queue: PrintQueue; queueChanged: CONDITION; queueCount: INTEGER _ 0; 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 ]; ConstructPrinterStatus: PROC [spoolerBusy, formatterBusy, printerBusy: BOOL] RETURNS [printerStatus: PrinterStatus] ~ { printerStatus _ NEW[ PrinterStatusObject[4] ]; printerStatus.body[0] _ NEW[ServiceStatusObject[spooler] _ [spooler[IF spoolerBusy THEN busy ELSE available]]]; printerStatus.body[1] _ NEW[ServiceStatusObject[formatter] _ [formatter[IF formatterBusy THEN busy ELSE available]]]; printerStatus.body[2] _ NEW[ServiceStatusObject[printer] _ [printer[IF printerBusy THEN busy ELSE available]]]; printerStatus.body[3] _ NEW[ServiceStatusObject[media] _ [media[ConstructMedia[]]]]; }; Logger: ENTRY PROC [format: Rope.ROPE _ NIL, v1, v2, v3, v4, v5: IO.Value _ [null[]], id: PrintingP4V3.RequestID] ~ { out: IO.STREAM _ IO.ROS[]; r: ROPE; IO.PutF[out, format, v1, v2, v3, v4, v5]; r _ IO.RopeFromROS[out]; XNSPSMessages.LogMessage[r, id]; }; 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 [lo, hi: CARDINAL]; i: CARD; md1: MACHINE DEPENDENT RECORD [lo, hi: CARDINAL] _ LOOPHOLE[BasicTime.Now[]]; md.lo _ currentID[4]; md.hi _ currentID[3]; i _ LOOPHOLE[md]; i _ i + 1; md _ LOOPHOLE[i]; currentID[4] _ md.lo; currentID[3] _ md.hi; currentID[2] _ md1.lo; currentID[1] _ md1.hi; RETURN [currentID]; }; GetPrinterProperties: PUBLIC PROC [h: Handle] RETURNS [PrinterProperties] ~ { RETURN[properties]; }; ConvertToRequestStatus: PROC [s: State] RETURNS [PrintingP4V3.InterpressMasterStatus] = { RETURN [SELECT s FROM empty => unknown, spooling => pending, spooled => pending, printing => inProgress, done => completed, aborted => aborted, ENDCASE => ERROR]; }; GetPrintRequestStatus: PUBLIC PROC [h: Handle, printRequestID: RequestID] RETURNS [status: RequestStatus] ~ { FOR i: QueueIndex IN QueueIndex DO IF queue[i].id = printRequestID THEN { status _ NEW[RequestStatusObject[1]]; status.body[0] _ NEW[JobStatusObject[status] _ [status[ConvertToRequestStatus[queue[i].state]]]]; RETURN [status]; }; ENDLOOP; status _ NEW[RequestStatusObject[1]]; status.body[0] _ NEW[JobStatusObject[status] _ [status[unknown]]]; RETURN [status]; }; EnumerateQueue: PUBLIC PROC [ p: PROC [id: PrintingP4V3.RequestID, status: PrintingP4V3.InterpressMasterStatus, printAttributes: PrintingP4V3.PrintAttributes, printOptions: PrintingP4V3.PrintOptions] RETURNS [continue: BOOL]] = BEGIN FOR i: QueueIndex IN QueueIndex DO cont: BOOL; cont _ p[queue[i].id, ConvertToRequestStatus[queue[i].state], queue[i].printAttributes, queue[i].printOptions]; IF ~cont THEN EXIT; ENDLOOP; END; GetPrinterStatus: PUBLIC PROC [h: Handle] RETURNS [status: PrinterStatus] ~ { status _ ConstructPrinterStatus[spoolerBusy, formatterBusy, printerBusy]; RETURN[status]; }; FindQueueSlot: ENTRY PROC RETURNS [slot: QueueIndex] = { ENABLE UNWIND => NULL; FOR i: QueueIndex IN QueueIndex DO IF queue[i].state = empty OR queue[i].state = done OR queue[i].state = aborted 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; queueCount _ queueCount + 1; BROADCAST queueChanged; }; aborted, sendAbort: BOOL _ FALSE; out: IO.STREAM _ NIL; CheckAbort: CrRPC.BulkDataCheckAbortProc ~ {abort _ sendAbort}; { -- for exit printRequestID _ GetNextID[]; Logger[format: "Print called:", id: printRequestID]; Logger[format: " printAttributes: %g", v1: IO.rope[PrintingP4V3Aux.ExposePrintAttributes[printAttributes, 2]], id: printRequestID]; Logger[format: " printOptions: %g", v1: IO.rope[PrintingP4V3Aux.ExposePrintOptions[printOptions, 2]], id: printRequestID]; current _ FindQueueSlot[]; queue[current].id _ printRequestID; queue[current].state _ spooling; spoolerBusy _ TRUE; 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; spoolerBusy _ FALSE; MarkQueued[]; EXITS Abort => { FS.Delete[queue[current].fileName ! FS.Error => CONTINUE]; queue[current].state _ empty; spoolerBusy _ FALSE; ERROR TransferError[aborted]; }; }; -- for exit }; DecomposeAndPrint: PROC [] = { Wait: ENTRY PROC [] ={ENABLE UNWIND => NULL; WAIT queueChanged}; current: QueueIndex _ 0; potential: QueueIndex; found, abort, ok: BOOL _ FALSE; DO -- Forever WHILE queueCount <= 0 DO Wait[] ENDLOOP; found _ FALSE; FOR i: QueueIndex IN QueueIndex DO potential _ (current + i) MOD maxQueue; IF queue[potential].state = spooled THEN {current _ potential; found _ TRUE; EXIT}; ENDLOOP; IF ~found THEN LOOP; -- Excess queueChanged queue[current].state _ printing; abort _ FALSE; formatterBusy _ printerBusy _ TRUE; ok _ XNSPSPrint.PrintFile[id: queue[current].id, fileName: queue[current].fileName, printAttributes: queue[current].printAttributes, printOptions: queue[current].printOptions ! ABORTED => {abort _ TRUE; CONTINUE}]; queue[current].state _ IF abort OR ~ok THEN aborted ELSE done; formatterBusy _ printerBusy _ FALSE; queueCount _ queueCount - 1; ENDLOOP; -- Forever }; ConstructPrinterProperties: PROC [] RETURNS [properties: PrinterProperties] ~ { properties _ NEW[ PrinterPropertiesObject[3] ]; properties.body[0] _ NEW[PropertyObject[ppmedia] _ [ppmedia[ConstructMedia[]]]]; properties.body[1] _ NEW[PropertyObject[ppstaple] _ [ppstaple[FALSE]]]; properties.body[2] _ NEW[PropertyObject[pptwoSided] _ [pptwoSided[FALSE]]]; }; ConstructMedia: PROC [] RETURNS [media: Media] ~ { media _ NEW[ MediaObject[1] ]; media.body[0] _ NEW[MediumObject[paper] _ [paper[paper: NEW[PaperObject[knownSize] _ [knownSize[usLetter]]]]]]; }; SetUpQueue: PROC [] = { FOR i: QueueIndex IN QueueIndex DO queue[i].fileName _ IO.PutFR1["///Spool/File%02g.ip", IO.card[i]]; FS.Delete[queue[i].fileName ! FS.Error => CONTINUE]; ENDLOOP; }; Init: ENTRY PROC ~ { properties _ ConstructPrinterProperties[]; SetUpQueue[]; TRUSTED {Process.Detach[FORK DecomposeAndPrint[]]}; }; Init[]; }... ΚXNSPSSpoolerImpl.mesa Copyright Σ 1986, 1987 by Xerox Corporation. All rights reserved. Tim Diebert: March 6, 1987 5:38:14 pm PST Copied Types Global vars PrintQueue Helper PROCs I/O Procs Errors Active Procs REPORTS [ServiceUnavailable, SystemError, Undefined] REPORTS [ServiceUnavailable, SystemError, Undefined] REPORTS [ServiceUnavailable, SystemError, Undefined] REPORTS [Busy, ConnectionError, InsufficientSpoolSpace, InvalidPrintParameters, MasterTooLarge, MediumUnavailable, ServiceUnavailable, SpoolingDisabled, SpoolingQueueFull, SystemError, TooManyClients, TransferError, Undefined] Init Procs TRUSTED { media.body[n] _ [paper[otherSize[width: mm, length: 0]]] }; -- zero is infinity! Κ ˜codešœ™KšœB™BK™)K™—šΟk ˜ Kšœ œ˜Kšœœ2˜=Kšœœ˜%Kš œœ!œ œ œ˜LKšœœ-˜BKšœœ ˜Kšœœœ˜Kšœ ˜ Kšœœ˜!Kšœ œ ˜Kšœ ˜ —K˜šΠlnœœ˜Kšœ œ5˜NKšœ˜&Kšœ˜—K™K™ ™Kšœœ˜,Kšœœ˜Kšœœœ˜—K˜™ K˜Kšœ*˜+—K˜™ K˜Kšœ)œœ˜6Kšœœ7˜BKšœ œ˜Kšœ œ˜#K˜KšœΟc˜.Kšœ˜Kšœ œ˜Kšœ œ˜K˜Kšœ œœ œ˜7šœœœ˜ Kšœ-˜-Kšœ œœ˜K˜Kšœ0œ˜4Kšœ*˜-K˜K˜——K˜šœ ™ K˜šΟnœœ+œœ#˜wKšœœ˜.Kš œœ)œ œœ˜oKš œœ-œœœ˜uKš œœ)œ œœ˜oKšœœ9˜TK˜——K™™ K™š  œœœœœœ2˜uK•StartOfExpansionldStream: STREAM _ NIL]š œœœœœœ˜#Kšœ'˜)Jšœœ˜Jšœ ˜ Kšœ˜K˜——˜K˜—šœ™K™Kš œœœœ˜Kš œœœ œ˜BKš œœœœ˜,Kš œœœœ˜,Kš œœœœ˜$Kš œœœœ˜'Kš œœœœ˜(Kš œœœœ˜&Kš œœœœ˜'Kš  œœœœ˜!Kš œœœœ˜$Kš  œœœœ˜>Kš   œœœ œœ˜3K™—šœ ™ K˜Kšœ4˜4K˜š  œ œœ!˜AKšœœœ˜Kš œœ œœ œœ˜9Kš œœ œœ œœ˜MKšœ+˜+Kšœœ˜K˜ Kšœœ˜Kšœ+˜+Kšœ-˜-Kšœ ˜Kšœ˜—K˜š œœœ œ˜MKšœ-™4Kšœ ˜K˜K˜—š œœ œ*˜Yšœœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜Kšœœ˜—Kšœ˜—K˜š œœœ(œ˜mKšœ.™5šœœ ˜"šœœ˜&Kšœ œ˜%KšœœM˜aKšœ ˜Kšœ˜—Kšœ˜—Kšœ œ˜%Kšœœ.˜BKšœ ˜K˜K˜—š  œœœœ£œ œ˜ιšœœ ˜"Kšœœ˜ Kšœo˜oKšœœœ˜Kšœ˜—Kšœ˜—K˜š œœœ œ˜MKšœ-™4KšœI˜IKšœ ˜Kšœ˜K˜—š  œœœœ˜8Kšœœœ˜šœœ ˜"šœœœœ˜UKšœ˜Kšœ˜ Kšœ˜—Kšœ˜—Kšœ˜Kšœ˜—K˜š œœœcœ ˜œKšœΫ™βKšœ˜š  œœœ˜Kšœœœ˜Kšœ˜K˜Kš œ˜Kšœ˜—Kšœœœ˜!Kšœœœœ˜Kš  œ5˜?šœŸ ˜ Kšœ˜Kšœ4˜4Kšœ,œV˜„Kšœ)œP˜{Kšœ˜Kšœ#˜#Kšœ ˜ Kšœœ˜Kšœ1˜1Kšœ+˜+Kšœ"œ œ˜:Kšœœ.˜6Kšœ'œœœ ˜SKšœœœœ ˜ Kšœ œœ˜Kšœœ˜K˜ šœ ˜Kšœ"œ œ˜:Kšœ˜Kšœœ˜Kšœ˜K˜—KšœŸ ˜—Kšœ˜—K˜š œœ˜Kš œœœœœœœ˜@KšœBœœ˜OšœŸ ˜ Kšœœœ˜(Kšœœ˜šœœ ˜"Kšœœ ˜'Kšœ"œœœ˜SKšœ˜—KšœœœŸ˜+Kšœ ˜ Kšœœ˜Kšœœ˜#Kšœ±œ œœ˜ΦKš œœœœ œ˜>Kšœœ˜$Kšœ˜KšœŸ ˜—Kšœ˜—K˜K˜—™ K˜š œœœ$˜OKšœ œ˜/Kšœœ8˜PKšœœ&œ˜GKšœœ*œ˜KK˜K˜—š œœœ˜2Kšœœ˜Kšœœ%œ4˜oKšœ?Ÿ™ZK˜K˜—š  œœ˜šœœ ˜"Kšœœ œ ˜BKšœœ œ˜4Kšœ˜—Kšœ˜—K˜š œœœ˜Kšœ+˜+K˜ Kšœœ˜3Kšœ˜——K˜K˜K˜K˜—…— -ς